From bc6805a6a6c738bc6ddf5058cea8196e7eab804a Mon Sep 17 00:00:00 2001 From: Holger Just Date: Fri, 18 Jun 2010 19:31:21 +0200 Subject: [PATCH 001/777] Initial version of acts_as_journalized --- app/models/journal.rb | 65 +------- vendor/plugins/acts_as_journalized/init.rb | 2 + .../lib/acts_as_journalized.rb | 139 ++++++++++++++++++ 3 files changed, 147 insertions(+), 59 deletions(-) create mode 100644 vendor/plugins/acts_as_journalized/init.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb diff --git a/app/models/journal.rb b/app/models/journal.rb index a0e1ae87..d25cc94c 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -1,68 +1,15 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - class Journal < ActiveRecord::Base - belongs_to :journalized, :polymorphic => true - # added as a quick fix to allow eager loading of the polymorphic association - # since always associated to an issue, for now - belongs_to :issue, :foreign_key => :journalized_id + self.abstract_class = true belongs_to :user - has_many :details, :class_name => "JournalDetail", :dependent => :delete_all + serialize :details + attr_accessor :indice - acts_as_event :title => Proc.new {|o| status = ((s = o.new_status) ? " (#{s})" : nil); "#{o.issue.tracker} ##{o.issue.id}#{status}: #{o.issue.subject}" }, - :description => :notes, - :author => :user, - :type => Proc.new {|o| (s = o.new_status) ? (s.is_closed? ? 'issue-closed' : 'issue-edit') : 'issue-note' }, - :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.issue.id, :anchor => "change-#{o.id}"}} + before_save :check_for_empty_journal - acts_as_activity_provider :type => 'issues', - :permission => :view_issues, - :author_key => :user_id, - :find_options => {:include => [{:issue => :project}, :details, :user], - :conditions => "#{Journal.table_name}.journalized_type = 'Issue' AND" + - " (#{JournalDetail.table_name}.prop_key = 'status_id' OR #{Journal.table_name}.notes <> '')"} - - def save(*args) + def check_for_empty_journal # Do not save an empty journal - (details.empty? && notes.blank?) ? false : super - end - - # Returns the new status if the journal contains a status change, otherwise nil - def new_status - c = details.detect {|detail| detail.prop_key == 'status_id'} - (c && c.value) ? IssueStatus.find_by_id(c.value.to_i) : nil - end - - def new_value_for(prop) - c = details.detect {|detail| detail.prop_key == prop} - c ? c.value : nil - end - - def editable_by?(usr) - usr && usr.logged? && (usr.allowed_to?(:edit_issue_notes, project) || (self.user == usr && usr.allowed_to?(:edit_own_issue_notes, project))) - end - - def project - journalized.respond_to?(:project) ? journalized.project : nil - end - - def attachments - journalized.respond_to?(:attachments) ? journalized.attachments : nil + !(details.empty? && notes.blank?) end end diff --git a/vendor/plugins/acts_as_journalized/init.rb b/vendor/plugins/acts_as_journalized/init.rb new file mode 100644 index 00000000..ade67d28 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/init.rb @@ -0,0 +1,2 @@ +require File.dirname(__FILE__) + '/lib/acts_as_journalized' +ActiveRecord::Base.send(:include, Redmine::Acts::Journalized) diff --git a/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb new file mode 100644 index 00000000..4bcdf1ba --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb @@ -0,0 +1,139 @@ +module Redmine + module Acts + module Journalized + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + def acts_as_journalized(options = {}) + return if self.included_modules.include?(Redmine::Acts::Journalized::InstanceMethods) + + self.include Redmine::Acts::Journalized::InstanceMethods + + plural_name = self.name.underscore.pluralize + journal_name = "#{self.name}Journal" + + extra_module = options.delete(:extra_module) + + event_hash = { + :description => :notes, + :author => Proc.new {|o| User.find_by_id(o.journal.user_id)}, + :url => Proc.new do |o| + { + :controller => self.name.underscore.pluralize, + :action => 'show', + :id => o.id, + :anchor => "change-#{o.id}" + } + end + } + + activity_hash = { + :type => plural_name, + :permission => "view_#{plural_name}".to_sym, + :author_key => :user_id, + } + + options.each_pair do |k, v| + case + when key = k.to_s.slice(/event_(.+)/, 1) + event_hash[key.to_sym] = v + when key = k.to_s.slice(/activity_(.+)/, 1) + activity_hash[key.to_sym] = v + end + end + + # create the new model class + journal = Class.new(Journal) + journal.belongs_to self.name.underscore + journal.acts_as_event event_hash + journal.acts_as_activity_provider activity_hash + journal.send(:include, extra_module) + Object.const_set("#{self.name}Journal", journal) + + unless Redmine::Activity.providers[plural_name].include? self.name + Redmine::Activity.register plural_name.to_sym + end + end + end + + module InstanceMethods + def self.included(base) + base.extend ClassMethods + + base.class_eval do + after_save :create_journal + has_many :journals, :class_name => "#{self.name}Journal", :dependent => :destroy + end + end + + def journal_class + "#{self.class.name}Journal".constantize + end + + def init_journal(user, notes = "") + @notes ||= "" + @current_journal ||= journal_class.new(:journalized => self, :user => user, :notes => notes) + @object_before_change = self.clone + @object_before_change.status = self.status + if self.respond_to? :custom_values + @custom_values_before_change = {} + self.custom_values.each {|c| @custom_values_before_change[c.custom_field_id] = c.value } + end + # Make sure updated_on is updated when adding a note. + updated_on_will_change! + @current_journal + end + + # Saves the changes in a Journal + # Called after_save + def create_journal + if @current_journal + details = {:attr => {}} + if self.respond_to? :custom_values + details[:cf] = {} + end + + # attributes changes + self.class.journalized_columns.each do |c| + unless send(c) == @object_before_change.send(c) + details[:attr][c] = { + :old => @object_before_change.send(c), + :new => send(c) + } + end + end + + if self.respond_to? :custom_values + # custom fields changes + custom_values.each do |c| + unless ( @custom_values_before_change[c.custom_field_id]==c.value || + (@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?)) + details[:cf][c.custom_field_id] = { + :old => @custom_values_before_change[c.custom_field_id], + :new => c.value + } + end + end + end + @current_journal.details = details + @current_journal.save + end + end + + module ClassMethods + def journalized_columns=(columns = []) + @journalized_columns = columns + end + + def journalized_columns + @journalized_columns ||= begin + (self.column_names - %w(id description lock_version created_on updated_on)) + end + end + end + end + end + end +end From f2957176bf4b3eb83b33267a6db8adcad50b37c4 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Tue, 29 Jun 2010 19:39:28 +0200 Subject: [PATCH 002/777] Added helper functions to base journal class --- app/models/journal.rb | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/models/journal.rb b/app/models/journal.rb index d25cc94c..94f66bef 100644 --- a/app/models/journal.rb +++ b/app/models/journal.rb @@ -12,4 +12,12 @@ class Journal < ActiveRecord::Base # Do not save an empty journal !(details.empty? && notes.blank?) end + + def journalized + nil + end + + def project + journalized.respond_to?('project') ? journalized.project: nil + end end From d7768ce600b769f6337b017a205c78c2f96dd497 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 14 Jul 2010 14:13:55 +0200 Subject: [PATCH 003/777] remove journals to start moving it all out to vestal_versions based plugin --- app/models/issue.rb | 18 +-- app/models/journal.rb | 23 --- app/models/version.rb | 3 + config/environment.rb | 4 +- vendor/plugins/acts_as_journalized/init.rb | 2 - .../lib/acts_as_journalized.rb | 139 ------------------ 6 files changed, 13 insertions(+), 176 deletions(-) delete mode 100644 app/models/journal.rb delete mode 100644 vendor/plugins/acts_as_journalized/init.rb delete mode 100644 vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb diff --git a/app/models/issue.rb b/app/models/issue.rb index 2d002183..a8e0bd7e 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -25,10 +25,9 @@ class Issue < ActiveRecord::Base belongs_to :priority, :class_name => 'IssuePriority', :foreign_key => 'priority_id' belongs_to :category, :class_name => 'IssueCategory', :foreign_key => 'category_id' - has_many :journals, :as => :journalized, :dependent => :destroy has_many :time_entries, :dependent => :delete_all has_and_belongs_to_many :changesets, :order => "#{Changeset.table_name}.committed_on ASC, #{Changeset.table_name}.id ASC" - + has_many :relations_from, :class_name => 'IssueRelation', :foreign_key => 'issue_from_id', :dependent => :delete_all has_many :relations_to, :class_name => 'IssueRelation', :foreign_key => 'issue_to_id', :dependent => :delete_all @@ -36,16 +35,15 @@ class Issue < ActiveRecord::Base acts_as_attachable :after_remove => :attachment_removed acts_as_customizable acts_as_watchable + + acts_as_journalized :event_title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, + :event_type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }, + :activity_find_options => {:include => [:project, :author, :tracker]} + acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], - :include => [:project, :journals], + :include => [:project, :changes], # sort by id so that limited eager loading doesn't break with postgresql - :order_column => "#{table_name}.id" - acts_as_event :title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, - :url => Proc.new {|o| {:controller => 'issues', :action => 'show', :id => o.id}}, - :type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') } - - acts_as_activity_provider :find_options => {:include => [:project, :author, :tracker]}, - :author_key => :author_id + :order_column => "#{table_name}.id" DONE_RATIO_OPTIONS = %w(issue_field issue_status) diff --git a/app/models/journal.rb b/app/models/journal.rb deleted file mode 100644 index 94f66bef..00000000 --- a/app/models/journal.rb +++ /dev/null @@ -1,23 +0,0 @@ -class Journal < ActiveRecord::Base - self.abstract_class = true - - belongs_to :user - serialize :details - - attr_accessor :indice - - before_save :check_for_empty_journal - - def check_for_empty_journal - # Do not save an empty journal - !(details.empty? && notes.blank?) - end - - def journalized - nil - end - - def project - journalized.respond_to?('project') ? journalized.project: nil - end -end diff --git a/app/models/version.rb b/app/models/version.rb index 07e66434..86b0cc18 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -19,6 +19,9 @@ class Version < ActiveRecord::Base after_update :update_issues_from_sharing_change belongs_to :project has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify + + acts_as_journalized + acts_as_customizable acts_as_attachable :view_permission => :view_files, :delete_permission => :manage_files diff --git a/config/environment.rb b/config/environment.rb index f89695f4..e0c939e4 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -36,11 +36,11 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector - config.active_record.observers = :message_observer, :issue_observer, :journal_observer, :news_observer, :document_observer, :wiki_content_observer + config.active_record.observers = :message_observer, :issue_observer, :news_observer, :document_observer, :wiki_content_observer # Make Active Record use UTC-base instead of local time # config.active_record.default_timezone = :utc - + # Use Active Record's schema dumper instead of SQL when creating the test database # (enables use of different database adapters for development and test environments) # config.active_record.schema_format = :ruby diff --git a/vendor/plugins/acts_as_journalized/init.rb b/vendor/plugins/acts_as_journalized/init.rb deleted file mode 100644 index ade67d28..00000000 --- a/vendor/plugins/acts_as_journalized/init.rb +++ /dev/null @@ -1,2 +0,0 @@ -require File.dirname(__FILE__) + '/lib/acts_as_journalized' -ActiveRecord::Base.send(:include, Redmine::Acts::Journalized) diff --git a/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb deleted file mode 100644 index 4bcdf1ba..00000000 --- a/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb +++ /dev/null @@ -1,139 +0,0 @@ -module Redmine - module Acts - module Journalized - def self.included(base) - base.extend ClassMethods - end - - module ClassMethods - def acts_as_journalized(options = {}) - return if self.included_modules.include?(Redmine::Acts::Journalized::InstanceMethods) - - self.include Redmine::Acts::Journalized::InstanceMethods - - plural_name = self.name.underscore.pluralize - journal_name = "#{self.name}Journal" - - extra_module = options.delete(:extra_module) - - event_hash = { - :description => :notes, - :author => Proc.new {|o| User.find_by_id(o.journal.user_id)}, - :url => Proc.new do |o| - { - :controller => self.name.underscore.pluralize, - :action => 'show', - :id => o.id, - :anchor => "change-#{o.id}" - } - end - } - - activity_hash = { - :type => plural_name, - :permission => "view_#{plural_name}".to_sym, - :author_key => :user_id, - } - - options.each_pair do |k, v| - case - when key = k.to_s.slice(/event_(.+)/, 1) - event_hash[key.to_sym] = v - when key = k.to_s.slice(/activity_(.+)/, 1) - activity_hash[key.to_sym] = v - end - end - - # create the new model class - journal = Class.new(Journal) - journal.belongs_to self.name.underscore - journal.acts_as_event event_hash - journal.acts_as_activity_provider activity_hash - journal.send(:include, extra_module) - Object.const_set("#{self.name}Journal", journal) - - unless Redmine::Activity.providers[plural_name].include? self.name - Redmine::Activity.register plural_name.to_sym - end - end - end - - module InstanceMethods - def self.included(base) - base.extend ClassMethods - - base.class_eval do - after_save :create_journal - has_many :journals, :class_name => "#{self.name}Journal", :dependent => :destroy - end - end - - def journal_class - "#{self.class.name}Journal".constantize - end - - def init_journal(user, notes = "") - @notes ||= "" - @current_journal ||= journal_class.new(:journalized => self, :user => user, :notes => notes) - @object_before_change = self.clone - @object_before_change.status = self.status - if self.respond_to? :custom_values - @custom_values_before_change = {} - self.custom_values.each {|c| @custom_values_before_change[c.custom_field_id] = c.value } - end - # Make sure updated_on is updated when adding a note. - updated_on_will_change! - @current_journal - end - - # Saves the changes in a Journal - # Called after_save - def create_journal - if @current_journal - details = {:attr => {}} - if self.respond_to? :custom_values - details[:cf] = {} - end - - # attributes changes - self.class.journalized_columns.each do |c| - unless send(c) == @object_before_change.send(c) - details[:attr][c] = { - :old => @object_before_change.send(c), - :new => send(c) - } - end - end - - if self.respond_to? :custom_values - # custom fields changes - custom_values.each do |c| - unless ( @custom_values_before_change[c.custom_field_id]==c.value || - (@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?)) - details[:cf][c.custom_field_id] = { - :old => @custom_values_before_change[c.custom_field_id], - :new => c.value - } - end - end - end - @current_journal.details = details - @current_journal.save - end - end - - module ClassMethods - def journalized_columns=(columns = []) - @journalized_columns = columns - end - - def journalized_columns - @journalized_columns ||= begin - (self.column_names - %w(id description lock_version created_on updated_on)) - end - end - end - end - end - end -end From aecb868b854a742a09a7ee9644ff8168624b11a6 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 14 Jul 2010 19:00:03 +0200 Subject: [PATCH 004/777] remove more journal specific functionality --- app/controllers/issues_controller.rb | 10 ++-- app/helpers/issues_helper.rb | 76 ---------------------------- app/models/issue.rb | 71 ++++---------------------- app/views/issues/_history.rhtml | 8 +-- lib/redmine/activity/fetcher.rb | 7 +-- lib/redmine/export/pdf.rb | 2 +- 6 files changed, 25 insertions(+), 149 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 8b5d73fa..794b0af6 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -111,8 +111,8 @@ class IssuesController < ApplicationController end def show - @journals = @issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC") - @journals.each_with_index {|j,i| j.indice = i+1} + @journals = @issue.journals.find(:all, :include => [:user], :order => "#{Journal.table_name}.created_at ASC") + @journals.each_with_index {|j,i| j.number = i+1} @journals.reverse! if User.current.wants_comments_in_reverse_order? @changesets = @issue.changesets.visible.all @changesets.reverse! if User.current.wants_comments_in_reverse_order? @@ -234,7 +234,7 @@ class IssuesController < ApplicationController unsaved_issue_ids = [] @issues.each do |issue| issue.reload - journal = issue.init_journal(User.current, params[:notes]) + journal = issue.init_journal(params[:notes]) issue.safe_attributes = attributes call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) unless issue.save @@ -270,7 +270,7 @@ class IssuesController < ApplicationController changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) end end - issue.init_journal(User.current) + issue.init_journal call_hook(:controller_issues_move_before_save, { :params => params, :issue => issue, :target_project => @target_project, :copy => !!@copy }) if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => changed_attributes}) moved_issues << r @@ -436,7 +436,7 @@ private @time_entry = TimeEntry.new @notes = params[:notes] - @issue.init_journal(User.current, @notes) + @issue.init_journal(@notes) # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue] attrs = params[:issue].dup diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 60798fed..fee4a653 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -100,82 +100,6 @@ module IssuesHelper @sidebar_queries end - def show_detail(detail, no_html=false) - case detail.property - when 'attr' - field = detail.prop_key.to_s.gsub(/\_id$/, "") - label = l(("field_" + field).to_sym) - case - when ['due_date', 'start_date'].include?(detail.prop_key) - value = format_date(detail.value.to_date) if detail.value - old_value = format_date(detail.old_value.to_date) if detail.old_value - - when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key) - value = find_name_by_reflection(field, detail.value) - old_value = find_name_by_reflection(field, detail.old_value) - - when detail.prop_key == 'estimated_hours' - value = "%0.02f" % detail.value.to_f unless detail.value.blank? - old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank? - - when detail.prop_key == 'parent_id' - label = l(:field_parent_issue) - value = "##{detail.value}" unless detail.value.blank? - old_value = "##{detail.old_value}" unless detail.old_value.blank? - end - when 'cf' - custom_field = CustomField.find_by_id(detail.prop_key) - if custom_field - label = custom_field.name - value = format_value(detail.value, custom_field.field_format) if detail.value - old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value - end - when 'attachment' - label = l(:label_attachment) - end - call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value }) - - label ||= detail.prop_key - value ||= detail.value - old_value ||= detail.old_value - - unless no_html - label = content_tag('strong', label) - old_value = content_tag("i", h(old_value)) if detail.old_value - old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?) - if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key) - # Link to the attachment if it has not been removed - value = link_to_attachment(a) - else - value = content_tag("i", h(value)) if value - end - end - - if !detail.value.blank? - case detail.property - when 'attr', 'cf' - if !detail.old_value.blank? - l(:text_journal_changed, :label => label, :old => old_value, :new => value) - else - l(:text_journal_set_to, :label => label, :value => value) - end - when 'attachment' - l(:text_journal_added, :label => label, :value => value) - end - else - l(:text_journal_deleted, :label => label, :old => old_value) - end - end - - # Find the name of an associated record stored in the field attribute - def find_name_by_reflection(field, id) - association = Issue.reflect_on_association(field.to_sym) - if association - record = association.class_name.constantize.find_by_id(id) - return record.name if record - end - end - def issues_to_csv(issues, project = nil) ic = Iconv.new(l(:general_csv_encoding), 'UTF-8') decimal_separator = l(:general_csv_decimal_separator) diff --git a/app/models/issue.rb b/app/models/issue.rb index a8e0bd7e..1d85493d 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -38,17 +38,16 @@ class Issue < ActiveRecord::Base acts_as_journalized :event_title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, :event_type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }, - :activity_find_options => {:include => [:project, :author, :tracker]} + :activity_find_options => {:include => [:project, :author, :tracker]}, + :activity_author_key => :author_id acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], - :include => [:project, :changes], + :include => [:project, :journals], # sort by id so that limited eager loading doesn't break with postgresql :order_column => "#{table_name}.id" DONE_RATIO_OPTIONS = %w(issue_field issue_status) - attr_reader :current_journal - validates_presence_of :subject, :priority, :project, :tracker, :author, :status validates_length_of :subject, :maximum => 255 @@ -67,7 +66,7 @@ class Issue < ActiveRecord::Base before_create :default_assign before_save :reschedule_following_issues, :close_duplicates, :update_done_ratio_from_issue_status - after_save :update_nested_set_attributes, :update_parent_attributes, :create_journal + after_save :update_nested_set_attributes, :update_parent_attributes after_destroy :destroy_children after_destroy :update_parent_attributes @@ -310,18 +309,7 @@ class Issue < ActiveRecord::Base self.done_ratio = status.default_done_ratio end end - - def init_journal(user, notes = "") - @current_journal ||= Journal.new(:journalized => self, :user => user, :notes => notes) - @issue_before_change = self.clone - @issue_before_change.status = self.status - @custom_values_before_change = {} - self.custom_values.each {|c| @custom_values_before_change.store c.custom_field_id, c.value } - # Make sure updated_on is updated when adding a note. - updated_on_will_change! - @current_journal - end - + # Return true if the issue is closed, otherwise false def closed? self.status.is_closed? @@ -496,13 +484,12 @@ class Issue < ActiveRecord::Base if valid? attachments = Attachment.attach_files(self, params[:attachments]) - attachments[:files].each {|a| @current_journal.details << JournalDetail.new(:property => 'attachment', :prop_key => a.id, :value => a.filename)} # TODO: Rename hook - Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) + Redmine::Hook.call_hook(:controller_issues_edit_before_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => current_journal}) begin if save # TODO: Rename hook - Redmine::Hook.call_hook(:controller_issues_edit_after_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => @current_journal}) + Redmine::Hook.call_hook(:controller_issues_edit_after_save, { :params => params, :issue => self, :time_entry => @time_entry, :journal => current_journal}) else raise ActiveRecord::Rollback end @@ -718,22 +705,12 @@ class Issue < ActiveRecord::Base ).each do |issue| next if issue.project.nil? || issue.fixed_version.nil? unless issue.project.shared_versions.include?(issue.fixed_version) - issue.init_journal(User.current) issue.fixed_version = nil issue.save end end end - # Callback on attachment deletion - def attachment_removed(obj) - journal = init_journal(User.current) - journal.details << JournalDetail.new(:property => 'attachment', - :prop_key => obj.id, - :old_value => obj.filename) - journal.save - end - # Default assignment based on category def default_assign if assigned_to.nil? && category && category.assigned_to @@ -758,40 +735,14 @@ class Issue < ActiveRecord::Base duplicate.reload # Don't re-close it if it's already closed next if duplicate.closed? - # Same user and notes - if @current_journal - duplicate.init_journal(@current_journal.user, @current_journal.notes) - end + # Implicitely creates a new journal duplicate.update_attribute :status, self.status + # Same user and notes + duplicate.versions.last.user = current_journal.user + duplicate.versions.last.notes = current_journal.notes end end end - - # Saves the changes in a Journal - # Called after_save - def create_journal - if @current_journal - # attributes changes - (Issue.column_names - %w(id description root_id lft rgt lock_version created_on updated_on)).each {|c| - @current_journal.details << JournalDetail.new(:property => 'attr', - :prop_key => c, - :old_value => @issue_before_change.send(c), - :value => send(c)) unless send(c)==@issue_before_change.send(c) - } - # custom fields changes - custom_values.each {|c| - next if (@custom_values_before_change[c.custom_field_id]==c.value || - (@custom_values_before_change[c.custom_field_id].blank? && c.value.blank?)) - @current_journal.details << JournalDetail.new(:property => 'cf', - :prop_key => c.custom_field_id, - :old_value => @custom_values_before_change[c.custom_field_id], - :value => c.value) - } - @current_journal.save - # reset current journal - init_journal @current_journal.user, @current_journal.notes - end - end # Query generator for selecting groups of issue counts for a project # based on specific criteria diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml index 7459eb35..219be05d 100644 --- a/app/views/issues/_history.rhtml +++ b/app/views/issues/_history.rhtml @@ -1,15 +1,15 @@ <% reply_links = authorize_for('issues', 'edit') -%> <% for journal in journals %>
-

<%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %>
+

<%= link_to "##{journal.number}", :anchor => "note-#{journal.number}" %>
<%= avatar(journal.user, :size => "24") %> - <%= content_tag('a', '', :name => "note-#{journal.indice}")%> - <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

+ <%= content_tag('a', '', :name => "note-#{journal.number}")%> + <%= authoring journal.created_at, journal.user, :label => :label_updated_time_by %> <% if journal.details.any? %>
    <% for detail in journal.details %> -
  • <%= show_detail(detail) %>
  • +
  • <%= journal.show_detail(detail) %>
  • <% end %>
<% end %> diff --git a/lib/redmine/activity/fetcher.rb b/lib/redmine/activity/fetcher.rb index fb73d5d2..89dbbf1e 100644 --- a/lib/redmine/activity/fetcher.rb +++ b/lib/redmine/activity/fetcher.rb @@ -68,6 +68,7 @@ module Redmine # Returns an array of events for the given date range # sorted in reverse chronological order def events(from = nil, to = nil, options={}) + require 'ruby-debug'; debugger e = [] @options[:limit] = options[:limit] @@ -76,15 +77,15 @@ module Redmine e += provider.find_events(event_type, @user, from, to, @options) end end - + e.sort! {|a,b| b.event_datetime <=> a.event_datetime} - + if options[:limit] e = e.slice(0, options[:limit]) end e end - + private def constantized_providers(event_type) diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb index c2492165..1583fe9d 100644 --- a/lib/redmine/export/pdf.rb +++ b/lib/redmine/export/pdf.rb @@ -282,7 +282,7 @@ module Redmine pdf.Ln for journal in issue.journals.find(:all, :include => [:user, :details], :order => "#{Journal.table_name}.created_on ASC") pdf.SetFontStyle('B',8) - pdf.Cell(190,5, format_time(journal.created_on) + " - " + journal.user.name) + pdf.Cell(190,5, format_time(journal.created_at) + " - " + journal.user.name) pdf.Ln pdf.SetFontStyle('I',8) for detail in journal.details From 867266e9343bc0a7a61089ec7913e41d518cf193 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 15 Jul 2010 14:43:09 +0200 Subject: [PATCH 005/777] init_journal has now the old signature --- app/controllers/issues_controller.rb | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 794b0af6..c3d3b8bd 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -109,10 +109,9 @@ class IssuesController < ApplicationController rescue ActiveRecord::RecordNotFound render_404 end - + def show @journals = @issue.journals.find(:all, :include => [:user], :order => "#{Journal.table_name}.created_at ASC") - @journals.each_with_index {|j,i| j.number = i+1} @journals.reverse! if User.current.wants_comments_in_reverse_order? @changesets = @issue.changesets.visible.all @changesets.reverse! if User.current.wants_comments_in_reverse_order? @@ -180,6 +179,7 @@ class IssuesController < ApplicationController if @issue.save_issue_with_child_records(params, @time_entry) render_attachment_warning_if_needed(@issue) + # FIXME: current_journal.new_record? won't work no more flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? respond_to do |format| @@ -189,6 +189,7 @@ class IssuesController < ApplicationController end else render_attachment_warning_if_needed(@issue) + # FIXME: current_journal.new_record? won't work no more flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? @journal = @issue.current_journal @@ -234,7 +235,7 @@ class IssuesController < ApplicationController unsaved_issue_ids = [] @issues.each do |issue| issue.reload - journal = issue.init_journal(params[:notes]) + journal = issue.init_journal(User.current, params[:notes]) issue.safe_attributes = attributes call_hook(:controller_issues_bulk_edit_before_save, { :params => params, :issue => issue }) unless issue.save @@ -268,9 +269,9 @@ class IssuesController < ApplicationController [:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute| unless params[valid_attribute].blank? changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) - end + end end - issue.init_journal + issue.init_journal(User.current) call_hook(:controller_issues_move_before_save, { :params => params, :issue => issue, :target_project => @target_project, :copy => !!@copy }) if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => changed_attributes}) moved_issues << r @@ -434,9 +435,9 @@ private @priorities = IssuePriority.all @edit_allowed = User.current.allowed_to?(:edit_issues, @project) @time_entry = TimeEntry.new - + @notes = params[:notes] - @issue.init_journal(@notes) + @issue.init_journal(User.current, @notes) # User can change issue attributes only if he has :edit permission or if a workflow transition is allowed if (@edit_allowed || !@allowed_statuses.empty?) && params[:issue] attrs = params[:issue].dup From 7d4d87a9a9c3b1a7a337e2227558243f8f761aaa Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 15 Jul 2010 14:43:22 +0200 Subject: [PATCH 006/777] journal numbers are now called versions --- app/views/issues/_history.rhtml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml index 219be05d..243c77bf 100644 --- a/app/views/issues/_history.rhtml +++ b/app/views/issues/_history.rhtml @@ -1,11 +1,11 @@ <% reply_links = authorize_for('issues', 'edit') -%> <% for journal in journals %>
-

<%= link_to "##{journal.number}", :anchor => "note-#{journal.number}" %>
+

<%= link_to "##{journal.version}", :anchor => "note-#{journal.version}" %>
<%= avatar(journal.user, :size => "24") %> - <%= content_tag('a', '', :name => "note-#{journal.number}")%> + <%= content_tag('a', '', :name => "note-#{journal.version}")%> <%= authoring journal.created_at, journal.user, :label => :label_updated_time_by %>

- + <% if journal.details.any? %>
    <% for detail in journal.details %> From 96bbd94251ee3aea45590020930c5b320d152d3b Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 15 Jul 2010 15:23:43 +0200 Subject: [PATCH 007/777] adjust for acts_as_journalized --- app/controllers/issues_controller.rb | 8 ++--- app/controllers/journals_controller.rb | 41 -------------------------- app/views/journals/_notes_form.rhtml | 8 ----- app/views/journals/edit.rjs | 3 -- app/views/journals/update.rjs | 10 ------- 5 files changed, 3 insertions(+), 67 deletions(-) delete mode 100644 app/controllers/journals_controller.rb delete mode 100644 app/views/journals/_notes_form.rhtml delete mode 100644 app/views/journals/edit.rjs delete mode 100644 app/views/journals/update.rjs diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index c3d3b8bd..5f074527 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -179,8 +179,7 @@ class IssuesController < ApplicationController if @issue.save_issue_with_child_records(params, @time_entry) render_attachment_warning_if_needed(@issue) - # FIXME: current_journal.new_record? won't work no more - flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? + flash[:notice] = l(:notice_successful_update) unless @issue.current_journal == @journal respond_to do |format| format.html { redirect_back_or_default({:action => 'show', :id => @issue}) } @@ -189,8 +188,7 @@ class IssuesController < ApplicationController end else render_attachment_warning_if_needed(@issue) - # FIXME: current_journal.new_record? won't work no more - flash[:notice] = l(:notice_successful_update) unless @issue.current_journal.new_record? + flash[:notice] = l(:notice_successful_update) unless @issue.current_journal == @journal @journal = @issue.current_journal respond_to do |format| @@ -445,7 +443,7 @@ private attrs.delete(:status_id) unless @allowed_statuses.detect {|s| s.id.to_s == attrs[:status_id].to_s} @issue.safe_attributes = attrs end - + @journal = @issue.current_journal end # TODO: Refactor, lots of extra code in here diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb deleted file mode 100644 index e9fe9099..00000000 --- a/app/controllers/journals_controller.rb +++ /dev/null @@ -1,41 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class JournalsController < ApplicationController - before_filter :find_journal - - def edit - if request.post? - @journal.update_attributes(:notes => params[:notes]) if params[:notes] - @journal.destroy if @journal.details.empty? && @journal.notes.blank? - call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params}) - respond_to do |format| - format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id } - format.js { render :action => 'update' } - end - end - end - -private - def find_journal - @journal = Journal.find(params[:id]) - (render_403; return false) unless @journal.editable_by?(User.current) - @project = @journal.journalized.project - rescue ActiveRecord::RecordNotFound - render_404 - end -end diff --git a/app/views/journals/_notes_form.rhtml b/app/views/journals/_notes_form.rhtml deleted file mode 100644 index 94c710eb..00000000 --- a/app/views/journals/_notes_form.rhtml +++ /dev/null @@ -1,8 +0,0 @@ -<% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %> - <%= text_area_tag :notes, @journal.notes, :class => 'wiki-edit', - :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %> - <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %> -

    <%= submit_tag l(:button_save) %> - <%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " + - "Element.show('journal-#{@journal.id}-notes'); return false;" %>

    -<% end %> diff --git a/app/views/journals/edit.rjs b/app/views/journals/edit.rjs deleted file mode 100644 index 798cb0f0..00000000 --- a/app/views/journals/edit.rjs +++ /dev/null @@ -1,3 +0,0 @@ -page.hide "journal-#{@journal.id}-notes" -page.insert_html :after, "journal-#{@journal.id}-notes", - :partial => 'notes_form' diff --git a/app/views/journals/update.rjs b/app/views/journals/update.rjs deleted file mode 100644 index a83d5812..00000000 --- a/app/views/journals/update.rjs +++ /dev/null @@ -1,10 +0,0 @@ -if @journal.frozen? - # journal was destroyed - page.remove "change-#{@journal.id}" -else - page.replace "journal-#{@journal.id}-notes", render_notes(@journal.issue, @journal, :reply_links => authorize_for('issues', 'edit')) - page.show "journal-#{@journal.id}-notes" - page.remove "journal-#{@journal.id}-form" -end - -call_hook(:view_journals_update_rjs_bottom, { :page => page, :journal => @journal }) From 4b0bd11f6d1f3a3303305c17e6ff909457e74181 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 15 Jul 2010 18:23:19 +0200 Subject: [PATCH 008/777] move more journal classes --- app/helpers/journals_helper.rb | 42 ---------------------------------- app/models/journal_detail.rb | 25 -------------------- app/models/journal_observer.rb | 22 ------------------ 3 files changed, 89 deletions(-) delete mode 100644 app/helpers/journals_helper.rb delete mode 100644 app/models/journal_detail.rb delete mode 100644 app/models/journal_observer.rb diff --git a/app/helpers/journals_helper.rb b/app/helpers/journals_helper.rb deleted file mode 100644 index cf877243..00000000 --- a/app/helpers/journals_helper.rb +++ /dev/null @@ -1,42 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -module JournalsHelper - def render_notes(issue, journal, options={}) - content = '' - editable = User.current.logged? && (User.current.allowed_to?(:edit_issue_notes, issue.project) || (journal.user == User.current && User.current.allowed_to?(:edit_own_issue_notes, issue.project))) - links = [] - if !journal.notes.blank? - links << link_to_remote(image_tag('comment.png'), - { :url => {:controller => 'issues', :action => 'reply', :id => issue, :journal_id => journal} }, - :title => l(:button_quote)) if options[:reply_links] - links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", - { :controller => 'journals', :action => 'edit', :id => journal }, - :title => l(:button_edit)) if editable - end - content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty? - content << textilizable(journal, :notes) - css_classes = "wiki" - css_classes << " editable" if editable - content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => css_classes) - end - - def link_to_in_place_notes_editor(text, field_id, url, options={}) - onclick = "new Ajax.Request('#{url_for(url)}', {asynchronous:true, evalScripts:true, method:'get'}); return false;" - link_to text, '#', options.merge(:onclick => onclick) - end -end diff --git a/app/models/journal_detail.rb b/app/models/journal_detail.rb deleted file mode 100644 index 58239006..00000000 --- a/app/models/journal_detail.rb +++ /dev/null @@ -1,25 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class JournalDetail < ActiveRecord::Base - belongs_to :journal - - def before_save - self.value = value[0..254] if value && value.is_a?(String) - self.old_value = old_value[0..254] if old_value && old_value.is_a?(String) - end -end diff --git a/app/models/journal_observer.rb b/app/models/journal_observer.rb deleted file mode 100644 index 5604e064..00000000 --- a/app/models/journal_observer.rb +++ /dev/null @@ -1,22 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class JournalObserver < ActiveRecord::Observer - def after_create(journal) - Mailer.deliver_issue_edit(journal) if Setting.notified_events.include?('issue_updated') - end -end From 2d282f8debe620f2983207f8a26e86b3d46c7a99 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 15 Jul 2010 18:24:12 +0200 Subject: [PATCH 009/777] move (almost) everything over to acts_as_journalized --- app/models/changeset.rb | 18 +++++++-------- app/models/document.rb | 15 ++++++++----- app/models/mail_handler.rb | 6 ++--- app/models/mailer.rb | 2 +- app/models/message.rb | 22 +++++++++++-------- app/models/news.rb | 6 ++--- app/models/time_entry.rb | 15 +++++-------- config/environment.rb | 2 +- lib/redmine/activity/fetcher.rb | 3 +-- .../lib/acts_as_activity_provider.rb | 2 +- 10 files changed, 45 insertions(+), 46 deletions(-) diff --git a/app/models/changeset.rb b/app/models/changeset.rb index 3bd26b11..d2240362 100644 --- a/app/models/changeset.rb +++ b/app/models/changeset.rb @@ -23,20 +23,18 @@ class Changeset < ActiveRecord::Base has_many :changes, :dependent => :delete_all has_and_belongs_to_many :issues - acts_as_event :title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))}, - :description => :long_comments, - :datetime => :committed_on, - :url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :rev => o.revision}} - + acts_as_journalized :event_title => Proc.new {|o| "#{l(:label_revision)} #{o.revision}" + (o.short_comments.blank? ? '' : (': ' + o.short_comments))}, + :event_description => :long_comments, + :event_datetime => :committed_on, + :event_url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :rev => o.revision}}, + :activity_timestamp => "#{table_name}.committed_on", + :activity_author_key => :user_id + acts_as_searchable :columns => 'comments', :include => {:repository => :project}, :project_key => "#{Repository.table_name}.project_id", :date_column => 'committed_on' - - acts_as_activity_provider :timestamp => "#{table_name}.committed_on", - :author_key => :user_id, - :find_options => {:include => [:user, {:repository => :project}]} - + validates_presence_of :repository_id, :revision, :committed_on, :commit_date validates_uniqueness_of :revision, :scope => :repository_id validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true diff --git a/app/models/document.rb b/app/models/document.rb index 3aae3985..414772ea 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -20,15 +20,18 @@ class Document < ActiveRecord::Base belongs_to :category, :class_name => "DocumentCategory", :foreign_key => "category_id" acts_as_attachable :delete_permission => :manage_documents + acts_as_journalized :event_title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"}, + :event_url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id} }, + :event_author => (Proc.new do |o| + o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC").try(:author) + end) + acts_as_searchable :columns => ['title', "#{table_name}.description"], :include => :project - acts_as_event :title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"}, - :author => Proc.new {|o| (a = o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC")) ? a.author : nil }, - :url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id}} - acts_as_activity_provider :find_options => {:include => :project} - + + validates_presence_of :project, :title, :category validates_length_of :title, :maximum => 60 - + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_documents, project) end diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb index 518f0433..be3b5db1 100644 --- a/app/models/mail_handler.rb +++ b/app/models/mail_handler.rb @@ -197,11 +197,11 @@ class MailHandler < ActionMailer::Base # Reply will be added to the issue def receive_journal_reply(journal_id) journal = Journal.find_by_id(journal_id) - if journal && journal.journalized_type == 'Issue' - receive_issue_reply(journal.journalized_id) + if journal && journal.versioned_type == 'Issue' + receive_issue_reply(journal.versioned_id) end end - + # Receives a reply to a forum message def receive_message_reply(message_id) message = Message.find_by_id(message_id) diff --git a/app/models/mailer.rb b/app/models/mailer.rb index f39c5320..af35d8d1 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -55,7 +55,7 @@ class Mailer < ActionMailer::Base # issue_edit(journal) => tmail object # Mailer.deliver_issue_edit(journal) => sends an email to issue recipients def issue_edit(journal) - issue = journal.journalized.reload + issue = journal.versioned.reload redmine_headers 'Project' => issue.project.identifier, 'Issue-Id' => issue.id, 'Issue-Author' => issue.author.login diff --git a/app/models/message.rb b/app/models/message.rb index 3744c239..b36119a6 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -21,21 +21,25 @@ class Message < ActiveRecord::Base acts_as_tree :counter_cache => :replies_count, :order => "#{Message.table_name}.created_on ASC" acts_as_attachable belongs_to :last_reply, :class_name => 'Message', :foreign_key => 'last_reply_id' - + + acts_as_journalized :event_title => Proc.new {|o| "#{o.board.name}: #{o.subject}"}, + :event_description => :content, + :event_type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'}, + :event_url => (Proc.new do |o| + if o.parent_id.nil? + {:id => o.id} + else + {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"} + end.reverse_merge :controller => 'messages', :action => 'show', :board_id => o.board_id + end) + acts_as_searchable :columns => ['subject', 'content'], :include => {:board => :project}, :project_key => 'project_id', :date_column => "#{table_name}.created_on" - acts_as_event :title => Proc.new {|o| "#{o.board.name}: #{o.subject}"}, - :description => :content, - :type => Proc.new {|o| o.parent_id.nil? ? 'message' : 'reply'}, - :url => Proc.new {|o| {:controller => 'messages', :action => 'show', :board_id => o.board_id}.merge(o.parent_id.nil? ? {:id => o.id} : - {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"})} - acts_as_activity_provider :find_options => {:include => [{:board => :project}, :author]}, - :author_key => :author_id acts_as_watchable - + attr_protected :locked, :sticky validates_presence_of :board, :subject, :content validates_length_of :subject, :maximum => 255 diff --git a/app/models/news.rb b/app/models/news.rb index a167cdf3..91700ebf 100644 --- a/app/models/news.rb +++ b/app/models/news.rb @@ -24,11 +24,9 @@ class News < ActiveRecord::Base validates_length_of :title, :maximum => 60 validates_length_of :summary, :maximum => 255 + acts_as_journalized :event_url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id} } acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project - acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}} - acts_as_activity_provider :find_options => {:include => [:project, :author]}, - :author_key => :author_id - + def visible?(user=User.current) !user.nil? && user.allowed_to?(:view_news, project) end diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb index 73f39f94..37a7a13f 100644 --- a/app/models/time_entry.rb +++ b/app/models/time_entry.rb @@ -22,18 +22,15 @@ class TimeEntry < ActiveRecord::Base belongs_to :issue belongs_to :user belongs_to :activity, :class_name => 'TimeEntryActivity', :foreign_key => 'activity_id' - + attr_protected :project_id, :user_id, :tyear, :tmonth, :tweek acts_as_customizable - acts_as_event :title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"}, - :url => Proc.new {|o| {:controller => 'timelog', :action => 'details', :project_id => o.project, :issue_id => o.issue}}, - :author => :user, - :description => :comments - - acts_as_activity_provider :timestamp => "#{table_name}.created_on", - :author_key => :user_id, - :find_options => {:include => :project} + acts_as_journalized :event_title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"}, + :event_url => Proc.new {|o| {:controller => 'timelog', :action => 'details', :project_id => o.project, :issue_id => o.issue}}, + :event_author => :user, + :event_description => :comments, + :activity_timestamp => "#{table_name}.created_on" validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on validates_numericality_of :hours, :allow_nil => true, :message => :invalid diff --git a/config/environment.rb b/config/environment.rb index e0c939e4..4a337fcf 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -36,7 +36,7 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector - config.active_record.observers = :message_observer, :issue_observer, :news_observer, :document_observer, :wiki_content_observer + config.active_record.observers = :journal_observer, :message_observer, :issue_observer, :news_observer, :document_observer, :wiki_content_observer # Make Active Record use UTC-base instead of local time # config.active_record.default_timezone = :utc diff --git a/lib/redmine/activity/fetcher.rb b/lib/redmine/activity/fetcher.rb index 89dbbf1e..eb319837 100644 --- a/lib/redmine/activity/fetcher.rb +++ b/lib/redmine/activity/fetcher.rb @@ -68,10 +68,9 @@ module Redmine # Returns an array of events for the given date range # sorted in reverse chronological order def events(from = nil, to = nil, options={}) - require 'ruby-debug'; debugger e = [] @options[:limit] = options[:limit] - + @scope.each do |event_type| constantized_providers(event_type).each do |provider| e += provider.find_events(event_type, @user, from, to, @options) diff --git a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb index bbbf5814..e6624f43 100644 --- a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb +++ b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb @@ -54,7 +54,7 @@ module Redmine def find_events(event_type, user, from, to, options) provider_options = activity_provider_options[event_type] raise "#{self.name} can not provide #{event_type} events." if provider_options.nil? - + scope_options = {} cond = ARCondition.new if from && to From 2ec2405b3279a10fe46564598144eebdd2731f63 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 15 Jul 2010 21:10:05 +0200 Subject: [PATCH 010/777] convert more to acts_as_journalized --- app/models/attachment.rb | 36 +++++++++++++---------- app/models/changeset.rb | 2 +- app/models/issue.rb | 4 +-- app/models/time_entry.rb | 3 +- extra/sample_plugin/app/models/meeting.rb | 12 ++++---- lib/redmine.rb | 2 +- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 99e461dc..5005054b 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -25,26 +25,30 @@ class Attachment < ActiveRecord::Base validates_length_of :filename, :maximum => 255 validates_length_of :disk_filename, :maximum => 255 - acts_as_event :title => :filename, - :url => Proc.new {|o| {:controller => 'attachments', :action => 'download', :id => o.id, :filename => o.filename}} + acts_as_journalized :event_title => :filename, + :event_url => (Proc.new do |o| + { :controller => 'attachments', :action => 'download', + :id => o.id, :filename => o.filename } + end), + :activity_type => 'files', + :activity_permission => :view_files, + :activity_find_options => {:select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Version.table_name} ON #{Version.table_name}.id = #{Attachment.table_name}.container_id " + + " AND #{Attachment.table_name}.container_type = 'Version' " + + "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Version.table_name}.project_id " + + " OR ( #{Attachment.table_name}.container_id = #{Project.table_name}.id " + + " AND #{Attachment.table_name}.container_type = 'Project' ) " } - acts_as_activity_provider :type => 'files', - :permission => :view_files, - :author_key => :author_id, - :find_options => {:select => "#{Attachment.table_name}.*", - :joins => "LEFT JOIN #{Version.table_name} ON #{Attachment.table_name}.container_type='Version' AND #{Version.table_name}.id = #{Attachment.table_name}.container_id " + - "LEFT JOIN #{Project.table_name} ON #{Version.table_name}.project_id = #{Project.table_name}.id OR ( #{Attachment.table_name}.container_type='Project' AND #{Attachment.table_name}.container_id = #{Project.table_name}.id )"} - - acts_as_activity_provider :type => 'documents', - :permission => :view_documents, - :author_key => :author_id, - :find_options => {:select => "#{Attachment.table_name}.*", - :joins => "LEFT JOIN #{Document.table_name} ON #{Attachment.table_name}.container_type='Document' AND #{Document.table_name}.id = #{Attachment.table_name}.container_id " + - "LEFT JOIN #{Project.table_name} ON #{Document.table_name}.project_id = #{Project.table_name}.id"} + acts_as_activity :type => 'documents', + :permission => :view_documents, + :find_options => {:select => "#{Attachment.table_name}.*", + :joins => "LEFT JOIN #{Document.table_name} ON (#{Document.table_name}.id = #{Attachment.table_name}.container_id" + + " AND #{Attachment.table_name}.container_type='Document') " + + "LEFT JOIN #{Project.table_name} ON (#{Project.table_name}.id = #{Document.table_name}.project_id)" } cattr_accessor :storage_path @@storage_path = "#{RAILS_ROOT}/files" - + def validate if self.filesize > Setting.attachment_max_size.to_i.kilobytes errors.add(:base, :too_long, :count => Setting.attachment_max_size.to_i.kilobytes) diff --git a/app/models/changeset.rb b/app/models/changeset.rb index d2240362..90192ebe 100644 --- a/app/models/changeset.rb +++ b/app/models/changeset.rb @@ -28,7 +28,7 @@ class Changeset < ActiveRecord::Base :event_datetime => :committed_on, :event_url => Proc.new {|o| {:controller => 'repositories', :action => 'revision', :id => o.repository.project, :rev => o.revision}}, :activity_timestamp => "#{table_name}.committed_on", - :activity_author_key => :user_id + :activity_find_options => {:include => [:user, {:repository => :project}]} acts_as_searchable :columns => 'comments', :include => {:repository => :project}, diff --git a/app/models/issue.rb b/app/models/issue.rb index 1d85493d..76010358 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -37,9 +37,7 @@ class Issue < ActiveRecord::Base acts_as_watchable acts_as_journalized :event_title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, - :event_type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') }, - :activity_find_options => {:include => [:project, :author, :tracker]}, - :activity_author_key => :author_id + :event_type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') } acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], :include => [:project, :journals], diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb index 37a7a13f..f606848a 100644 --- a/app/models/time_entry.rb +++ b/app/models/time_entry.rb @@ -29,8 +29,7 @@ class TimeEntry < ActiveRecord::Base acts_as_journalized :event_title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"}, :event_url => Proc.new {|o| {:controller => 'timelog', :action => 'details', :project_id => o.project, :issue_id => o.issue}}, :event_author => :user, - :event_description => :comments, - :activity_timestamp => "#{table_name}.created_on" + :event_description => :comments validates_presence_of :user_id, :activity_id, :project_id, :hours, :spent_on validates_numericality_of :hours, :allow_nil => true, :message => :invalid diff --git a/extra/sample_plugin/app/models/meeting.rb b/extra/sample_plugin/app/models/meeting.rb index c1bb64a9..5adb621a 100644 --- a/extra/sample_plugin/app/models/meeting.rb +++ b/extra/sample_plugin/app/models/meeting.rb @@ -1,11 +1,9 @@ class Meeting < ActiveRecord::Base belongs_to :project - acts_as_event :title => Proc.new {|o| "#{o.scheduled_on} Meeting"}, - :datetime => :scheduled_on, - :author => nil, - :url => Proc.new {|o| {:controller => 'meetings', :action => 'show', :id => o.id}} - - acts_as_activity_provider :timestamp => 'scheduled_on', - :find_options => { :include => :project } + acts_as_journalized :event_title => Proc.new {|o| "#{o.scheduled_on} Meeting"}, + :event_datetime => :scheduled_on, + :event_author => nil, + :event_url => Proc.new {|o| {:controller => 'meetings', :action => 'show', :id => o.id}} + :activity_timestamp => 'scheduled_on' end diff --git a/lib/redmine.rb b/lib/redmine.rb index 238ee110..8c95f084 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -181,7 +181,7 @@ Redmine::MenuManager.map :project_menu do |menu| end Redmine::Activity.map do |activity| - activity.register :issues, :class_name => %w(Issue Journal) + activity.register :issues, :class_name => 'Issue' activity.register :changesets activity.register :news activity.register :documents, :class_name => %w(Document Attachment) From 4775864d69e64f4f50e9afebfd4026c966f8ae6c Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 16 Jul 2010 03:31:31 +0000 Subject: [PATCH 011/777] Adding 1.0 stable branch to prepare for 1.0.0 RC git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3844 e93f8b46-1217-0410-a6f0-8f06a7374b81 From 4f5dc94170f004ac3025c04ace63f2fd1cf1a23e Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 16 Jul 2010 03:47:03 +0000 Subject: [PATCH 012/777] Merged r3845 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3846 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- public/favicon.ico | Bin 0 -> 7886 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/public/favicon.ico b/public/favicon.ico index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..51c1aeb09896dfa4de1de34d55fc062e9b6eb351 100644 GIT binary patch literal 7886 zcmeHMdu&rx82{#AecX;MptvZ|#Rp1EbiPpIWBegR@ktE&mx(4CA%L$$6OA&+d_W?> zs9=_`t*wZPNDLB!1~OpCqqpmv>j2l=c56G3fUqILkZs4`xu^H`uD$Eptwdw?C13Bk z=X~GqJFk6@JE8(Aq|#CXmD7T8L^IJUD--W4Y(#bFD=!!CUqf#C1fm=9%2jxGf%=Pv z75u*=*M~%&R>7`$!!OVMdQ#rK1MLAYOYoxM^*tXM5JUld~vxbZ1uS8m7HMRKV6$H!B2rbMw$al(jnFWe zcSb078BrDZ(hCXOj#V3B3A;;E%X3#BI^o17B2Mo;$wht|W$z z)rh`+*u|~X*nOO6-F3O+*WaJS(6QiyJ%0`E=YGAOU+)~rHD@pmx8Z&peZlnpy4!LD zhq&vhbe!7z(Dym)1Tel1&znVDXmI3?|MO&`%{XJe4%b#-?M8+%m8ceeetsblk0HJn z;q%?9zt7o#ZyWSJL9BaJsBQ!%CmsXj1z@bfhrQ>qNIoLQvi;o-&*Q^AQFVDd^nw$1 z;GW3$GWc&WuywvRTXdpdo;K)ljMLbM$CLWro6r|c$RMwfeq#4(_yf1@y7Ue7{razyx@A#GK|* z#Jq)whXZ(iPjuv}R7w3^ic~@kwZBH*_A^fruSnVcI72Cf5Dj`pV^{eC-RauJH?i&bG0aQ$rgDg9V6SGE<5s+ z8rV3H$XfziOmk@IMd4kYuH@g>{hNPCPrw$u7`&)=Z78QRilM zjQUt5buV>N_Z%nnHadw_18ezUJp55pId~RW&%=1f7>(_~*bW$Wz>R#s{Z%@9;79X8 zYmjr9;j4X!yPgZ_`J0*}B7e>Y)m>qZujaaq7#lDjclq;S9oUo2@m2dC>qvBN&{M%6yv-J8*_ME-!hxd!=GzKE}5!k$?qetMQv-OD%31|?Wx3bYk4QQ5BUhr!iW1YTJoI~STgRpZ@D>|w+v%lLQc>1 zVPEbrm(R9$FLHDvp4!Ga`*7z{iPtV^vY3Mxwcbd{|AaZF{9QVtcdfasANO;lq<(|s z=a|Ax52PcuVx2y|H<~Q|{=Huk@!WKzbO3i-ZpSy(egkgX&}i~@$niR?M%2|@GEj#4 zX7SKEW+SMTBn5RLue&($`{ivC_gY>g`pka!AXebJt431rS=1+@X0o=M?3pHLe4;L} zhu4VuNjW8IOl`cORBL5^wn(URw&*n&uk$!tLJvYOL*2pG9r}2Xo?5R4U%QeYz1aWZWVw%~e>fSPq} zYTZ{v5v2SLR?Go)Wn#ayrxeqyEvp z)AR56F~6C8-iKOwThdhGP9!_>&I&uI2 literal 0 HcmV?d00001 From a2a3dae974fff867c32bd61dd919045bcd8afe64 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 18 Jul 2010 15:53:46 +0000 Subject: [PATCH 013/777] Merged r3847 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3850 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- config/locales/pt-BR.yml | 4 ++-- config/locales/ru.yml | 4 ++-- config/locales/sv.yml | 4 ++-- config/locales/zh-TW.yml | 4 ++-- config/locales/zh.yml | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index e3cf7d1c..9365505d 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -930,5 +930,5 @@ pt-BR: notice_failed_to_save_members: "Falha ao gravar membro(s): {{errors}}." text_zoom_out: Afastar zoom text_zoom_in: Aproximar zoom - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + notice_unable_delete_time_entry: Não foi possível excluir a entrada no registro de horas trabalhadas. + label_overall_spent_time: Tempo gasto geral diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 5386c1fc..cce12362 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -1022,5 +1022,5 @@ ru: field_principal: Глава text_zoom_out: Отдалить text_zoom_in: Приблизить - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + notice_unable_delete_time_entry: Невозможно удалить запись журнала. + label_overall_spent_time: Всего затрачено времени diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 30ac1700..23450007 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -203,6 +203,7 @@ sv: notice_account_pending: "Ditt konto skapades och avvaktar nu administratörens godkännande." notice_default_data_loaded: Standardkonfiguration inläst. notice_unable_delete_version: Denna version var inte möjlig att ta bort. + notice_unable_delete_time_entry: Tidloggning kunde inte tas bort. notice_issue_done_ratios_updated: % klart uppdaterade. error_can_t_load_default_data: "Standardkonfiguration gick inte att läsa in: {{value}}" @@ -689,6 +690,7 @@ sv: label_changes_details: Detaljer om alla ändringar label_issue_tracking: Ärendeuppföljning label_spent_time: Spenderad tid + label_overall_spent_time: Total tid spenderad label_f_hour: "{{value}} timme" label_f_hour_plural: "{{value}} timmar" label_time_tracking: Tidsuppföljning @@ -951,5 +953,3 @@ sv: enumeration_doc_categories: Dokumentkategorier enumeration_activities: Aktiviteter (tidsuppföljning) enumeration_system_activity: Systemaktivitet - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 7d5c8091..fc5f557d 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -243,6 +243,7 @@ notice_account_pending: "您的帳號已經建立,正在等待管理員的審核。" notice_default_data_loaded: 預設組態已載入成功。 notice_unable_delete_version: 無法刪除版本。 + notice_unable_delete_time_entry: 無法刪除工時記錄項目。 notice_issue_done_ratios_updated: 項目完成百分比已更新。 error_can_t_load_default_data: "無法載入預設組態: {{value}}" @@ -729,6 +730,7 @@ label_changes_details: 所有變更的明細 label_issue_tracking: 項目追蹤 label_spent_time: 耗用工時 + label_overall_spent_time: 整體耗用工時 label_f_hour: "{{value}} 小時" label_f_hour_plural: "{{value}} 小時" label_time_tracking: 工時追蹤 @@ -991,5 +993,3 @@ enumeration_doc_categories: 文件分類 enumeration_activities: 活動 (時間追蹤) enumeration_system_activity: 系統活動 - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 49725b0a..6fdb33f5 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -428,7 +428,7 @@ zh: one: 1 个项目 other: "{{count}} 个项目" label_project_all: 所有的项目 - label_project_latest: 最近更新的项目 + label_project_latest: 最近的项目 label_issue: 问题 label_issue_new: 新建问题 label_issue_plural: 问题 @@ -592,10 +592,10 @@ zh: label_all_time: 全部时间 label_yesterday: 昨天 label_this_week: 本周 - label_last_week: 下周 + label_last_week: 上周 label_last_n_days: "最后 {{count}} 天" label_this_month: 本月 - label_last_month: 下月 + label_last_month: 上月 label_this_year: 今年 label_date_range: 日期范围 label_less_than_ago: 之前天数少于 From 0ae9cc7d07bd19a6e4782187954e0b2039858ea8 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 18 Jul 2010 15:53:51 +0000 Subject: [PATCH 014/777] Merged r3848 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3851 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- doc/INSTALL | 80 +++++++++++++++++++++++++++++++++------------------ doc/UPGRADING | 60 +++++++++++++++++++++++++++----------- 2 files changed, 96 insertions(+), 44 deletions(-) diff --git a/doc/INSTALL b/doc/INSTALL index a4e4312e..7a0e1a12 100644 --- a/doc/INSTALL +++ b/doc/INSTALL @@ -11,61 +11,85 @@ http://www.redmine.org/ * Ruby on Rails 2.3.5 (official downloadable Redmine releases are packaged with the appropriate Rails version) - + +* Rack 1.0.1 + +* RubyGems 1.3.1 + +* Rake 0.8.3 + * A database: * MySQL (tested with MySQL 5) * PostgreSQL (tested with PostgreSQL 8.1) * SQLite (tested with SQLite 3) Optional: -* SVN binaries >= 1.3 (needed for repository browsing, must be available in PATH) -* RMagick (gantt export to png) +* SCM binaries (e.g. svn), for repository browsing (must be available in PATH) +* RMagick (to enable Gantt export to png images) +* Ruby OpenID Library >= version 2 (to enable OpenID support) == Installation 1. Uncompress the program archive - + 2. Create an empty database: "redmine" for example -3. Configure database parameters in config/database.yml - for "production" environment (default database is MySQL) +3. Configure the database parameters in config/database.yml + for the "production" environment (default database is MySQL) 4. Generate a session store secret + Redmine stores session data in cookies by default, which requires - a secret to be generated. Run: - rake generate_session_store + a secret to be generated. Under the application main directory run: + rake generate_session_store + +5. Create the database structure -5. Create the database structure. Under the application main directory: - rake db:migrate RAILS_ENV="production" - It will create tables and an administrator account. + Under the application main directory run: + rake db:migrate RAILS_ENV="production" + + It will create all the tables and an administrator account. + +6. Setting up permissions (Windows users have to skip this section) -6. Setting up permissions The user who runs Redmine must have write permission on the following - subdirectories: files, log, tmp (create the last one if not present). + subdirectories: files, log, tmp & public/plugin_assets (create the last + two if they are not yet present). + + Assuming you run Redmine with a user named "redmine": + mkdir tmp public/plugin_assets + sudo chown -R redmine:redmine files log tmp public/plugin_assets + sudo chmod -R 755 files log tmp public/plugin_assets - Assuming you run Redmine with a user named redmine: - mkdir tmp - sudo chown -R redmine:redmine files log tmp - sudo chmod -R 755 files log tmp - -7. Test the installation by running WEBrick web server: - ruby script/server -e production - +7. Test the installation by running the WEBrick web server + + Under the main application directory run: + ruby script/server -e production + Once WEBrick has started, point your browser to http://localhost:3000/ - You should now see the application welcome page + You should now see the application welcome page. -8. Use default administrator account to log in: +8. Use the default administrator account to log in: login: admin password: admin - Go to "Administration" to load the default configuration data (roles, - trackers, statuses, workflow) and adjust application settings + Go to "Administration" to load the default configuration data (roles, + trackers, statuses, workflow) and to adjust the application settings - -== Email delivery Configuration +== SMTP server Configuration Copy config/email.yml.example to config/email.yml and edit this file to adjust your SMTP settings. -Don't forget to restart the application after any change to this file. +Do not forget to restart the application after any change to this file. Please do not enter your SMTP settings in environment.rb. + +== References + +* http://www.redmine.org/wiki/redmine/RedmineInstall +* http://www.redmine.org/wiki/redmine/EmailConfiguration +* http://www.redmine.org/wiki/redmine/RedmineSettings +* http://www.redmine.org/wiki/redmine/RedmineRepositories +* http://www.redmine.org/wiki/redmine/RedmineReceivingEmails +* http://www.redmine.org/wiki/redmine/RedmineReminderEmails +* http://www.redmine.org/wiki/redmine/RedmineLDAP diff --git a/doc/UPGRADING b/doc/UPGRADING index a9b81d17..87f169c9 100644 --- a/doc/UPGRADING +++ b/doc/UPGRADING @@ -1,4 +1,4 @@ -== Redmine upgrade procedure +== Redmine upgrade Redmine - project management software Copyright (C) 2006-2010 Jean-Philippe Lang @@ -8,26 +8,54 @@ http://www.redmine.org/ == Upgrading 1. Uncompress the program archive in a new directory - + 2. Copy your database settings (RAILS_ROOT/config/database.yml) - and SMTP settings (RAILS_ROOT/config/email.yml) - into the new config directory + and SMTP settings (RAILS_ROOT/config/email.yml) into the new + config directory + +3. Copy the RAILS_ROOT/files directory content into your new installation + This directory contains all the attached files. + +4. Copy the folders of the installed plugins and themes into new installation + +5. Generate a session store secret + + Redmine stores session data in cookies by default, which requires + a secret to be generated. Under the new application directory run: + rake generate_session_store + DO NOT REPLACE OR EDIT ANY OTHER FILES. -3. Generate a session store secret - Redmine stores session data in cookies by default, which requires - a secret to be generated. Run: - rake generate_session_store - -4. Migrate your database (please make a backup before doing this): - rake db:migrate RAILS_ENV="production" +6. Migrate your database -5. Copy the RAILS_ROOT/files directory content into your new installation - This directory contains all the attached files + If you are upgrading to Rails 2.3.5 as part of this migration, you + need to upgrade the plugin migrations before running the plugin migrations + using: + rake db:migrate:upgrade_plugin_migrations RAILS_ENV="production" + + Please make a backup before doing this! Under the new application + directory run: + rake db:migrate RAILS_ENV="production" + + If you have installed any plugins, you should also run their database + migrations using: + rake db:migrate_plugins RAILS_ENV="production" + +7. Clean up + + Clear the cache and the existing sessions by running: + rake tmp:cache:clear + rake tmp:sessions:clear + +8. Restart the application server (e.g. mongrel, thin, passenger) + +9. Finally go to "Administration -> Roles & permissions" to check/set permissions + for new features, if any == Notes -1. Rails 2.3.5 is required for version 0.9. +* Rails 2.3.5 is required for versions 0.9.x and 1.0.x. -2. When upgrading your code with svn update, don't forget to clear - the application cache (RAILS_ROOT/tmp/cache) before restarting. +== References + +* http://www.redmine.org/wiki/redmine/RedmineUpgrade From 619c14871985d4ea36843a3b03c37f4bfabd1d45 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 18 Jul 2010 15:53:56 +0000 Subject: [PATCH 015/777] Merged r3849 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3852 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index fb70acaa..10c17047 100644 --- a/README.rdoc +++ b/README.rdoc @@ -2,4 +2,4 @@ Redmine is a flexible project management web application written using Ruby on Rails framework. -More details can be found at http://www.redmine.org +More details can be found at in the doc directory or on the official website http://www.redmine.org From 1cc116fe5c0daa34f3efb7bb0f31abd2acc06625 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 18 Jul 2010 16:38:51 +0000 Subject: [PATCH 016/777] Merged r3853 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3855 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- doc/CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/CHANGELOG b/doc/CHANGELOG index d6b81944..4a100bfc 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -4,7 +4,7 @@ Redmine - project management software Copyright (C) 2006-2010 Jean-Philippe Lang http://www.redmine.org/ -== v1.0.0 (Release candidate) +== 2010-07-18 v1.0.0 (Release candidate) #443: Adds context menu to the roadmap issue lists #443: Subtasking From 6ed2e003a142ca522ae97f1621eb806f6dc4be49 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 18 Jul 2010 16:38:56 +0000 Subject: [PATCH 017/777] Merged r3854 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3856 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/version.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/redmine/version.rb b/lib/redmine/version.rb index 65aaf4bd..5ea62f3e 100644 --- a/lib/redmine/version.rb +++ b/lib/redmine/version.rb @@ -2,9 +2,9 @@ require 'rexml/document' module Redmine module VERSION #:nodoc: - MAJOR = 0 - MINOR = 9 - TINY = 6 + MAJOR = 1 + MINOR = 0 + TINY = 0 # Branch values: # * official release: nil From 4b52b7a8df299e3850ee61ef84990eefd453415a Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 18 Jul 2010 16:39:00 +0000 Subject: [PATCH 018/777] Change version to the show this is the stable branch. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3857 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/redmine/version.rb b/lib/redmine/version.rb index 5ea62f3e..66f73dc2 100644 --- a/lib/redmine/version.rb +++ b/lib/redmine/version.rb @@ -10,7 +10,7 @@ module Redmine # * official release: nil # * stable branch: stable # * trunk: devel - BRANCH = 'devel' + BRANCH = 'stable' def self.revision revision = nil From 2287d7ce8cd0f3c89a81c5e84fe8699ad21c523d Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 21 Jul 2010 12:27:48 +0200 Subject: [PATCH 019/777] with acts_as_journalized activities only have to search the journal table --- .../acts_as_activity_provider/lib/acts_as_activity_provider.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb index e6624f43..c73a08b1 100644 --- a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb +++ b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb @@ -73,7 +73,7 @@ module Redmine end with_scope(:find => scope_options) do - find(:all, provider_options[:find_options].dup) + Journal.find(:all, provider_options[:find_options].dup) end end end From ff318751493dbbc7513d2f9df84a1e5c04b4f7b9 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 21 Jul 2010 17:57:45 +0200 Subject: [PATCH 020/777] move to STI for journals so the journals themselves can be events --- app/models/mail_handler.rb | 2 +- app/models/mailer.rb | 2 +- app/models/time_entry.rb | 2 +- app/views/issues/_history.rhtml | 4 +++- .../lib/acts_as_activity_provider.rb | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb index be3b5db1..ad71f756 100644 --- a/app/models/mail_handler.rb +++ b/app/models/mail_handler.rb @@ -197,7 +197,7 @@ class MailHandler < ActionMailer::Base # Reply will be added to the issue def receive_journal_reply(journal_id) journal = Journal.find_by_id(journal_id) - if journal && journal.versioned_type == 'Issue' + if journal && journal.versioned.is_a? Issue receive_issue_reply(journal.versioned_id) end end diff --git a/app/models/mailer.rb b/app/models/mailer.rb index af35d8d1..83d7b7c1 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -67,7 +67,7 @@ class Mailer < ActionMailer::Base # Watchers in cc cc(issue.watcher_recipients - @recipients) s = "[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}] " - s << "(#{issue.status.name}) " if journal.new_value_for('status_id') + s << "(#{issue.status.name}) " if journal.details['status_id'] s << issue.subject subject s body :issue => issue, diff --git a/app/models/time_entry.rb b/app/models/time_entry.rb index f606848a..46ab2d9d 100644 --- a/app/models/time_entry.rb +++ b/app/models/time_entry.rb @@ -26,7 +26,7 @@ class TimeEntry < ActiveRecord::Base attr_protected :project_id, :user_id, :tyear, :tmonth, :tweek acts_as_customizable - acts_as_journalized :event_title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).event_title})"}, + acts_as_journalized :event_title => Proc.new {|o| "#{l_hours(o.hours)} (#{(o.issue || o.project).current_journal.event_title})"}, :event_url => Proc.new {|o| {:controller => 'timelog', :action => 'details', :project_id => o.project, :issue_id => o.issue}}, :event_author => :user, :event_description => :comments diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml index 243c77bf..10db8f4f 100644 --- a/app/views/issues/_history.rhtml +++ b/app/views/issues/_history.rhtml @@ -9,7 +9,9 @@ <% if journal.details.any? %>
      <% for detail in journal.details %> -
    • <%= journal.show_detail(detail) %>
    • + <% if d = journal.show_detail(detail) %> +
    • <%= d %>
    • + <% end %> <% end %>
    <% end %> diff --git a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb index c73a08b1..1f145a7b 100644 --- a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb +++ b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb @@ -73,7 +73,7 @@ module Redmine end with_scope(:find => scope_options) do - Journal.find(:all, provider_options[:find_options].dup) + journal_class.find(:all, provider_options[:find_options].dup) end end end From ff6372ad43b1d8043a9f7bdc5f0579609f267818 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 21 Jul 2010 18:25:01 +0200 Subject: [PATCH 021/777] move wiki edits to use journalized plugin. will break if any actual edits are done --- app/models/wiki_content.rb | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb index 1f0eb9a6..aa0f07fb 100644 --- a/app/models/wiki_content.rb +++ b/app/models/wiki_content.rb @@ -50,23 +50,14 @@ class WikiContent < ActiveRecord::Base belongs_to :author, :class_name => '::User', :foreign_key => 'author_id' attr_protected :data - acts_as_event :title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, - :description => :comments, - :datetime => :updated_on, - :type => 'wiki-page', - :url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}} - - acts_as_activity_provider :type => 'wiki_edits', - :timestamp => "#{WikiContent.versioned_table_name}.updated_on", - :author_key => "#{WikiContent.versioned_table_name}.author_id", - :permission => :view_wiki_edits, - :find_options => {:select => "#{WikiContent.versioned_table_name}.updated_on, #{WikiContent.versioned_table_name}.comments, " + - "#{WikiContent.versioned_table_name}.#{WikiContent.version_column}, #{WikiPage.table_name}.title, " + - "#{WikiContent.versioned_table_name}.page_id, #{WikiContent.versioned_table_name}.author_id, " + - "#{WikiContent.versioned_table_name}.id", - :joins => "LEFT JOIN #{WikiPage.table_name} ON #{WikiPage.table_name}.id = #{WikiContent.versioned_table_name}.page_id " + - "LEFT JOIN #{Wiki.table_name} ON #{Wiki.table_name}.id = #{WikiPage.table_name}.wiki_id " + - "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Wiki.table_name}.project_id"} + acts_as_journalized :event_type => 'wiki-page', + :event_title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, + :event_url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}, + :activity_type => 'wiki_edits', + :activity_timestamp => "#{WikiContent.versioned_table_name}.updated_on", + :activity_author_key => "#{WikiContent.versioned_table_name}.author_id", + :activity_permission => :view_wiki_edits, + :activity_find_options => { :include => [:page => [:wiki => :project]] } def text=(plain) case Setting.wiki_compression From 8a3cb1895b8b9f1c69697e198f0ce1b0a79407e3 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Fri, 23 Jul 2010 14:26:08 +0200 Subject: [PATCH 022/777] use the provided helper in issue history --- app/views/issues/_history.rhtml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml index 10db8f4f..4193403a 100644 --- a/app/views/issues/_history.rhtml +++ b/app/views/issues/_history.rhtml @@ -1,21 +1,4 @@ -<% reply_links = authorize_for('issues', 'edit') -%> <% for journal in journals %> -
    -

    <%= link_to "##{journal.version}", :anchor => "note-#{journal.version}" %>
    - <%= avatar(journal.user, :size => "24") %> - <%= content_tag('a', '', :name => "note-#{journal.version}")%> - <%= authoring journal.created_at, journal.user, :label => :label_updated_time_by %>

    - - <% if journal.details.any? %> -
      - <% for detail in journal.details %> - <% if d = journal.show_detail(detail) %> -
    • <%= d %>
    • - <% end %> - <% end %> -
    - <% end %> - <%= render_notes(issue, journal, :reply_links => reply_links) unless journal.notes.blank? %> -
    + <%= render_journal(issue, journal) %> <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %> <% end %> From 4851451017a52d33fe9dc329f790aa70f85b3dd6 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Fri, 23 Jul 2010 17:17:00 +0200 Subject: [PATCH 023/777] remove changes from version model --- app/models/version.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/models/version.rb b/app/models/version.rb index 86b0cc18..76f0a528 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -18,9 +18,7 @@ class Version < ActiveRecord::Base after_update :update_issues_from_sharing_change belongs_to :project - has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify - - acts_as_journalized + has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id', :dependent => :nullify acts_as_customizable acts_as_attachable :view_permission => :view_files, From 8a1d45ffd6c66d76d3d9c03badef58858c98c060 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sat, 24 Jul 2010 00:20:35 +0000 Subject: [PATCH 024/777] Merged r3860 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3861 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/change.rb | 5 +++-- .../20100705164950_change_changes_path_length_limit.rb | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/models/change.rb b/app/models/change.rb index e5c1585b..657652c9 100644 --- a/app/models/change.rb +++ b/app/models/change.rb @@ -19,12 +19,13 @@ class Change < ActiveRecord::Base belongs_to :changeset validates_presence_of :changeset_id, :action, :path + before_save :init_path def relative_path changeset.repository.relative_path(path) end - def before_save - path ||= "" + def init_path + self.path ||= "" end end diff --git a/db/migrate/20100705164950_change_changes_path_length_limit.rb b/db/migrate/20100705164950_change_changes_path_length_limit.rb index 62ba4ec2..62b8644a 100644 --- a/db/migrate/20100705164950_change_changes_path_length_limit.rb +++ b/db/migrate/20100705164950_change_changes_path_length_limit.rb @@ -1,6 +1,9 @@ class ChangeChangesPathLengthLimit < ActiveRecord::Migration def self.up + # these are two steps to please MySQL 5 on Win32 + change_column :changes, :path, :text, :default => nil, :null => true change_column :changes, :path, :text, :null => false + change_column :changes, :from_path, :text end From be52ccf01fd65b96c3bcdd258103f1886d9f156e Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sat, 24 Jul 2010 00:23:50 +0000 Subject: [PATCH 025/777] Merged r3859 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3862 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/admin/_menu.rhtml | 2 +- app/views/settings/_authentication.rhtml | 2 +- public/images/server_key.png | Bin 0 -> 746 bytes public/stylesheets/application.css | 2 ++ 4 files changed, 4 insertions(+), 2 deletions(-) create mode 100644 public/images/server_key.png diff --git a/app/views/admin/_menu.rhtml b/app/views/admin/_menu.rhtml index 9b3bc66b..4fc08d88 100644 --- a/app/views/admin/_menu.rhtml +++ b/app/views/admin/_menu.rhtml @@ -3,7 +3,7 @@
  • <%= link_to l(:label_project_plural), {:controller => 'admin', :action => 'projects'}, :class => 'projects' %>
  • <%= link_to l(:label_user_plural), {:controller => 'users'}, :class => 'users' %>
  • <%= link_to l(:label_group_plural), {:controller => 'groups'}, :class => 'groups' %>
  • -
  • <%= link_to l(:label_ldap_authentication), :controller => 'ldap_auth_sources', :action => 'index' %>
  • +
  • <%= link_to l(:label_ldap_authentication), {:controller => 'ldap_auth_sources', :action => 'index'}, :class => 'server_authentication' %>
  • <%= link_to l(:label_role_and_permissions), {:controller => 'roles'}, :class => 'roles' %>
  • <%= link_to l(:label_tracker_plural), {:controller => 'trackers'}, :class => 'trackers' %>
  • <%= link_to l(:label_issue_status_plural), {:controller => 'issue_statuses'}, :class => 'issue_statuses' %>
  • diff --git a/app/views/settings/_authentication.rhtml b/app/views/settings/_authentication.rhtml index 7e8e693d..da29bb70 100644 --- a/app/views/settings/_authentication.rhtml +++ b/app/views/settings/_authentication.rhtml @@ -20,7 +20,7 @@
- <%= link_to l(:label_ldap_authentication), :controller => 'ldap_auth_sources', :action => 'index' %> + <%= link_to l(:label_ldap_authentication), {:controller => 'ldap_auth_sources', :action => 'index'}, :class => 'icon icon-server-authentication' %>
<%= submit_tag l(:button_save) %> diff --git a/public/images/server_key.png b/public/images/server_key.png new file mode 100644 index 0000000000000000000000000000000000000000..ecd517425f0cf0a573f091656a0c69e294b6197f GIT binary patch literal 746 zcmVR5;6} zlS@n!Q51&%dDs?eX$!L{YO$aaAT^% z8wrtxVNvT!(-=&NwM9+Zn#dzTR2m+|($3p^r?x7Vm6P0@nLFqI&VSCGVRT)`|6Kge zjaV!eR1{@UmSvtqkZ3GPl4zXp`~BxC0uqUYod_N{91g$PTn&+kplLAt5tmM<1L1J! zEP47D5Rb=CQn4Ti`>a+g<`U7ws?&F_ zfzvp|MzQqNH!H3#j~%}BVf-%##aZb_G6l4GJB;cj7tG=`j&}>Nw_Z7xnHjztyK`i@ z<3{><*+B_lKuBdOqW7yc^Z1f_jE;l*VQ=n3ZZU*Cw&q%gTbv4AZ5(1tfU;QqJva(_ zn7WS!r2xBk0P6N9ScH1;)qty~y}GH@J!&|h!zq1{)G}>Brx3Dtt?nj-%`oKk1+ZKO z44Z?gCIb|<@nc2g$}P}S;5e?>w@Rn3!6Yu>fc6sRS^`$SgVipF07*qoM6N<$f~LGuF8}}l literal 0 HcmV?d00001 diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 2067bf3d..60c50d2b 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -64,6 +64,7 @@ h4, .wiki h3 {font-size: 13px;padding: 2px 10px 1px 0px;margin-bottom: 5px; bord #admin-menu a.settings { background-image: url(../images/changeset.png); } #admin-menu a.plugins { background-image: url(../images/plugin.png); } #admin-menu a.info { background-image: url(../images/help.png); } +#admin-menu a.server_authentication { background-image: url(../images/server_key.png); } #main {background-color:#EEEEEE;} @@ -837,6 +838,7 @@ padding-bottom: 3px; .icon-report { background-image: url(../images/report.png); } .icon-comment { background-image: url(../images/comment.png); } .icon-summary { background-image: url(../images/lightning.png); } +.icon-server-authentication { background-image: url(../images/server_key.png); } .icon-file { background-image: url(../images/files/default.png); } .icon-file.text-plain { background-image: url(../images/files/text.png); } From 69f34a595dc3094a3ebbb2de56e0551645866095 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 25 Jul 2010 09:34:04 +0000 Subject: [PATCH 026/777] Merged r3865 and r3866 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3867 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/versions_controller.rb | 3 +++ app/views/versions/show.rhtml | 7 ++----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb index 05c9743e..46b4778d 100644 --- a/app/controllers/versions_controller.rb +++ b/app/controllers/versions_controller.rb @@ -27,6 +27,9 @@ class VersionsController < ApplicationController helper :projects def show + @issues = @version.fixed_issues.visible.find(:all, + :include => [:status, :tracker, :priority], + :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") end def new diff --git a/app/views/versions/show.rhtml b/app/views/versions/show.rhtml index 18bc6bc4..79de5984 100644 --- a/app/views/versions/show.rhtml +++ b/app/views/versions/show.rhtml @@ -32,13 +32,10 @@ <%= render :partial => 'versions/overview', :locals => {:version => @version} %> <%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %> -<% issues = @version.fixed_issues.find(:all, - :include => [:status, :tracker, :priority], - :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") %> -<% if issues.size > 0 %> +<% if @issues.present? %>

<%= avatar(message.author, :size => "24") %> - <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :anchor => "message-#{message.id}" } %> + <%= link_to h(message.subject), { :controller => 'messages', :action => 'show', :board_id => @board, :id => @topic, :r => message, :anchor => "message-#{message.id}" } %> - <%= authoring message.created_on, message.author %>

From 8146e096f434c7b3a20576d8bf4138377f07100c Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 25 Jul 2010 10:35:35 +0000 Subject: [PATCH 032/777] Merged r3879 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3880 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/attachments/_form.rhtml | 3 +-- public/javascripts/application.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/views/attachments/_form.rhtml b/app/views/attachments/_form.rhtml index 7702f92e..6d387d1c 100644 --- a/app/views/attachments/_form.rhtml +++ b/app/views/attachments/_form.rhtml @@ -1,6 +1,5 @@ -<%= file_field_tag 'attachments[1][file]', :size => 30, :id => nil -%> -
diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 612739f5..989065b3 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -52,7 +52,7 @@ function addFileField() { d.type = "text"; d.name = "attachments[" + fileFieldCount + "][description]"; d.size = 60; - var dLabel = document.createElement("label"); + var dLabel = new Element('label'); dLabel.addClassName('inline'); // Pulls the languge value used for Optional Description dLabel.update($('attachment_description_label_content').innerHTML) From 52a12aaca884e1389ac0867dc91200c63d73f41a Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 25 Jul 2010 10:49:08 +0000 Subject: [PATCH 033/777] Merged r3881 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3882 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/issue_status.rb | 9 ++++++++- test/unit/issue_status_test.rb | 8 +++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/models/issue_status.rb b/app/models/issue_status.rb index fdda12a8..f376d5d1 100644 --- a/app/models/issue_status.rb +++ b/app/models/issue_status.rb @@ -17,8 +17,10 @@ class IssueStatus < ActiveRecord::Base before_destroy :check_integrity - has_many :workflows, :foreign_key => "old_status_id", :dependent => :delete_all + has_many :workflows, :foreign_key => "old_status_id" acts_as_list + + before_destroy :delete_workflows validates_presence_of :name validates_uniqueness_of :name @@ -89,4 +91,9 @@ private def check_integrity raise "Can't delete status" if Issue.find(:first, :conditions => ["status_id=?", self.id]) end + + # Deletes associated workflows + def delete_workflows + Workflow.delete_all(["old_status_id = :id OR new_status_id = :id", {:id => id}]) + end end diff --git a/test/unit/issue_status_test.rb b/test/unit/issue_status_test.rb index 2c0685ce..bcc50a48 100644 --- a/test/unit/issue_status_test.rb +++ b/test/unit/issue_status_test.rb @@ -32,10 +32,12 @@ class IssueStatusTest < ActiveSupport::TestCase end def test_destroy - count_before = IssueStatus.count status = IssueStatus.find(3) - assert status.destroy - assert_equal count_before - 1, IssueStatus.count + assert_difference 'IssueStatus.count', -1 do + assert status.destroy + end + assert_nil Workflow.first(:conditions => {:old_status_id => status.id}) + assert_nil Workflow.first(:conditions => {:new_status_id => status.id}) end def test_destroy_status_in_use From e771fc03bd60160f42a9aad552415c79a87e8902 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 25 Jul 2010 11:49:07 +0000 Subject: [PATCH 034/777] Merged r3883, r3884 and r3885 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3886 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/gantts_controller.rb | 2 +- lib/redmine/export/pdf.rb | 17 ++++++++++------- lib/redmine/helpers/gantt.rb | 13 ++++++++++--- 3 files changed, 21 insertions(+), 11 deletions(-) diff --git a/app/controllers/gantts_controller.rb b/app/controllers/gantts_controller.rb index bc2d6350..e762c19c 100644 --- a/app/controllers/gantts_controller.rb +++ b/app/controllers/gantts_controller.rb @@ -37,7 +37,7 @@ class GanttsController < ApplicationController respond_to do |format| format.html { render :action => "show", :layout => !request.xhr? } - format.png { send_data(@gantt.to_image, :disposition => 'inline', :type => 'image/png', :filename => "#{basename}.png") } if @gantt.respond_to?('to_image') + format.png { send_data(@gantt.to_image(@project), :disposition => 'inline', :type => 'image/png', :filename => "#{basename}.png") } if @gantt.respond_to?('to_image') format.pdf { send_data(gantt_to_pdf(@gantt, @project), :type => 'application/pdf', :filename => "#{basename}.pdf") } end end diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb index c2492165..9b1f2b8a 100644 --- a/lib/redmine/export/pdf.rb +++ b/lib/redmine/export/pdf.rb @@ -325,7 +325,7 @@ module Redmine pdf.Ln pdf.SetFontStyle('B',9) - subject_width = 70 + subject_width = 100 header_heigth = 5 headers_heigth = header_heigth @@ -341,7 +341,7 @@ module Redmine end end - g_width = 210 + g_width = 280 - subject_width zoom = (g_width) / (gantt.date_to - gantt.date_from + 1) g_height = 120 t_height = g_height + headers_heigth @@ -415,16 +415,19 @@ module Redmine pdf.SetY(top) pdf.SetX(15) + text = "" if i.is_a? Issue - pdf.Cell(subject_width-15, 5, "#{i.tracker} #{i.id}: #{i.subject}".sub(/^(.{30}[^\s]*\s).*$/, '\1 (...)'), "LR") + text = "#{i.tracker} #{i.id}: #{i.subject}" else - pdf.Cell(subject_width-15, 5, "#{l(:label_version)}: #{i.name}", "LR") + text = i.name end + text = "#{i.project} - #{text}" unless project && project == i.project + pdf.Cell(subject_width-15, 5, text, "LR") - pdf.SetY(top) + pdf.SetY(top + 0.2) pdf.SetX(subject_width) - pdf.Cell(g_width, 5, "", "LR") - + pdf.SetFillColor(255, 255, 255) + pdf.Cell(g_width, 4.6, "", "LR", 0, "", 1) pdf.SetY(top+1.5) if i.is_a? Issue diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb index 330b58ee..96ba4db7 100644 --- a/lib/redmine/helpers/gantt.rb +++ b/lib/redmine/helpers/gantt.rb @@ -91,12 +91,12 @@ module Redmine # Generates a gantt image # Only defined if RMagick is avalaible - def to_image(format='PNG') + def to_image(project, format='PNG') date_to = (@date_from >> @months)-1 show_weeks = @zoom > 1 show_days = @zoom > 2 - subject_width = 320 + subject_width = 400 header_heigth = 18 # width of one day in pixels zoom = @zoom*2 @@ -115,7 +115,14 @@ module Redmine gc.stroke('transparent') gc.stroke_width(1) events.each do |i| - gc.text(4, top + 2, (i.is_a?(Issue) ? i.subject : i.name)) + text = "" + if i.is_a? Issue + text = "#{i.tracker} #{i.id}: #{i.subject}" + else + text = i.name + end + text = "#{i.project} - #{text}" unless project && project == i.project + gc.text(4, top + 2, text) top = top + 20 end From f682be8468f12acc0ad6cd313cb5805e58c63504 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 25 Jul 2010 11:56:45 +0000 Subject: [PATCH 035/777] Merged r3887 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3888 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/issues/context_menu.rhtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/issues/context_menu.rhtml b/app/views/issues/context_menu.rhtml index 489896e0..d9e92a4f 100644 --- a/app/views/issues/context_menu.rhtml +++ b/app/views/issues/context_menu.rhtml @@ -34,7 +34,7 @@
    <% @priorities.each do |p| -%>
  • <%= context_menu_link p.name, {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'priority_id' => p}, :back_url => @back}, :method => :post, - :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || !@issue.leaf?) %>
  • + :selected => (@issue && p == @issue.priority), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %> <% end -%>
@@ -83,7 +83,7 @@
    <% (0..10).map{|x|x*10}.each do |p| -%>
  • <%= context_menu_link "#{p}%", {:controller => 'issues', :action => 'bulk_edit', :ids => @issues.collect(&:id), :issue => {'done_ratio' => p}, :back_url => @back}, :method => :post, - :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || !@issue.leaf?) %>
  • + :selected => (@issue && p == @issue.done_ratio), :disabled => (!@can[:edit] || @issues.detect {|i| !i.leaf?}) %> <% end -%>
From 29e7ae969824c4f2b65e5158c48b1079678a7f93 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 25 Jul 2010 12:49:15 +0000 Subject: [PATCH 036/777] Merged r3889 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3890 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/admin/_menu.rhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/_menu.rhtml b/app/views/admin/_menu.rhtml index 4fc08d88..a8de8885 100644 --- a/app/views/admin/_menu.rhtml +++ b/app/views/admin/_menu.rhtml @@ -3,7 +3,6 @@
  • <%= link_to l(:label_project_plural), {:controller => 'admin', :action => 'projects'}, :class => 'projects' %>
  • <%= link_to l(:label_user_plural), {:controller => 'users'}, :class => 'users' %>
  • <%= link_to l(:label_group_plural), {:controller => 'groups'}, :class => 'groups' %>
  • -
  • <%= link_to l(:label_ldap_authentication), {:controller => 'ldap_auth_sources', :action => 'index'}, :class => 'server_authentication' %>
  • <%= link_to l(:label_role_and_permissions), {:controller => 'roles'}, :class => 'roles' %>
  • <%= link_to l(:label_tracker_plural), {:controller => 'trackers'}, :class => 'trackers' %>
  • <%= link_to l(:label_issue_status_plural), {:controller => 'issue_statuses'}, :class => 'issue_statuses' %>
  • @@ -11,6 +10,7 @@
  • <%= link_to l(:label_custom_field_plural), {:controller => 'custom_fields'}, :class => 'custom_fields' %>
  • <%= link_to l(:label_enumerations), {:controller => 'enumerations'}, :class => 'enumerations' %>
  • <%= link_to l(:label_settings), {:controller => 'settings'}, :class => 'settings' %>
  • +
  • <%= link_to l(:label_ldap_authentication), {:controller => 'ldap_auth_sources', :action => 'index'}, :class => 'server_authentication' %>
  • <% menu_items_for(:admin_menu) do |item| -%>
  • <%= link_to h(item.caption), item.url, item.html_options %>
  • <% end -%> From 8f64938b9e36df0464a77cfb37621e0dedab892d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 25 Jul 2010 12:57:49 +0000 Subject: [PATCH 037/777] Merged r3891 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3892 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- public/stylesheets/application.css | 1 + 1 file changed, 1 insertion(+) diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 60c50d2b..b3dbfd7f 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -697,6 +697,7 @@ div.wiki pre { border: 1px solid #dadada; width:auto; overflow-x: auto; + overflow-y: hidden; } div.wiki ul.toc { From d34abea14e39f49bead8c7d7a72f23c85f4e1532 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 29 Jul 2010 11:30:24 +0200 Subject: [PATCH 038/777] use the journal formatters API to register the issue journal formats --- app/models/issue.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index 76010358..72443107 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -36,9 +36,15 @@ class Issue < ActiveRecord::Base acts_as_customizable acts_as_watchable - acts_as_journalized :event_title => Proc.new {|o| "#{o.tracker.name} ##{o.id} (#{o.status}): #{o.subject}"}, + acts_as_journalized :event_title => Proc.new {|o| "#{o.tracker.name} ##{o.versioned.id} (#{o.status}): #{o.subject}"}, :event_type => Proc.new {|o| 'issue' + (o.closed? ? ' closed' : '') } + register_on_journal_formatter(:id, 'parent_id') + register_on_journal_formatter(:named_association, 'project_id', 'status_id', 'tracker_id', 'assigned_to_id', + 'priority_id', 'category_id', 'fixed_version_id') + register_on_journal_formatter(:fraction, 'estimated_hours', 'done_ratio') + register_on_journal_formatter(:datetime, 'due_date', 'start_date') + acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], :include => [:project, :journals], # sort by id so that limited eager loading doesn't break with postgresql From 75024acf5a31b1f426a87823926649771af61b79 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 29 Jul 2010 11:31:06 +0200 Subject: [PATCH 039/777] possibly use the activity permissions in the fetcher to find visible event types --- lib/redmine/activity/fetcher.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/redmine/activity/fetcher.rb b/lib/redmine/activity/fetcher.rb index eb319837..6dca3275 100644 --- a/lib/redmine/activity/fetcher.rb +++ b/lib/redmine/activity/fetcher.rb @@ -38,7 +38,15 @@ module Redmine return @event_types unless @event_types.nil? @event_types = Redmine::Activity.available_event_types - @event_types = @event_types.select {|o| @user.allowed_to?("view_#{o}".to_sym, @project)} if @project + @event_types = @event_types.select do |o| + permissions = constantized_providers(o).collect do |p| + p.activity_provider_options[o].try(:[], :permission) + end.compact + if @project + return @user.allowed_to?("view_#{o}".to_sym, @project) if permissions.blank? + permissions.all? {|p| @user.allowed_to?(p, @project) } if @project + end + end @event_types end From 5de0d0997f06ad4e233665961f18725bdb0e7716 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 29 Jul 2010 14:48:24 +0200 Subject: [PATCH 040/777] remove the reply action from IssueController, and use the JournalHelper API for that --- app/controllers/issues_controller.rb | 35 ++++++---------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 5f074527..c0904e2e 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -18,8 +18,8 @@ class IssuesController < ApplicationController menu_item :new_issue, :only => [:new, :create] default_search_scope :issues - - before_filter :find_issue, :only => [:show, :edit, :update, :reply] + + before_filter :find_issue, :only => [:show, :edit, :update] before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] before_filter :find_project, :only => [:new, :create, :update_form, :preview, :auto_complete] before_filter :authorize, :except => [:index, :changes, :preview, :context_menu] @@ -29,10 +29,11 @@ class IssuesController < ApplicationController accept_key_auth :index, :show, :changes rescue_from Query::StatementInvalid, :with => :query_statement_invalid - + helper :journals + include JournalsHelper helper :projects - include ProjectsHelper + include ProjectsHelper helper :custom_fields include CustomFieldsHelper helper :issue_relations @@ -162,8 +163,9 @@ class IssuesController < ApplicationController # Attributes that can be updated on workflow transition (without :edit permission) # TODO: make it configurable (at least per role) UPDATABLE_ATTRS_ON_TRANSITION = %w(status_id assigned_to_id fixed_version_id done_ratio) unless const_defined?(:UPDATABLE_ATTRS_ON_TRANSITION) - + def edit + return render_reply(@journal) if @journal update_issue_from_params @journal = @issue.current_journal @@ -199,29 +201,6 @@ class IssuesController < ApplicationController end end - def reply - journal = Journal.find(params[:journal_id]) if params[:journal_id] - if journal - user = journal.user - text = journal.notes - else - user = @issue.author - text = @issue.description - end - # Replaces pre blocks with [...] - text = text.to_s.strip.gsub(%r{
    ((.|\s)*?)
    }m, '[...]') - content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " - content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - - render(:update) { |page| - page.<< "$('notes').value = \"#{escape_javascript content}\";" - page.show 'update' - page << "Form.Element.focus('notes');" - page << "Element.scrollTo('update');" - page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" - } - end - # Bulk edit a set of issues def bulk_edit @issues.sort! From f45bb1e85ef20e0601629174dfd72c2299629a0d Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 29 Jul 2010 14:48:47 +0200 Subject: [PATCH 041/777] use the render_journal API to pass Issue note editing permissions --- app/views/issues/_history.rhtml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml index 4193403a..8d048dbf 100644 --- a/app/views/issues/_history.rhtml +++ b/app/views/issues/_history.rhtml @@ -1,4 +1,5 @@ <% for journal in journals %> - <%= render_journal(issue, journal) %> + <%= render_journal issue, journal, :edit_permission => :edit_issue_notes, + :edit_own_permission => :edit_own_issue_notes %> <%= call_hook(:view_issues_history_journal_bottom, { :journal => journal }) %> <% end %> From 0843b188fb8397431278367c5f58029b281b5f5f Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 29 Jul 2010 15:03:06 +0000 Subject: [PATCH 042/777] Merged r3893 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3895 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- config/locales/de.yml | 1 + config/locales/he.yml | 737 +++++++++++++++++++++--------------------- config/locales/hu.yml | 34 +- 3 files changed, 389 insertions(+), 383 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 70ea4548..8e3c4455 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -136,6 +136,7 @@ de: greater_than_start_date: "muss größer als Anfangsdatum sein" not_same_project: "gehört nicht zum selben Projekt" circular_dependency: "Diese Beziehung würde eine zyklische Abhängigkeit erzeugen" + cant_link_an_issue_with_a_descendant: "Ein Ticket kann nicht mit einer ihrer Unteraufgaben verlinkt werden" actionview_instancetag_blank_option: Bitte auswählen diff --git a/config/locales/he.yml b/config/locales/he.yml index 125f0265..f84fd01f 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -1,5 +1,6 @@ -# Hebrew translations for Ruby on Rails -# by Dotan Nahum (dipidi@gmail.com) +# Hebrew translation for Redmine +# Initiated by Dotan Nahum (dipidi@gmail.com) +# Jul 2010 - Updated by Orgad Shaneh (orgads@gmail.com) he: date: @@ -14,7 +15,7 @@ he: month_names: [~, ינואר, פברואר, מרץ, אפריל, מאי, יוני, יולי, אוגוסט, ספטמבר, אוקטובר, נובמבר, דצמבר] abbr_month_names: [~, יאנ, פבר, מרץ, אפר, מאי, יונ, יול, אוג, ספט, אוק, נוב, דצמ] order: [ :day, :month, :year ] - + time: formats: default: "%a %d/%m/%Y %H:%M:%S" @@ -22,28 +23,28 @@ he: short: "%d %b %H:%M" long: "%B %d, %Y %H:%M" only_second: "%S" - + datetime: formats: default: "%d-%m-%YT%H:%M:%S%Z" - + am: 'am' pm: 'pm' - + datetime: distance_in_words: half_a_minute: 'חצי דקה' less_than_x_seconds: - zero: 'פחות משניה אחת' - one: 'פחות משניה אחת' - other: 'פחות מ- {{count}} שניות' + zero: 'פחות משניה' + one: 'פחות משניה' + other: 'פחות מ־{{count}} שניות' x_seconds: one: 'שניה אחת' other: '{{count}} שניות' less_than_x_minutes: zero: 'פחות מדקה אחת' one: 'פחות מדקה אחת' - other: 'פחות מ- {{count}} דקות' + other: 'פחות מ־{{count}} דקות' x_minutes: one: 'דקה אחת' other: '{{count}} דקות' @@ -66,9 +67,9 @@ he: one: 'מעל שנה אחת' other: 'מעל {{count}} שנים' almost_x_years: - one: "almost 1 year" - other: "almost {{count}} years" - + one: "כמעט שנה" + other: "כמעט {{count}} שנים" + number: format: precision: 3 @@ -76,7 +77,7 @@ he: delimiter: ',' currency: format: - unit: 'שח' + unit: 'ש"ח' precision: 2 format: '%u %n' human: @@ -84,18 +85,18 @@ he: format: "%n %u" units: byte: - one: "Byte" - other: "Bytes" + one: "בייט" + other: "בתים" kb: "KB" mb: "MB" gb: "GB" tb: "TB" - + support: array: - sentence_connector: "and" - skip_last_comma: false - + sentence_connector: "וגם" + skip_last_comma: true + activerecord: errors: messages: @@ -106,16 +107,16 @@ he: accepted: "חייב באישור" empty: "חייב להכלל" blank: "חייב להכלל" - too_long: "יותר מדי ארוך (לא יותר מ- {{count}} תוים)" - too_short: "יותר מדי קצר (לא יותר מ- {{count}} תוים)" + too_long: "ארוך מדי (לא יותר מ־{{count}} תוים)" + too_short: "קצר מדי (לא יותר מ־{{count}} תוים)" wrong_length: "לא באורך הנכון (חייב להיות {{count}} תוים)" taken: "לא זמין" not_a_number: "הוא לא מספר" - greater_than: "חייב להיות גדול מ- {{count}}" - greater_than_or_equal_to: "חייב להיות גדול או שווה ל- {{count}}" - equal_to: "חייב להיות שווה ל- {{count}}" - less_than: "חייב להיות קטן מ- {{count}}" - less_than_or_equal_to: "חייב להיות קטן או שווה ל- {{count}}" + greater_than: "חייב להיות גדול מ־{{count}}" + greater_than_or_equal_to: "חייב להיות גדול או שווה ל־{{count}}" + equal_to: "חייב להיות שווה ל־{{count}}" + less_than: "חייב להיות קטן מ־{{count}}" + less_than_or_equal_to: "חייב להיות קטן או שווה ל־{{count}}" odd: "חייב להיות אי זוגי" even: "חייב להיות זוגי" greater_than_start_date: "חייב להיות מאוחר יותר מתאריך ההתחלה" @@ -123,7 +124,7 @@ he: circular_dependency: "הקשר הזה יצור תלות מעגלית" actionview_instancetag_blank_option: בחר בבקשה - + general_text_No: 'לא' general_text_Yes: 'כן' general_text_no: 'לא' @@ -131,10 +132,10 @@ he: general_lang_name: 'Hebrew (עברית)' general_csv_separator: ',' general_csv_decimal_separator: '.' - general_csv_encoding: ISO-8859-8-I - general_pdf_encoding: ISO-8859-8-I + general_csv_encoding: ISO-8859-8 + general_pdf_encoding: ISO-8859-8 general_first_day_of_week: '7' - + notice_account_updated: החשבון עודכן בהצלחה! notice_account_invalid_creditentials: שם משתמש או סיסמה שגויים notice_account_password_updated: הסיסמה עודכנה בהצלחה! @@ -148,26 +149,59 @@ he: notice_successful_update: עידכון מוצלח. notice_successful_delete: מחיקה מוצלחת. notice_successful_connection: חיבור מוצלח. - notice_file_not_found: הדף שאת\ה מנסה לגשת אליו אינו קיים או שהוסר. + notice_file_not_found: הדף שאתה מנסה לגשת אליו אינו קיים או שהוסר. notice_locking_conflict: המידע עודכן על ידי משתמש אחר. notice_not_authorized: אינך מורשה לראות דף זה. notice_email_sent: "דואל נשלח לכתובת {{value}}" notice_email_error: "ארעה שגיאה בעט שליחת הדואל ({{value}})" - notice_feeds_access_key_reseted: מפתח ה-RSS שלך אופס. + notice_feeds_access_key_reseted: מפתח ה־RSS שלך אופס. + notice_api_access_key_reseted: מפתח הגישה שלך ל־API אופס. notice_failed_to_save_issues: "נכשרת בשמירת {{count}} נושא\ים ב {{total}} נבחרו: {{ids}}." + notice_failed_to_save_members: "כשלון בשמירת חבר(ים): {{errors}}." notice_no_issue_selected: "לא נבחר אף נושא! בחר בבקשה את הנושאים שברצונך לערוך." - - error_scm_not_found: כניסה ו\או גירסא אינם קיימים במאגר. + notice_account_pending: "החשבון שלך נוצר ועתה מחכה לאישור מנהל המערכת." + notice_default_data_loaded: אפשרויות ברירת מחדל מופעלות. + notice_unable_delete_version: לא ניתן למחוק גירסה + notice_unable_delete_time_entry: לא ניתן למחוק רשומת זמן. + notice_issue_done_ratios_updated: אחוזי התקדמות לנושא עודכנו. + + error_can_t_load_default_data: "אפשרויות ברירת המחדל לא הצליחו להיטען: {{value}}" + error_scm_not_found: כניסה ו\או גירסה אינם קיימים במאגר. error_scm_command_failed: "ארעה שגיאה בעת ניסון גישה למאגר: {{value}}" - - mail_subject_lost_password: "סיסמת ה-{{value}} שלך" - mail_body_lost_password: 'לשינו סיסמת ה-Redmine שלך,לחץ על הקישור הבא:' + error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר אותה." + error_issue_not_found_in_project: 'הנושאים לא נמצאו או אינם שיכים לפרויקט' + error_no_tracker_in_project: לא הוגדר סיווג לפרויקט זה. נא בדוק את הגדרות הפרויקט. + error_no_default_issue_status: לא מוגדר מצב ברירת מחדל לנושאים. נא בדוק את התצורה ("ניהול -> מצבי נושא"). + error_can_not_delete_custom_field: לא ניתן למחוק שדה מותאם אישית + error_can_not_delete_tracker: קיימים נושאים בסיווג זה, ולא ניתן למחוק אותו. + error_can_not_remove_role: תפקיד זה נמצא בשימוש, ולא ניתן למחוק אותו. + error_can_not_reopen_issue_on_closed_version: לא ניתן לפתוח מחדש נושא שמשויך לגירסה סגורה + error_can_not_archive_project: לא ניתן לארכב פרויקט זה + error_issue_done_ratios_not_updated: אחוז התקדמות לנושא לא עודכן. + error_workflow_copy_source: נא בחר סיווג או תפקיד מקור + error_workflow_copy_target: נא בחר תפקיד(ים) וסיווג(ים) + error_unable_delete_issue_status: לא ניתן למחוק מצב נושא + error_unable_to_connect: לא ניתן להתחבר ({{value}}) + warning_attachments_not_saved: "כשלון בשמירת {{count}} קבצים." + + mail_subject_lost_password: "סיסמת ה־{{value}} שלך" + mail_body_lost_password: 'לשינו סיסמת ה־Redmine שלך, לחץ על הקישור הבא:' mail_subject_register: "הפעלת חשבון {{value}}" - mail_body_register: 'להפעלת חשבון ה-Redmine שלך, לחץ על הקישור הבא:' - + mail_body_register: 'להפעלת חשבון ה־Redmine שלך, לחץ על הקישור הבא:' + mail_body_account_information_external: "אתה יכול להשתמש בחשבון {{value}} כדי להתחבר" + mail_body_account_information: פרטי החשבון שלך + mail_subject_account_activation_request: "בקשת הפעלה לחשבון {{value}}" + mail_body_account_activation_request: "משתמש חדש ({{value}}) נרשם. החשבון שלו מחכה לאישור שלך:" + mail_subject_reminder: "{{count}} נושאים מיעדים להגשה בימים הקרובים" + mail_body_reminder: "{{count}} נושאים שמיועדים אליך מיועדים להגשה בתוך {{days}} ימים:" + mail_subject_wiki_content_added: "דף ה־wiki ‏'{{page}}' נוסף" + mail_body_wiki_content_added: דף ה־wiki ‏'{{page}}' נוסף ע"י {{author}}. + mail_subject_wiki_content_updated: "דף ה־wiki ‏'{{page}}' עודכן" + mail_body_wiki_content_updated: דף ה־wiki ‏'{{page}}' עודכן ע"י {{author}}. + gui_validation_error: שגיאה 1 gui_validation_error_plural: "{{count}} שגיאות" - + field_name: שם field_description: תיאור field_summary: תקציר @@ -199,10 +233,11 @@ he: field_tracker: סיווג field_subject: שם נושא field_due_date: תאריך סיום - field_assigned_to: מוצב ל + field_assigned_to: אחראי field_priority: עדיפות - field_fixed_version: גירסאת יעד + field_fixed_version: גירסת יעד field_user: מתשמש + field_principal: מנהל field_role: תפקיד field_homepage: דף הבית field_is_public: פומבי @@ -217,7 +252,7 @@ he: field_password: סיסמה field_new_password: סיסמה חדשה field_password_confirmation: אישור - field_version: גירסא + field_version: גירסה field_type: סוג field_host: שרת field_port: פורט @@ -235,7 +270,7 @@ he: field_comments: הערות field_url: URL field_start_page: דף התחלתי - field_subproject: תת פרויקט + field_subproject: תת־פרויקט field_hours: שעות field_activity: פעילות field_spent_on: תאריך @@ -247,10 +282,21 @@ he: field_redirect_existing_links: העבר קישורים קיימים field_estimated_hours: זמן משוער field_column_names: עמודות + field_time_zone: איזור זמן + field_searchable: ניתן לחיפוש field_default_value: ערך ברירת מחדל - + field_comments_sorting: הצג הערות + field_parent_title: דף אב + field_editable: ניתן לעריכה + field_watcher: צופה + field_identity_url: כתובת OpenID + field_content: תוכן + field_group_by: קבץ את התוצאות לפי + field_sharing: שיתוף + field_parent_issue: משימת אב + setting_app_title: כותרת ישום - setting_app_subtitle: תת-כותרת ישום + setting_app_subtitle: תת־כותרת ישום setting_welcome_text: טקסט "ברוך הבא" setting_default_language: שפת ברירת מחדל setting_login_required: דרוש אימות @@ -258,39 +304,140 @@ he: setting_attachment_max_size: גודל דבוקה מקסימאלי setting_issues_export_limit: גבול יצוא נושאים setting_mail_from: כתובת שליחת דוא"ל + setting_bcc_recipients: מוסתר (bcc) + setting_plain_text_mail: טקסט פשוט בלבד (ללא HTML) setting_host_name: שם שרת setting_text_formatting: עיצוב טקסט setting_wiki_compression: כיווץ היסטורית WIKI setting_feeds_limit: גבול תוכן הזנות - setting_autofetch_changesets: משיכה אוטומתי של עידכונים - setting_sys_api_enabled: אפשר WS לניהול המאגר + setting_default_projects_public: פרויקטים חדשים הינם פומביים כברירת מחדל + setting_autofetch_changesets: משיכה אוטומטית של עידכונים + setting_sys_api_enabled: אפשר שירות רשת לניהול המאגר setting_commit_ref_keywords: מילות מפתח מקשרות setting_commit_fix_keywords: מילות מפתח מתקנות setting_autologin: חיבור אוטומטי setting_date_format: פורמט תאריך + setting_time_format: פורמט זמן setting_cross_project_issue_relations: הרשה קישור נושאים בין פרויקטים setting_issue_list_default_columns: עמודות ברירת מחדל המוצגות ברשימת הנושאים setting_repositories_encodings: קידוד המאגרים - + setting_commit_logs_encoding: קידוד הודעות הפקדה + setting_emails_footer: תחתית דוא"ל + setting_protocol: פרוטוקול + setting_per_page_options: אפשרויות אוביקטים לפי דף + setting_user_format: פורמט הצגת משתמשים + setting_activity_days_default: ימים המוצגים על פעילות הפרויקט + setting_display_subprojects_issues: הצג נושאים של תתי־פרויקטים כברירת מחדל + setting_enabled_scm: אפשר ניהול תצורה + setting_mail_handler_body_delimiters: חתוך כתובות דואר אחרי אחת משורות אלה + setting_mail_handler_api_enabled: אפשר שירות רשת לדואר נכנס + setting_mail_handler_api_key: מפתח API + setting_sequential_project_identifiers: השתמש במספרים עוקבים למזהי פרויקט + setting_gravatar_enabled: שימוש בצלמיות משתמשים מ־Gravatar + setting_gravatar_default: תמונת Gravatar ברירת מחדל + setting_diff_max_lines_displayed: מספר מירבי של שורות בתצוגת שינויים + setting_file_max_size_displayed: גודל מירבי של מלל המוצג בתוך השורה + setting_repository_log_display_limit: מספר מירבי של גירסאות המוצגות ביומן קובץ + setting_openid: אפשר התחברות ורישום באמצעות OpenID + setting_password_min_length: אורך סיסמא מינימאלי + setting_new_project_user_role_id: התפקיד שמוגדר למשתמש פשוט אשר יוצר פרויקט + setting_default_projects_modules: מודולים מאופשרים בברירת מחדל עבור פרויקטים חדשים + setting_issue_done_ratio: חשב אחוז התקדמות בנושא עם + setting_issue_done_ratio_issue_field: השתמש בשדה הנושא + setting_issue_done_ratio_issue_status: השתמש במצב הנושא + setting_start_of_week: התחל יומנים לפי + setting_rest_api_enabled: אפשר שירות רשת REST + setting_cache_formatted_text: שמור טקסט מעוצב במטמון + + permission_add_project: יצירת פרויקט + permission_add_subprojects: יצירת תתי־פרויקט + permission_edit_project: עריכת פרויקט + permission_select_project_modules: בחירת מודולי פרויקט + permission_manage_members: ניהול חברים + permission_manage_project_activities: נהל פעילויות פרויקט + permission_manage_versions: ניהול גירסאות + permission_manage_categories: ניהול קטגוריות נושאים + permission_view_issues: צפיה בנושאים + permission_add_issues: הוספת נושא + permission_edit_issues: עריכת נושאים + permission_manage_issue_relations: ניהול קשרים בין נושאים + permission_add_issue_notes: הוספת הערות לנושאים + permission_edit_issue_notes: עריכת רשימות + permission_edit_own_issue_notes: עריכת הערות של עצמו + permission_move_issues: הזזת נושאים + permission_delete_issues: מחיקת נושאים + permission_manage_public_queries: ניהול שאילתות פומביות + permission_save_queries: שמירת שאילתות + permission_view_gantt: צפיה בגאנט + permission_view_calendar: צפיה בלוח השנה + permission_view_issue_watchers: צפיה ברשימת צופים + permission_add_issue_watchers: הוספת צופים + permission_delete_issue_watchers: הסרת צופים + permission_log_time: תיעוד זמן שהושקע + permission_view_time_entries: צפיה בזמן שהושקע + permission_edit_time_entries: עריכת רישום זמנים + permission_edit_own_time_entries: עריכת לוג הזמן של עצמו + permission_manage_news: ניהול חדשות + permission_comment_news: תגובה לחדשות + permission_manage_documents: ניהול מסמכים + permission_view_documents: צפיה במסמכים + permission_manage_files: ניהול קבצים + permission_view_files: צפיה בקבצים + permission_manage_wiki: ניהול wiki + permission_rename_wiki_pages: שינוי שם של דפי wiki + permission_delete_wiki_pages: מחיקת דפי wiki + permission_view_wiki_pages: צפיה ב־wiki + permission_view_wiki_edits: צפיה בהיסטורית wiki + permission_edit_wiki_pages: עריכת דפי wiki + permission_delete_wiki_pages_attachments: מחיקת דבוקות + permission_protect_wiki_pages: הגנה על כל דפי wiki + permission_manage_repository: ניהול מאגר + permission_browse_repository: סיור במאגר + permission_view_changesets: צפיה בקבוצות שינויים + permission_commit_access: אישור הפקדות + permission_manage_boards: ניהול לוחות + permission_view_messages: צפיה בהודעות + permission_add_messages: הצבת הודעות + permission_edit_messages: עריכת הודעות + permission_edit_own_messages: עריכת הודעות של עצמו + permission_delete_messages: מחיקת הודעות + permission_delete_own_messages: מחיקת הודעות של עצמו + permission_export_wiki_pages: יצא דפי wiki + permission_manage_subtasks: נהל תתי־משימות + + project_module_issue_tracking: מעקב נושאים + project_module_time_tracking: מעקב אחר זמנים + project_module_news: חדשות + project_module_documents: מסמכים + project_module_files: קבצים + project_module_wiki: Wiki + project_module_repository: מאגר + project_module_boards: לוחות + label_user: משתמש label_user_plural: משתמשים label_user_new: משתמש חדש + label_user_anonymous: אלמוני label_project: פרויקט label_project_new: פרויקט חדש label_project_plural: פרויקטים label_x_projects: - zero: no projects - one: 1 project - other: "{{count}} projects" + zero: ללא פרויקטים + one: פרויקט אחד + other: "{{count}} פרויקטים" label_project_all: כל הפרויקטים label_project_latest: הפרויקטים החדשים ביותר label_issue: נושא label_issue_new: נושא חדש label_issue_plural: נושאים label_issue_view_all: צפה בכל הנושאים + label_issues_by: "נושאים לפי {{value}}" + label_issue_added: נושא נוסף + label_issue_updated: נושא עודכן label_document: מסמך label_document_new: מסמך חדש label_document_plural: מסמכים + label_document_added: מוסמך נוסף label_role: תפקיד label_role_plural: תפקידים label_role_new: תפקיד חדש @@ -317,11 +464,13 @@ he: label_information_plural: מידע label_please_login: התחבר בבקשה label_register: הרשמה + label_login_with_open_id_option: או התחבר באמצעות OpenID label_password_lost: אבדה הסיסמה? label_home: דף הבית label_my_page: הדף שלי label_my_account: החשבון שלי label_my_projects: הפרויקטים שלי + label_my_page_block: בלוק הדף שלי label_administration: ניהול label_login: התחבר label_logout: התנתק @@ -331,6 +480,8 @@ he: label_last_login: חיבור אחרון label_registered_on: נרשם בתאריך label_activity: פעילות + label_overall_activity: פעילות כוללת + label_user_activity: "הפעילות של {{value}}" label_new: חדש label_logged_as: מחובר כ label_environment: סביבה @@ -338,11 +489,14 @@ he: label_auth_source: מצב אישור label_auth_source_new: מצב אישור חדש label_auth_source_plural: מצבי אישור - label_subproject_plural: תת-פרויקטים + label_subproject_plural: תת־פרויקטים + label_subproject_new: תת־פרויקט חדש + label_and_its_subprojects: "{{value}} וכל תתי־הפרויקטים שלו" label_min_max_length: אורך מינימאלי - מקסימאלי label_list: רשימה label_date: תאריך label_integer: מספר שלם + label_float: צף label_boolean: ערך בוליאני label_string: טקסט label_text: טקסט ארוך @@ -357,6 +511,7 @@ he: label_attachment_new: קובץ חדש label_attachment_delete: מחק קובץ label_attachment_plural: קבצים + label_file_added: קובץ נוסף label_report: דו"ח label_report_plural: דו"חות label_news: חדשות @@ -364,11 +519,13 @@ he: label_news_plural: חדשות label_news_latest: חדשות אחרונות label_news_view_all: צפה בכל החדשות + label_news_added: חדשות הוספו label_settings: הגדרות label_overview: מבט רחב - label_version: גירסא - label_version_new: גירסא חדשה + label_version: גירסה + label_version_new: גירסה חדשה label_version_plural: גירסאות + label_close_versions: סגור גירסאות שהושלמו label_confirmation: אישור label_export_to: יצא ל label_read: קרא... @@ -395,6 +552,7 @@ he: label_new_statuses_allowed: מצבים חדשים אפשריים label_all: הכל label_none: כלום + label_nobody: אף אחד label_next: הבא label_previous: הקודם label_used_by: בשימוש ע"י @@ -426,9 +584,19 @@ he: label_not_equals: הוא לא label_in_less_than: בפחות מ label_in_more_than: ביותר מ + label_greater_or_equal: ">=" + label_less_or_equal: <= label_in: ב label_today: היום + label_all_time: תמיד + label_yesterday: אתמול label_this_week: השבוע + label_last_week: שבוע שעבר + label_last_n_days: "ב־{{count}} ימים אחרונים" + label_this_month: החודש + label_last_month: חודש שעבר + label_this_year: השנה + label_date_range: טווח תאריכים label_less_than_ago: פחות מ label_more_than_ago: יותר מ label_ago: לפני @@ -436,17 +604,25 @@ he: label_not_contains: לא מכיל label_day_plural: ימים label_repository: מאגר + label_repository_plural: מאגרים label_browse: סייר label_modification: "שינוי {{count}}" label_modification_plural: "{{count}} שינויים" - label_revision: גירסא + label_branch: ענף + label_tag: סימון + label_revision: גירסה label_revision_plural: גירסאות + label_revision_id: גירסה {{value}} + label_associated_revisions: גירסאות קשורות label_added: נוסף label_modified: שונה + label_copied: הועתק + label_renamed: השם שונה label_deleted: נמחק - label_latest_revision: גירסא אחרונה + label_latest_revision: גירסה אחרונה label_latest_revision_plural: גירסאות אחרונות label_view_revisions: צפה בגירסאות + label_view_all_revisions: צפה בכל הגירסאות label_max_size: גודל מקסימאלי label_sort_highest: הזז לראשית label_sort_higher: הזז למעלה @@ -455,7 +631,7 @@ he: label_roadmap: מפת הדרכים label_roadmap_due_in: "נגמר בעוד {{value}}" label_roadmap_overdue: "{{value}} מאחר" - label_roadmap_no_issues: אין נושאים לגירסא זו + label_roadmap_no_issues: אין נושאים לגירסה זו label_search: חפש label_result_plural: תוצאות label_all_words: כל המילים @@ -466,12 +642,13 @@ he: label_wiki_page_plural: דפי Wiki label_index_by_title: סדר על פי כותרת label_index_by_date: סדר על פי תאריך - label_current_version: גירסא נוכאית + label_current_version: גירסה נוכחית label_preview: תצוגה מקדימה label_feed_plural: הזנות label_changes_details: פירוט כל השינויים label_issue_tracking: מעקב אחר נושאים label_spent_time: זמן שהושקע + label_overall_spent_time: זמן שהושקע סה"כ label_f_hour: "{{value}} שעה" label_f_hour_plural: "{{value}} שעות" label_time_tracking: מעקב זמנים @@ -479,7 +656,7 @@ he: label_statistics: סטטיסטיקות label_commits_per_month: הפקדות לפי חודש label_commits_per_author: הפקדות לפי כותב - label_view_diff: צפה בהבדלים + label_view_diff: צפה בשינויים label_diff_inline: בתוך השורה label_diff_side_by_side: צד לצד label_options: אפשרויות @@ -487,12 +664,13 @@ he: label_permissions_report: דו"ח הרשאות label_watched_issues: נושאים שנצפו label_related_issues: נושאים קשורים - label_applied_status: מוצב מוחל + label_applied_status: מצב מוחל label_loading: טוען... label_relation_new: קשר חדש label_relation_delete: מחק קשר label_relates_to: קשור ל label_duplicates: מכפיל את + label_duplicated_by: שוכפל ע"י label_blocks: חוסם את label_blocked_by: חסום ע"י label_precedes: מקדים את @@ -508,10 +686,13 @@ he: label_board: פורום label_board_new: פורום חדש label_board_plural: פורומים + label_board_locked: נעול + label_board_sticky: דביק label_topic_plural: נושאים label_message_plural: הודעות label_message_last: הודעה אחרונה label_message_new: הודעה חדשה + label_message_posted: הודעה הוספה label_reply_plural: השבות label_send_information: שלח מידע על חשבון למשתמש label_year: שנה @@ -522,9 +703,12 @@ he: label_language_based: מבוסס שפה label_sort_by: "מין לפי {{value}}" label_send_test_email: שלח דוא"ל בדיקה + label_feeds_access_key: מפתח גישה ל־RSS + label_missing_feeds_access_key: חסר מפתח גישה ל־RSS label_feeds_access_key_created_on: "מפתח הזנת RSS נוצר לפני{{value}}" label_module_plural: מודולים label_added_time_by: "נוסף על ידי {{author}} לפני {{age}} " + label_updated_time_by: 'עודכן ע"י {{author}} לפני {{age}}' label_updated_time: "עודכן לפני {{value}} " label_jump_to_a_project: קפוץ לפרויקט... label_file_plural: קבצים @@ -534,7 +718,61 @@ he: label_bulk_edit_selected_issues: ערוך את הנושאים המסומנים label_theme: ערכת נושא label_default: ברירת מחדל - + label_search_titles_only: חפש בכותרות בלבד + label_user_mail_option_all: "לכל אירוע בכל הפרויקטים שלי" + label_user_mail_option_selected: "לכל אירוע בפרויקטים שבחרתי בלבד..." + label_user_mail_option_none: "רק לנושאים שאני צופה או קשור אליהם" + label_user_mail_no_self_notified: "אני לא רוצה שיודיעו לי על שינויים שאני מבצע" + label_registration_activation_by_email: הפעל חשבון באמצעות דוא"ל + label_registration_manual_activation: הפעלת חשבון ידנית + label_registration_automatic_activation: הפעלת חשבון אוטומטית + label_display_per_page: "בכל דף: {{value}} תוצאות" + label_age: גיל + label_change_properties: שנה מאפיינים + label_general: כללי + label_more: עוד + label_scm: מערכת ניהול תצורה + label_plugins: תוספים + label_ldap_authentication: אימות LDAP + label_downloads_abbr: D/L + label_optional_description: תיאור רשות + label_add_another_file: הוסף עוד קובץ + label_preferences: העדפות + label_chronological_order: בסדר כרונולוגי + label_reverse_chronological_order: בסדר כרונולוגי הפוך + label_planning: תכנון + label_incoming_emails: דוא"ל נכנס + label_generate_key: צור מפתח + label_issue_watchers: צופים + label_example: דוגמא + label_display: תצוגה + label_sort: מיון + label_ascending: בסדר עולה + label_descending: בסדר יורד + label_date_from_to: 'מתאריך {{start}} ועד תאריך {{end}}' + label_wiki_content_added: הדף נוסף ל־wiki + label_wiki_content_updated: דף ה־wiki עודכן + label_group: קבוצה + label_group_plural: קבוצות + label_group_new: קבוצה חדשה + label_time_entry_plural: זמן שהושקע + label_version_sharing_none: לא משותף + label_version_sharing_descendants: עם פרויקטים בנים + label_version_sharing_hierarchy: עם היררכית הפרויקטים + label_version_sharing_tree: עם עץ הפרויקט + label_version_sharing_system: עם כל הפרויקטים + label_update_issue_done_ratios: עדכן אחוז התקדמות לנושא + label_copy_source: מקור + label_copy_target: יעד + label_copy_same_as_target: זהה ליעד + label_display_used_statuses_only: הצג רק את המצבים בשימוש לסיווג זה + label_api_access_key: מפתח גישה ל־API + label_missing_api_access_key: חסר מפתח גישה ל־API + label_api_access_key_created_on: 'מפתח גישה ל־API נוצר לפני {{value}}' + label_profile: פרופיל + label_subtask_plural: תתי־משימות + label_project_copy_notifications: שלח התראות דואר במהלך העתקת הפרויקט + button_login: התחבר button_submit: אשר button_save: שמור @@ -542,6 +780,7 @@ he: button_uncheck_all: בחר כלום button_delete: מחק button_create: צור + button_create_and_continue: צור ופתח חדש button_test: בדוק button_edit: ערוך button_add: הוסף @@ -554,12 +793,13 @@ he: button_list: רשימה button_view: צפה button_move: הזז + button_move_and_follow: העבר ועקוב button_back: הקודם button_cancel: בטל button_activate: הפעל button_sort: מיין button_log_time: זמן לוג - button_rollback: חזור לגירסא זו + button_rollback: חזור לגירסה זו button_watch: צפה button_unwatch: בטל צפיה button_reply: השב @@ -567,344 +807,109 @@ he: button_unarchive: הוצא מהארכיון button_reset: אפס button_rename: שנה שם - + button_change_password: שנה סיסמא + button_copy: העתק + button_copy_and_follow: העתק ועקוב + button_annotate: הוסף תיאור מסגרת + button_update: עדכן + button_configure: אפשרויות + button_quote: צטט + button_duplicate: שכפל + button_show: הצג + status_active: פעיל status_registered: רשום status_locked: נעול - + + version_status_open: פתוח + version_status_locked: נעול + version_status_closed: סגור + + field_active: פעיל + text_select_mail_notifications: בחר פעולת שבגללן ישלח דוא"ל. text_regexp_info: כגון. ^[A-Z0-9]+$ text_min_max_length_info: 0 משמעו ללא הגבלות - text_project_destroy_confirmation: האם אתה בטוח שברצונך למחוק את הפרויקט ואת כל המידע הקשור אליו ? - text_workflow_edit: בחר תפקיד ועוקב כדי לערות את זרימת העבודה - text_are_you_sure: האם אתה בטוח ? + text_project_destroy_confirmation: האם אתה בטוח שברצונך למחוק את הפרויקט ואת כל המידע הקשור אליו? + text_subprojects_destroy_warning: "תת־הפרויקט\ים: {{value}} ימחקו גם כן." + text_workflow_edit: בחר תפקיד וסיווג כדי לערוך את זרימת העבודה + text_are_you_sure: האם אתה בטוח? + text_journal_changed: "{{label}} השתנה מ{{old}} ל{{new}}" + text_journal_set_to: "{{label}} נקבע ל{{value}}" + text_journal_deleted: "{{label}} נמחק ({{old}})" + text_journal_added: "{{label}} {{value}} נוסף" text_tip_task_begin_day: מטלה המתחילה היום text_tip_task_end_day: מטלה המסתיימת היום text_tip_task_begin_end_day: מטלה המתחילה ומסתיימת היום text_project_identifier_info: 'אותיות לטיניות (a-z), מספרים ומקפים.
    ברגע שנשמר, לא ניתן לשנות את המזהה.' text_caracters_maximum: "מקסימום {{count}} תווים." + text_caracters_minimum: "חייב להיות לפחות באורך של {{count}} תווים." text_length_between: "אורך בין {{min}} ל {{max}} תווים." text_tracker_no_workflow: זרימת עבודה לא הוגדרה עבור סיווג זה text_unallowed_characters: תווים לא מורשים text_comma_separated: הכנסת ערכים מרובים מותרת (מופרדים בפסיקים). - text_issues_ref_in_commit_messages: קישור ותיקום נושאים בהודעות הפקדות + text_line_separated: ניתן להזין מספר ערכים (שורה אחת לכל ערך). + text_issues_ref_in_commit_messages: קישור ותיקום נושאים בהודעות הפקדה text_issue_added: "הנושא {{id}} דווח (by {{author}})." text_issue_updated: "הנושא {{id}} עודכן (by {{author}})." text_wiki_destroy_confirmation: האם אתה בטוח שברצונך למחוק את הWIKI הזה ואת כל תוכנו? text_issue_category_destroy_question: "כמה נושאים ({{count}}) מוצבים לקטגוריה הזו. מה ברצונך לעשות?" text_issue_category_destroy_assignments: הסר הצבת קטגוריה text_issue_category_reassign_to: הצב מחדש את הקטגוריה לנושאים - + text_user_mail_option: "בפרויקטים שלא בחרת, אתה רק תקבל התרעות על שאתה צופה או קשור אליהם (לדוגמא:נושאים שאתה היוצר שלהם או אחראי עליהם)." + text_no_configuration_data: "לא הוגדרה תצורה עבור תפקידים, סיווגים, מצבי נושא וזרימת עבודה.\nמומלץ מאד לטעון את תצורת ברירת המחדל. תוכל לשנותה מאוחר יותר." + text_load_default_configuration: טען את אפשרויות ברירת המחדל + text_status_changed_by_changeset: "הוחל בסדרת השינויים {{value}}." + text_issues_destroy_confirmation: 'האם אתה בטוח שברצונך למחוק את הנושא\ים?' + text_select_project_modules: 'בחר מודולים להחיל על פרויקט זה:' + text_default_administrator_account_changed: מנהל המערכת ברירת המחדל שונה + text_file_repository_writable: מאגר הקבצים ניתן לכתיבה + text_plugin_assets_writable: ספרית נכסי תוספים ניתנת לכתיבה + text_rmagick_available: RMagick זמין (רשות) + text_destroy_time_entries_question: "{{hours}} שעות דווחו על הנושאים שאתה עומד למחוק. מה ברצונך לעשות?" + text_destroy_time_entries: מחק שעות שדווחו + text_assign_time_entries_to_project: הצב שעות שדווחו לפרויקט הזה + text_reassign_time_entries: 'הצב מחדש שעות שדווחו לפרויקט הזה:' + text_user_wrote: "{{value}} כתב:" + text_enumeration_destroy_question: "{{count}} אוביקטים מוצבים לערך זה." + text_enumeration_category_reassign_to: 'הצב מחדש לערך הזה:' + text_email_delivery_not_configured: 'לא נקבעה תצורה לשליחת דואר, וההתראות כבויות.\nקבע את תצורת שרת ה־SMTP בקובץ config/email.yml והתחל את האפליקציה מחדש ע"מ לאפשר אותם.' + text_repository_usernames_mapping: "בחר או עדכן את משתמש Redmine הממופה לכל שם משתמש ביומן המאגר.\nמשתמשים בעלי שם או כתובת דואר זהה ב־Redmine ובמאגר ממופים באופן אוטומטי." + text_diff_truncated: '... השינויים עוברים את מספר השורות המירבי לתצוגה, ולכן הם קוצצו.' + text_custom_field_possible_values_info: שורה אחת לכל ערך + text_wiki_page_destroy_question: לדף זה יש {{descendants}} דפים בנים ותלויים. מה ברצונך לעשות? + text_wiki_page_nullify_children: השאר דפים בנים כדפים ראשיים + text_wiki_page_destroy_children: מחק את הדפים הבנים ואת כל התלויים בהם + text_wiki_page_reassign_children: הצב מחדש דפים בנים לדף האב הנוכחי + text_own_membership_delete_confirmation: |- + בכוונתך למחוק חלק או את כל ההרשאות שלך. לאחר מכן לא תוכל יותר לערוך פרויקט זה. + האם אתה בטוח שברצונך להמשיך? + text_zoom_in: התקרב + text_zoom_out: התרחק + default_role_manager: מנהל default_role_developer: מפתח default_role_reporter: מדווח - default_tracker_bug: באג - default_tracker_feature: פיצ'ר + default_tracker_bug: תקלה + default_tracker_feature: יכולת default_tracker_support: תמיכה default_issue_status_new: חדש - default_issue_status_in_progress: In Progress - default_issue_status_resolved: פתור + default_issue_status_in_progress: בעבודה + default_issue_status_resolved: נפתר default_issue_status_feedback: משוב default_issue_status_closed: סגור - default_issue_status_rejected: דחוי + default_issue_status_rejected: נדחה default_doc_category_user: תיעוד משתמש default_doc_category_tech: תיעוד טכני default_priority_low: נמוכה default_priority_normal: רגילה - default_priority_high: גהבוה + default_priority_high: גבוהה default_priority_urgent: דחופה default_priority_immediate: מידית default_activity_design: עיצוב default_activity_development: פיתוח - + enumeration_issue_priorities: עדיפות נושאים enumeration_doc_categories: קטגוריות מסמכים enumeration_activities: פעילויות (מעקב אחר זמנים) - label_search_titles_only: חפש בכותרות בלבד - label_nobody: אף אחד - button_change_password: שנה סיסמא - text_user_mail_option: "בפרויקטים שלא בחרת, אתה רק תקבל התרעות על שאתה צופה או קשור אליהם (לדוגמא:נושאים שאתה היוצר שלהם או מוצבים אליך)." - label_user_mail_option_selected: "לכל אירוע בפרויקטים שבחרתי בלבד..." - label_user_mail_option_all: "לכל אירוע בכל הפרויקטים שלי" - label_user_mail_option_none: "רק לנושאים שאני צופה או קשור אליהם" - setting_emails_footer: תחתית דוא"ל - label_float: צף - button_copy: העתק - mail_body_account_information_external: "אתה יכול להשתמש בחשבון {{value}} כדי להתחבר" - mail_body_account_information: פרטי החשבון שלך - setting_protocol: פרוטוקול - label_user_mail_no_self_notified: "אני לא רוצה שיודיעו לי על שינויים שאני מבצע" - setting_time_format: פורמט זמן - label_registration_activation_by_email: הפעל חשבון באמצעות דוא"ל - mail_subject_account_activation_request: "בקשת הפעלה לחשבון {{value}}" - mail_body_account_activation_request: "משתמש חדש ({{value}}) נרשם. החשבון שלו מחכה לאישור שלך:" - label_registration_automatic_activation: הפעלת חשבון אוטומטית - label_registration_manual_activation: הפעלת חשבון ידנית - notice_account_pending: "החשבון שלך נוצר ועתה מחכה לאישור מנהל המערכת." - field_time_zone: איזור זמן - text_caracters_minimum: "חייב להיות לפחות באורך של {{count}} תווים." - setting_bcc_recipients: מוסתר (bcc) - button_annotate: הוסף תיאור מסגרת - label_issues_by: "נושאים לפי {{value}}" - field_searchable: ניתן לחיפוש - label_display_per_page: "בכל דף: {{value}} תוצאות" - setting_per_page_options: אפשרויות אוביקטים לפי דף - label_age: גיל - notice_default_data_loaded: אפשרויות ברירת מחדל מופעלות. - text_load_default_configuration: טען את אפשרויות ברירת המחדל - text_no_configuration_data: "Roles, trackers, issue statuses and workflow have not been configured yet.\nIt is highly recommended to load the default configuration. יהיה באפשרותך לשנותו לאחר שיטען." - error_can_t_load_default_data: "אפשרויות ברירת המחדל לא הצליחו להיטען: {{value}}" - button_update: עדכן - label_change_properties: שנה מאפיינים - label_general: כללי - label_repository_plural: מאגרים - label_associated_revisions: שינויים קשורים - setting_user_format: פורמט הצגת משתמשים - text_status_changed_by_changeset: "הוחל בסדרת השינויים {{value}}." - label_more: עוד - text_issues_destroy_confirmation: 'האם את\ה בטוח שברצונך למחוק את הנושא\ים ?' - label_scm: SCM - text_select_project_modules: 'בחר מודולים להחיל על פקרויקט זה:' - label_issue_added: נושא נוסף - label_issue_updated: נושא עודכן - label_document_added: מוסמך נוסף - label_message_posted: הודעה הוספה - label_file_added: קובץ נוסף - label_news_added: חדשות הוספו - project_module_boards: לוחות - project_module_issue_tracking: מעקב נושאים - project_module_wiki: Wiki - project_module_files: קבצים - project_module_documents: מסמכים - project_module_repository: מאגר - project_module_news: חדשות - project_module_time_tracking: מעקב אחר זמנים - text_file_repository_writable: מאגר הקבצים ניתן לכתיבה - text_default_administrator_account_changed: מנהל המערכת ברירת המחדל שונה - text_rmagick_available: RMagick available (optional) - button_configure: אפשרויות - label_plugins: תוספים - label_ldap_authentication: אימות LDAP - label_downloads_abbr: D/L - label_this_month: החודש - label_last_n_days: "ב-{{count}} ימים אחרונים" - label_all_time: תמיד - label_this_year: השנה - label_date_range: טווח תאריכים - label_last_week: שבוע שעבר - label_yesterday: אתמול - label_last_month: חודש שעבר - label_add_another_file: הוסף עוד קובץ - label_optional_description: תיאור רשות - text_destroy_time_entries_question: "{{hours}} שעות דווחו על הנושים שאת\ה עומד\ת למחוק. מה ברצונך לעשות ?" - error_issue_not_found_in_project: 'הנושאים לא נמצאו או אינם שיכים לפרויקט' - text_assign_time_entries_to_project: הצב שעות שדווחו לפרויקט הזה - text_destroy_time_entries: מחק שעות שדווחו - text_reassign_time_entries: 'הצב מחדש שעות שדווחו לפרויקט הזה:' - setting_activity_days_default: ימים המוצגים על פעילות הפרויקט - label_chronological_order: בסדר כרונולוגי - field_comments_sorting: הצג הערות - label_reverse_chronological_order: בסדר כרונולוגי הפוך - label_preferences: העדפות - setting_display_subprojects_issues: הצג נושאים של תת פרויקטים כברירת מחדל - label_overall_activity: פעילות כוללת - setting_default_projects_public: פרויקטים חדשים הינם פומביים כברירת מחדל - error_scm_annotate: "הכניסה לא קיימת או שלא ניתן לתאר אותה." - label_planning: תכנון - text_subprojects_destroy_warning: "תת הפרויקט\ים: {{value}} ימחקו גם כן." - label_and_its_subprojects: "{{value}} וכל תת הפרויקטים שלו" - mail_body_reminder: "{{count}} נושאים שמיועדים אליך מיועדים להגשה בתוך {{days}} ימים:" - mail_subject_reminder: "{{count}} נושאים מיעדים להגשה בימים הקרובים" - text_user_wrote: "{{value}} כתב:" - label_duplicated_by: שוכפל ע"י - setting_enabled_scm: אפשר SCM - text_enumeration_category_reassign_to: 'הצב מחדש לערך הזה:' - text_enumeration_destroy_question: "{{count}} אוביקטים מוצבים לערך זה." - label_incoming_emails: דוא"ל נכנס - label_generate_key: יצר מפתח - setting_mail_handler_api_enabled: Enable WS for incoming emails - setting_mail_handler_api_key: מפתח API - text_email_delivery_not_configured: "Email delivery is not configured, and notifications are disabled.\nConfigure your SMTP server in config/email.yml and restart the application to enable them." - field_parent_title: דף אב - label_issue_watchers: צופים - setting_commit_logs_encoding: Commit messages encoding - button_quote: צטט - setting_sequential_project_identifiers: Generate sequential project identifiers - notice_unable_delete_version: לא ניתן למחוק גירסא - label_renamed: השם שונה - label_copied: הועתק - setting_plain_text_mail: טקסט פשוט בלבד (ללא HTML) - permission_view_files: צפה בקבצים - permission_edit_issues: ערוך נושאים - permission_edit_own_time_entries: ערוך את לוג הזמן של עצמך - permission_manage_public_queries: נהל שאילתות פומביות - permission_add_issues: הוסף נושא - permission_log_time: תעד זמן שבוזבז - permission_view_changesets: צפה בקבוצות שינויים - permission_view_time_entries: צפה בזמן שבוזבז - permission_manage_versions: נהל גירסאות - permission_manage_wiki: נהל wiki - permission_manage_categories: נהל קטגוריות נושאים - permission_protect_wiki_pages: הגן כל דפי wiki - permission_comment_news: הגב על החדשות - permission_delete_messages: מחק הודעות - permission_select_project_modules: בחר מודולי פרויקט - permission_manage_documents: נהל מסמכים - permission_edit_wiki_pages: ערוך דפי wiki - permission_add_issue_watchers: הוסף צופים - permission_view_gantt: צפה בגאנט - permission_move_issues: הזז נושאים - permission_manage_issue_relations: נהל יחס בין נושאים - permission_delete_wiki_pages: מחק דפי wiki - permission_manage_boards: נהל לוחות - permission_delete_wiki_pages_attachments: מחק דבוקות - permission_view_wiki_edits: צפה בהיסטורית wiki - permission_add_messages: הצב הודעות - permission_view_messages: צפה בהודעות - permission_manage_files: נהל קבצים - permission_edit_issue_notes: ערוך רשימות - permission_manage_news: נהל חדשות - permission_view_calendar: צפה בלוח השנה - permission_manage_members: נהל חברים - permission_edit_messages: ערוך הודעות - permission_delete_issues: מחק נושאים - permission_view_issue_watchers: צפה ברשימה צופים - permission_manage_repository: נהל מאגר - permission_commit_access: Commit access - permission_browse_repository: סייר במאגר - permission_view_documents: צפה במסמכים - permission_edit_project: ערוך פרויקט - permission_add_issue_notes: Add notes - permission_save_queries: שמור שאילתות - permission_view_wiki_pages: צפה ב-wiki - permission_rename_wiki_pages: שנה שם של דפי wiki - permission_edit_time_entries: ערוך רישום זמנים - permission_edit_own_issue_notes: Edit own notes - setting_gravatar_enabled: Use Gravatar user icons - label_example: דוגמא - text_repository_usernames_mapping: "Select ou update the Redmine user mapped to each username found in the repository log.\nUsers with the same Redmine and repository username or email are automatically mapped." - permission_edit_own_messages: ערוך הודעות של עצמך - permission_delete_own_messages: מחק הודעות של עצמך - label_user_activity: "הפעילות של {{value}}" - label_updated_time_by: "עודכן ע'י {{author}} לפני {{age}}" - setting_diff_max_lines_displayed: Max number of diff lines displayed - text_plugin_assets_writable: Plugin assets directory writable - text_diff_truncated: '... This diff was truncated because it exceeds the maximum size that can be displayed.' - warning_attachments_not_saved: "{{count}} file(s) could not be saved." - button_create_and_continue: צור ופתח חדש - text_custom_field_possible_values_info: 'One line for each value' - label_display: תצוגה - field_editable: ניתן לעריכה - setting_repository_log_display_limit: Maximum number of revisions displayed on file log - setting_file_max_size_displayed: Max size of text files displayed inline - field_watcher: צופה - setting_openid: Allow OpenID login and registration - field_identity_url: OpenID URL - label_login_with_open_id_option: or login with OpenID - field_content: Content - label_descending: Descending - label_sort: Sort - label_ascending: Ascending - label_date_from_to: מתאריך {{start}} ועד תאריך {{end}} - label_greater_or_equal: ">=" - label_less_or_equal: <= - text_wiki_page_destroy_question: This page has {{descendants}} child page(s) and descendant(s). What do you want to do? - text_wiki_page_reassign_children: Reassign child pages to this parent page - text_wiki_page_nullify_children: Keep child pages as root pages - text_wiki_page_destroy_children: Delete child pages and all their descendants - setting_password_min_length: אורך סיסמא מינימאלי - field_group_by: Group results by - mail_subject_wiki_content_updated: "'{{page}}' wiki page has been updated" - label_wiki_content_added: Wiki page added - mail_subject_wiki_content_added: "'{{page}}' wiki page has been added" - mail_body_wiki_content_added: The '{{page}}' wiki page has been added by {{author}}. - label_wiki_content_updated: Wiki page updated - mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. - permission_add_project: Create project - setting_new_project_user_role_id: Role given to a non-admin user who creates a project - label_view_all_revisions: View all revisions - label_tag: Tag - label_branch: Branch - error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. - error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). - text_journal_changed: "{{label}} השתנה מ{{old}} ל{{new}}" - text_journal_set_to: "{{label}} נקבע ל{{value}}" - text_journal_deleted: "{{label}} נמחק ({{old}})" - label_group_plural: קבוצות - label_group: קבוצה - label_group_new: קבוצה חדשה - label_time_entry_plural: זמן שהושקע - text_journal_added: "{{label}} {{value}} נוסף" - field_active: Active - enumeration_system_activity: System Activity - permission_delete_issue_watchers: Delete watchers - version_status_closed: סגור - version_status_locked: נעול - version_status_open: פתוח - error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened - label_user_anonymous: Anonymous - button_move_and_follow: Move and follow - setting_default_projects_modules: Default enabled modules for new projects - setting_gravatar_default: Default Gravatar image - field_sharing: Sharing - label_version_sharing_hierarchy: With project hierarchy - label_version_sharing_system: With all projects - label_version_sharing_descendants: With subprojects - label_version_sharing_tree: With project tree - label_version_sharing_none: Not shared - error_can_not_archive_project: This project can not be archived - button_duplicate: שכפל - button_copy_and_follow: Copy and follow - label_copy_source: Source - setting_issue_done_ratio: Calculate the issue done ratio with - setting_issue_done_ratio_issue_status: Use the issue status - error_issue_done_ratios_not_updated: Issue done ratios not updated. - error_workflow_copy_target: Please select target tracker(s) and role(s) - setting_issue_done_ratio_issue_field: Use the issue field - label_copy_same_as_target: Same as target - label_copy_target: Target - notice_issue_done_ratios_updated: Issue done ratios updated. - error_workflow_copy_source: Please select a source tracker or role - label_update_issue_done_ratios: Update issue done ratios - setting_start_of_week: התחל יומנים לפי - permission_view_issues: View Issues - label_display_used_statuses_only: Only display statuses that are used by this tracker - label_revision_id: Revision {{value}} - label_api_access_key: API access key - label_api_access_key_created_on: API access key created {{value}} ago - label_feeds_access_key: RSS access key - notice_api_access_key_reseted: Your API access key was reset. - setting_rest_api_enabled: Enable REST web service - label_missing_api_access_key: Missing an API access key - label_missing_feeds_access_key: Missing a RSS access key - button_show: Show - text_line_separated: Multiple values allowed (one line for each value). - setting_mail_handler_body_delimiters: Truncate emails after one of these lines - permission_add_subprojects: Create subprojects - label_subproject_new: תת-פרויקט חדש - text_own_membership_delete_confirmation: |- - You are about to remove some or all of your permissions and may no longer be able to edit this project after that. - Are you sure you want to continue? - label_close_versions: Close completed versions - label_board_sticky: Sticky - label_board_locked: Locked - permission_export_wiki_pages: Export wiki pages - setting_cache_formatted_text: Cache formatted text - permission_manage_project_activities: Manage project activities - error_can_not_delete_custom_field: Unable to delete custom field - permission_manage_subtasks: Manage subtasks - label_profile: Profile - error_unable_to_connect: Unable to connect ({{value}}) - error_can_not_remove_role: This role is in use and can not be deleted. - field_parent_issue: Parent task - error_unable_delete_issue_status: Unable to delete issue status - label_subtask_plural: Subtasks - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. - label_project_copy_notifications: Send email notifications during the project copy - field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + enumeration_system_activity: פעילות מערכת diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 6839fb7b..a62d0732 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -914,20 +914,20 @@ permission_export_wiki_pages: Wiki oldalak exportálása permission_manage_project_activities: Projekt tevékenységek kezelése label_board_locked: Zárolt - error_can_not_delete_custom_field: Unable to delete custom field - permission_manage_subtasks: Manage subtasks - label_profile: Profile - error_unable_to_connect: Unable to connect ({{value}}) - error_can_not_remove_role: This role is in use and can not be deleted. - field_parent_issue: Parent task - error_unable_delete_issue_status: Unable to delete issue status - label_subtask_plural: Subtasks - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. - label_project_copy_notifications: Send email notifications during the project copy - field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + error_can_not_delete_custom_field: Nem lehet törölni az egyéni mezőt + permission_manage_subtasks: Alfeladatok kezelése + label_profile: Profil + error_unable_to_connect: Nem lehet csatlakozni ({{value}}) + error_can_not_remove_role: Ez a szerepkör használatban van és ezért nem törölhető- + field_parent_issue: Szülő feladat + error_unable_delete_issue_status: Nem lehet törölni a feladat állapotát + label_subtask_plural: Alfeladatok + error_can_not_delete_tracker: Ebbe a kategóriába feladatok tartoznak és ezért nem törölhető. + label_project_copy_notifications: Küldjön e-mail értesítéseket projektmásolás közben. + field_principal: Felelős + label_my_page_block: Saját kezdőlap-blokk + notice_failed_to_save_members: "Nem sikerült menteni a tago(ka)t: {{errors}}." + text_zoom_out: Kicsinyít + text_zoom_in: Nagyít + notice_unable_delete_time_entry: Az időrögzítés nem törölhető + label_overall_spent_time: Összes rászánt idő From 677fee310a17bcef7404f936c8fad962c5b65c29 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 29 Jul 2010 15:03:11 +0000 Subject: [PATCH 043/777] Merged r3894 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3896 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/application_helper.rb | 4 ++++ app/views/layouts/base.rhtml | 1 + 2 files changed, 5 insertions(+) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 054bac8a..4d698a23 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -783,6 +783,10 @@ module ApplicationHelper end end + def favicon + "" + end + private def wiki_helper diff --git a/app/views/layouts/base.rhtml b/app/views/layouts/base.rhtml index 1873191c..9521457d 100644 --- a/app/views/layouts/base.rhtml +++ b/app/views/layouts/base.rhtml @@ -5,6 +5,7 @@ <%=h html_title %> +<%= favicon %> <%= stylesheet_link_tag 'application', :media => 'all' %> <%= javascript_include_tag :defaults %> <%= heads_for_wiki_formatter %> From 59f98693ae4739f610c232f3e8a0f0bd8adc5008 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 30 Jul 2010 19:20:46 +0000 Subject: [PATCH 044/777] Merged r3897 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3900 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- config/locales/de.yml | 79 +++++++++++++++++++++++-------------------- config/locales/zh.yml | 30 ++++++++-------- 2 files changed, 57 insertions(+), 52 deletions(-) diff --git a/config/locales/de.yml b/config/locales/de.yml index 8e3c4455..05d5d963 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -99,13 +99,13 @@ de: gb: "GB" tb: "TB" - + # Used in array.to_sentence. support: array: sentence_connector: "und" skip_last_comma: true - + activerecord: errors: template: @@ -139,7 +139,7 @@ de: cant_link_an_issue_with_a_descendant: "Ein Ticket kann nicht mit einer ihrer Unteraufgaben verlinkt werden" actionview_instancetag_blank_option: Bitte auswählen - + general_text_No: 'Nein' general_text_Yes: 'Ja' general_text_no: 'nein' @@ -172,6 +172,7 @@ de: notice_feeds_access_key_reseted: Ihr Atom-Zugriffsschlüssel wurde zurückgesetzt. notice_api_access_key_reseted: Ihr API-Zugriffsschlüssel wurde zurückgesetzt. notice_failed_to_save_issues: "{{count}} von {{total}} ausgewählten Tickets konnte(n) nicht gespeichert werden: {{ids}}." + notice_failed_to_save_members: "Benutzer konnte nicht gespeichert werden: {{errors}}." notice_no_issue_selected: "Kein Ticket ausgewählt! Bitte wählen Sie die Tickets, die Sie bearbeiten möchten." notice_account_pending: "Ihr Konto wurde erstellt und wartet jetzt auf die Genehmigung des Administrators." notice_default_data_loaded: Die Standard-Konfiguration wurde erfolgreich geladen. @@ -186,17 +187,18 @@ de: error_issue_not_found_in_project: 'Das Ticket wurde nicht gefunden oder gehört nicht zu diesem Projekt.' error_no_tracker_in_project: Diesem Projekt ist kein Tracker zugeordnet. Bitte überprüfen Sie die Projekteinstellungen. error_no_default_issue_status: Es ist kein Status als Standard definiert. Bitte überprüfen Sie Ihre Konfiguration (unter "Administration -> Ticket-Status"). + error_can_not_delete_custom_field: Kann das benutzerdefinierte Feld nicht löschen. + error_can_not_delete_tracker: Dieser Tracker enthält Tickets und kann nicht gelöscht werden. + error_can_not_remove_role: Diese Rolle wird verwendet und kann nicht gelöscht werden. error_can_not_reopen_issue_on_closed_version: Das Ticket ist einer abgeschlossenen Version zugeordnet und kann daher nicht wieder geöffnet werden. error_can_not_archive_project: Dieses Projekt kann nicht archiviert werden. error_issue_done_ratios_not_updated: Der Ticket-Fortschritt wurde nicht aktualisiert. error_workflow_copy_source: Bitte wählen Sie einen Quell-Tracker und eine Quell-Rolle. error_workflow_copy_target: Bitte wählen Sie die Ziel-Tracker und -Rollen. error_unable_delete_issue_status: "Der Ticket-Status konnte nicht gelöscht werden." - - warning_attachments_not_saved: - one: "1 Datei konnte nicht gespeichert werden." - other: "{{count}} Dateien konnten nicht gespeichert werden." - + error_unable_to_connect: Fehler beim Verbinden ({{value}}) + warning_attachments_not_saved: "{{count}} Datei(en) konnten nicht gespeichert werden." + mail_subject_lost_password: "Ihr {{value}} Kennwort" mail_body_lost_password: 'Benutzen Sie den folgenden Link, um Ihr Kennwort zu ändern:' mail_subject_register: "{{value}} Kontoaktivierung" @@ -211,7 +213,6 @@ de: mail_body_wiki_content_added: "Die Wiki-Seite '{{page}}' wurde von {{author}} hinzugefügt." mail_subject_wiki_content_updated: "Wiki-Seite '{{page}}' erfolgreich aktualisiert" mail_body_wiki_content_updated: "Die Wiki-Seite '{{page}}' wurde von {{author}} aktualisiert." - gui_validation_error: 1 Fehler gui_validation_error_plural: "{{count}} Fehler" @@ -250,6 +251,7 @@ de: field_priority: Priorität field_fixed_version: Zielversion field_user: Benutzer + field_principal: Principal field_role: Rolle field_homepage: Projekt-Homepage field_is_public: Öffentlich @@ -305,6 +307,7 @@ de: field_content: Inhalt field_group_by: Gruppiere Ergebnisse nach field_sharing: Gemeinsame Verwendung + field_parent_issue: Übergeordnete Aufgabe setting_app_title: Applikations-Titel setting_app_subtitle: Applikations-Untertitel @@ -414,6 +417,7 @@ de: permission_delete_messages: Forenbeiträge löschen permission_delete_own_messages: Eigene Forenbeiträge löschen permission_export_wiki_pages: Wiki-Seiten exportieren + permission_manage_subtasks: Unteraufgaben verwalten project_module_issue_tracking: Ticket-Verfolgung project_module_time_tracking: Zeiterfassung @@ -423,7 +427,7 @@ de: project_module_wiki: Wiki project_module_repository: Projektarchiv project_module_boards: Foren - + label_user: Benutzer label_user_plural: Benutzer label_user_new: Neuer Benutzer @@ -480,6 +484,7 @@ de: label_my_page: Meine Seite label_my_account: Mein Konto label_my_projects: Meine Projekte + label_my_page_block: My page block label_administration: Administration label_login: Anmelden label_logout: Abmelden @@ -543,9 +548,18 @@ de: label_open_issues_plural: offen label_closed_issues: geschlossen label_closed_issues_plural: geschlossen - label_x_open_issues_abbr_on_total: "{{count}} offen / {{total}}" - label_x_open_issues_abbr: "{{count}} offen" - label_x_closed_issues_abbr: "{{count}} geschlossen" + label_x_open_issues_abbr_on_total: + zero: 0 offen / {{total}} + one: 1 offen / {{total}} + other: "{{count}} offen / {{total}}" + label_x_open_issues_abbr: + zero: 0 offen + one: 1 offen + other: "{{count}} offen" + label_x_closed_issues_abbr: + zero: 0 geschlossen + one: 1 geschlossen + other: "{{count}} geschlossen" label_total: Gesamtzahl label_permissions: Berechtigungen label_current_status: Gegenwärtiger Status @@ -769,7 +783,10 @@ de: label_api_access_key: API-Zugriffsschlüssel label_missing_api_access_key: Der API-Zugriffsschlüssel fehlt. label_api_access_key_created_on: Der API-Zugriffsschlüssel wurde vor {{value}} erstellt - + label_profile: Profil + label_subtask_plural: Unteraufgaben + label_project_copy_notifications: Sende Mailbenachrichtigungen beim Kopieren des Projekts. + button_login: Anmelden button_submit: OK button_save: Speichern @@ -817,13 +834,13 @@ de: status_active: aktiv status_registered: angemeldet status_locked: gesperrt - - version_status_closed: abgeschlossen - version_status_locked: gesperrt + version_status_open: offen + version_status_locked: gesperrt + version_status_closed: abgeschlossen - field_active: Aktiv - + field_active: Activ + text_select_mail_notifications: Bitte wählen Sie die Aktionen aus, für die eine Mailbenachrichtigung gesendet werden soll. text_regexp_info: z. B. ^[A-Z0-9]+$ text_min_max_length_info: 0 heißt keine Beschränkung @@ -878,10 +895,10 @@ de: text_wiki_page_nullify_children: Verschiebe die Unterseiten auf die oberste Ebene text_wiki_page_destroy_children: Lösche alle Unterseiten text_wiki_page_reassign_children: Ordne die Unterseiten dieser Seite zu - text_own_membership_delete_confirmation: |- - Sie sind dabei, einige oder alle Ihre Berechtigungen zu entfernen. Es ist möglich, dass Sie danach das Projekt nicht mehr ansehen oder bearbeiten dürfen. - Sind Sie sicher, dass Sie dies tun möchten? - + text_own_membership_delete_confirmation: "Sie sind dabei, einige oder alle Ihre Berechtigungen zu entfernen. Es ist möglich, dass Sie danach das Projekt nicht mehr ansehen oder bearbeiten dürfen.\nSind Sie sicher, dass Sie dies tun möchten?" + text_zoom_in: Zoom in + text_zoom_out: Zoom out + default_role_manager: Manager default_role_developer: Entwickler default_role_reporter: Reporter @@ -903,21 +920,9 @@ de: default_priority_immediate: Sofort default_activity_design: Design default_activity_development: Entwicklung + enumeration_issue_priorities: Ticket-Prioritäten enumeration_doc_categories: Dokumentenkategorien enumeration_activities: Aktivitäten (Zeiterfassung) enumeration_system_activity: System-Aktivität - label_profile: Profil - permission_manage_subtasks: Unteraufgaben verwalten - field_parent_issue: Übergeordnete Aufgabe - label_subtask_plural: Unteraufgaben - label_project_copy_notifications: Sende Mailbenachrichtigungen beim Kopieren des Projekts. - error_can_not_delete_custom_field: Kann das benutzerdefinierte Feld nicht löschen. - error_unable_to_connect: Fehler beim Verbinden ({{value}}) - error_can_not_remove_role: Diese Rolle wird verwendet und kann nicht gelöscht werden. - error_can_not_delete_tracker: Dieser Tracker enthält Tickets und kann nicht gelöscht werden. - field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in + diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 6fdb33f5..3f05306b 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -498,9 +498,9 @@ zh: label_date: 日期 label_integer: 整数 label_float: 浮点数 - label_boolean: 布尔量 - label_string: 文字 - label_text: 长段文字 + label_boolean: 布尔值 + label_string: 字符串 + label_text: 文本 label_attribute: 属性 label_attribute_plural: 属性 label_download: "{{count}} 次下载" @@ -910,19 +910,19 @@ zh: setting_cache_formatted_text: 缓存已格式化文字 permission_manage_project_activities: 管理项目活动 error_unable_delete_issue_status: 无法删除问题状态 - label_profile: 配置概况 - permission_manage_subtasks: Manage subtasks - field_parent_issue: Parent task - label_subtask_plural: Subtasks - label_project_copy_notifications: Send email notifications during the project copy + label_profile: 简介 + permission_manage_subtasks: 管理子任务 + field_parent_issue: 父任务 + label_subtask_plural: 子任务 + label_project_copy_notifications: 复制项目时发送邮件通知 error_can_not_delete_custom_field: 不能删除自定义属性 error_unable_to_connect: 不能连接到 ({{value}}) error_can_not_remove_role: 该角色正在使用中, 不能删除. error_can_not_delete_tracker: 该跟踪标签包含问题, 不能删除. - field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + field_principal: 用户/用户组 + label_my_page_block: 我的工作台模块 + notice_failed_to_save_members: "成员保存失败:{{errors}}。" + text_zoom_out: 缩小 + text_zoom_in: 放大 + notice_unable_delete_time_entry: 无法删除工时记录。 + label_overall_spent_time: 所有项目耗用工时 From df120e43cd5872045852e6ec57894173b01a4d28 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 30 Jul 2010 19:20:52 +0000 Subject: [PATCH 045/777] Merged r3898 from trunk git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3901 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/issues/_changesets.rhtml | 4 +- app/views/issues/_history.rhtml | 2 +- public/stylesheets/application.css | 4 ++ public/themes/rtl/stylesheets/application.css | 50 +++++++++++++++++++ .../themes/rtl/stylesheets/context_menu.css | 6 +++ 5 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 public/themes/rtl/stylesheets/application.css create mode 100644 public/themes/rtl/stylesheets/context_menu.css diff --git a/app/views/issues/_changesets.rhtml b/app/views/issues/_changesets.rhtml index 0b1f10b7..52cd60ff 100644 --- a/app/views/issues/_changesets.rhtml +++ b/app/views/issues/_changesets.rhtml @@ -3,6 +3,8 @@

    <%= link_to("#{l(:label_revision)} #{changeset.revision}", :controller => 'repositories', :action => 'revision', :id => changeset.project, :rev => changeset.revision) %>
    <%= authoring(changeset.committed_on, changeset.author) %>

    - <%= textilizable(changeset, :comments) %> +
    + <%= textilizable(changeset, :comments) %> +
    <% end %> diff --git a/app/views/issues/_history.rhtml b/app/views/issues/_history.rhtml index 7459eb35..a95cbf81 100644 --- a/app/views/issues/_history.rhtml +++ b/app/views/issues/_history.rhtml @@ -1,7 +1,7 @@ <% reply_links = authorize_for('issues', 'edit') -%> <% for journal in journals %>
    -

    <%= link_to "##{journal.indice}", :anchor => "note-#{journal.indice}" %>
    +

    <%= avatar(journal.user, :size => "24") %> <%= content_tag('a', '', :name => "note-#{journal.indice}")%> <%= authoring journal.created_on, journal.user, :label => :label_updated_time_by %>

    diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index b3dbfd7f..59a2c3ed 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -903,6 +903,10 @@ td.username img.gravatar { clear: left; } +.journal-link { + float: right; +} + h2 img { vertical-align:middle; } .hascontextmenu { cursor: context-menu; } diff --git a/public/themes/rtl/stylesheets/application.css b/public/themes/rtl/stylesheets/application.css new file mode 100644 index 00000000..74f20b43 --- /dev/null +++ b/public/themes/rtl/stylesheets/application.css @@ -0,0 +1,50 @@ +@import url(../../alternate/stylesheets/application.css); + +body, #wrapper { direction: rtl;} + +#quick-search { float: left; } +#main-menu { margin-left: -500px; left: auto; right: 6px; margin-right: 0px;} +#main-menu li { float: right; } +#top-menu ul { float: right; } +#account { float: left; } +#top-menu #loggedas { float: left; } +#top-menu li { float: right; } +.tabular label.floating +{ + margin-right: 0; + margin-left: auto; + text-align: right; +} +.tabular label +{ + float: right; + margin-left: auto; +} +.tabular p { clear: right; } +.tabular label.block { text-align: right; } + +.icon { background-position: 100% 40%; padding-right: 20px; padding-left: 0px; } +div#activity dt, #search-results dt { background-position: 100% 50%; padding-right: 20px; padding-left: 0px; } +#content .tabs ul li { float: right; } +#content .tabs ul { padding-left: auto; padding-right: 1em; } +table.progress { float: right; } +.contextual { float: left; } +.icon22 { background-position: 100% 40%; padding-right: 26px; padding-left: auto; } +h3, .wiki h2 { padding: 10px 2px 1px 0; } +.tooltip span.tip { text-align: right; } +tr.issue td.subject { text-align: right; } +tr.time-entry td.subject, tr.time-entry td.comments { text-align: right; } +#sidebar { float: left; } +#main.nosidebar #content { border-width: 1px; border-style: solid; border-color: #D7D7D7 #BBBBBB #BBBBBB #D7D7D7;} +.tabular.settings label { margin-left: auto; } +.splitcontentleft { float: right; } +.splitcontentright { float: left; } +p.progress-info { clear: right; } +table.list td.buttons a { padding-right: 20px; } +.filecontent { direction: ltr; } +.entries { direction: ltr; } +.changeset-changes { direction: ltr; padding-left: 2em } +.changesets { direction: ltr; } +div#issue-changesets { float: left; margin-right: 1em; margin-left: 0 } +#activity dt, .journal { clear: right; } +.journal-link { float: left; } diff --git a/public/themes/rtl/stylesheets/context_menu.css b/public/themes/rtl/stylesheets/context_menu.css new file mode 100644 index 00000000..c400d3e8 --- /dev/null +++ b/public/themes/rtl/stylesheets/context_menu.css @@ -0,0 +1,6 @@ +@import url(../../../stylesheets/context_menu.css); + +#context-menu li.folder ul { left:auto; right:168px; } +#context-menu li.folder>ul { left:auto; right:148px; } + +#context-menu li a.submenu { background:url("../../../images/bullet_arrow_left.png") left no-repeat; } From 9af4cb5c38af6e409ed2e56170fe15dbf2c24f18 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 30 Jul 2010 19:20:56 +0000 Subject: [PATCH 046/777] Merged r3899 from trunk git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3902 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/application_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 4d698a23..e4075896 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -784,7 +784,7 @@ module ApplicationHelper end def favicon - "" + "" end private From cea1a987abcba4878fd0f041d3d233877d85f2fc Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 4 Aug 2010 18:56:33 +0200 Subject: [PATCH 047/777] fix display of attachments with acts_as_journalized --- app/models/attachment.rb | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 5005054b..669dc55c 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -28,23 +28,23 @@ class Attachment < ActiveRecord::Base acts_as_journalized :event_title => :filename, :event_url => (Proc.new do |o| { :controller => 'attachments', :action => 'download', - :id => o.id, :filename => o.filename } + :id => o.versioned_id, :filename => o.filename } end), :activity_type => 'files', - :activity_permission => :view_files, - :activity_find_options => {:select => "#{Attachment.table_name}.*", - :joins => "LEFT JOIN #{Version.table_name} ON #{Version.table_name}.id = #{Attachment.table_name}.container_id " + - " AND #{Attachment.table_name}.container_type = 'Version' " + - "LEFT JOIN #{Project.table_name} ON #{Project.table_name}.id = #{Version.table_name}.project_id " + - " OR ( #{Attachment.table_name}.container_id = #{Project.table_name}.id " + - " AND #{Attachment.table_name}.container_type = 'Project' ) " } + :activity_permission => :view_files - acts_as_activity :type => 'documents', - :permission => :view_documents, - :find_options => {:select => "#{Attachment.table_name}.*", - :joins => "LEFT JOIN #{Document.table_name} ON (#{Document.table_name}.id = #{Attachment.table_name}.container_id" + - " AND #{Attachment.table_name}.container_type='Document') " + - "LEFT JOIN #{Project.table_name} ON (#{Project.table_name}.id = #{Document.table_name}.project_id)" } + acts_as_activity :type => 'documents', :permission => :view_documents + + def activity_type + case container_type + when "Document" + "documents" + when "Version" + "files" + else + super + end + end cattr_accessor :storage_path @@storage_path = "#{RAILS_ROOT}/files" From 47ecf151dd8040a8658d660e064e04b866ceb097 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 4 Aug 2010 18:58:31 +0200 Subject: [PATCH 048/777] completely remove acts_as_versioned as it's functionality is contained in acts_as_journalized This makes the wiki just use the versioning provided by acts_as_journalized --- app/controllers/wiki_controller.rb | 8 +- app/models/wiki_content.rb | 88 +-- app/views/wiki/edit.rhtml | 2 +- app/views/wiki/history.rhtml | 6 +- lib/redmine.rb | 2 +- lib/redmine/wiki_formatting/macros.rb | 2 +- vendor/plugins/acts_as_versioned/CHANGELOG | 74 --- vendor/plugins/acts_as_versioned/MIT-LICENSE | 20 - vendor/plugins/acts_as_versioned/README | 28 - .../acts_as_versioned/RUNNING_UNIT_TESTS | 41 -- vendor/plugins/acts_as_versioned/Rakefile | 182 ------ vendor/plugins/acts_as_versioned/init.rb | 1 - .../lib/acts_as_versioned.rb | 564 ------------------ .../acts_as_versioned/test/abstract_unit.rb | 41 -- .../acts_as_versioned/test/database.yml | 18 - .../test/fixtures/authors.yml | 6 - .../test/fixtures/landmark.rb | 3 - .../test/fixtures/landmark_versions.yml | 7 - .../test/fixtures/landmarks.yml | 6 - .../test/fixtures/locked_pages.yml | 10 - .../test/fixtures/locked_pages_revisions.yml | 27 - .../migrations/1_add_versioned_tables.rb | 13 - .../acts_as_versioned/test/fixtures/page.rb | 43 -- .../test/fixtures/page_versions.yml | 16 - .../acts_as_versioned/test/fixtures/pages.yml | 7 - .../acts_as_versioned/test/fixtures/widget.rb | 6 - .../acts_as_versioned/test/migration_test.rb | 46 -- .../plugins/acts_as_versioned/test/schema.rb | 68 --- .../acts_as_versioned/test/versioned_test.rb | 347 ----------- 29 files changed, 54 insertions(+), 1628 deletions(-) delete mode 100644 vendor/plugins/acts_as_versioned/CHANGELOG delete mode 100644 vendor/plugins/acts_as_versioned/MIT-LICENSE delete mode 100644 vendor/plugins/acts_as_versioned/README delete mode 100644 vendor/plugins/acts_as_versioned/RUNNING_UNIT_TESTS delete mode 100644 vendor/plugins/acts_as_versioned/Rakefile delete mode 100644 vendor/plugins/acts_as_versioned/init.rb delete mode 100644 vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb delete mode 100644 vendor/plugins/acts_as_versioned/test/abstract_unit.rb delete mode 100644 vendor/plugins/acts_as_versioned/test/database.yml delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/authors.yml delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/landmark.rb delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/landmark_versions.yml delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/landmarks.yml delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/locked_pages.yml delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/locked_pages_revisions.yml delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/migrations/1_add_versioned_tables.rb delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/page.rb delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/page_versions.yml delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/pages.yml delete mode 100644 vendor/plugins/acts_as_versioned/test/fixtures/widget.rb delete mode 100644 vendor/plugins/acts_as_versioned/test/migration_test.rb delete mode 100644 vendor/plugins/acts_as_versioned/test/schema.rb delete mode 100644 vendor/plugins/acts_as_versioned/test/versioned_test.rb diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index 55194e04..15967a91 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -73,7 +73,7 @@ class WikiController < ApplicationController @content.comments = nil if request.get? # To prevent StaleObjectError exception when reverting to a previous version - @content.version = @page.content.version + @content.lock_version = @page.content.lock_version else if !@page.new_record? && @content.text == params[:content][:text] attachments = Attachment.attach_files(@page, params[:attachments]) @@ -120,9 +120,9 @@ class WikiController < ApplicationController def history @version_count = @page.content.versions.count @version_pages = Paginator.new self, @version_count, per_page_option, params['p'] - # don't load text - @versions = @page.content.versions.find :all, - :select => "id, author_id, comments, updated_on, version", + # don't load text + @versions = @page.content.versions.find :all, + :select => "id, user_id, notes, updated_at, version", :order => 'version DESC', :limit => @version_pages.items_per_page + 1, :offset => @version_pages.current.offset diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb index aa0f07fb..aeeec1e6 100644 --- a/app/models/wiki_content.rb +++ b/app/models/wiki_content.rb @@ -18,84 +18,84 @@ require 'zlib' class WikiContent < ActiveRecord::Base - set_locking_column :version belongs_to :page, :class_name => 'WikiPage', :foreign_key => 'page_id' belongs_to :author, :class_name => 'User', :foreign_key => 'author_id' validates_presence_of :text validates_length_of :comments, :maximum => 255, :allow_nil => true - - acts_as_versioned - + + acts_as_journalized :event_type => 'wiki-page', + :event_title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, + :event_url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}, + :activity_type => 'wiki_edits', + :activity_permission => :view_wiki_edits + + def activity_type + 'wiki_edits' + end + def visible?(user=User.current) page.visible?(user) end - + def project page.project end - + def attachments page.nil? ? [] : page.attachments end - + # Returns the mail adresses of users that should be notified def recipients notified = project.notified_users notified.reject! {|user| !visible?(user)} notified.collect(&:mail) end - - class Version - belongs_to :page, :class_name => '::WikiPage', :foreign_key => 'page_id' - belongs_to :author, :class_name => '::User', :foreign_key => 'author_id' - attr_protected :data - acts_as_journalized :event_type => 'wiki-page', - :event_title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, - :event_url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}, - :activity_type => 'wiki_edits', - :activity_timestamp => "#{WikiContent.versioned_table_name}.updated_on", - :activity_author_key => "#{WikiContent.versioned_table_name}.author_id", - :activity_permission => :view_wiki_edits, - :activity_find_options => { :include => [:page => [:wiki => :project]] } + # FIXME: This is for backwards compatibility only. Remove once we decide it is not needed anymore + WikiContentJournal.class_eval do + attr_protected :data + after_save :compress_version_text + + # Wiki Content might be large and the data should possibly be compressed + def compress_version_text + self.text = changes["text"].last if changes["text"] + end def text=(plain) case Setting.wiki_compression - when 'gzip' - begin - self.data = Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION) - self.compression = 'gzip' - rescue - self.data = plain - self.compression = '' - end + when "gzip" + begin + text_hash :text => Zlib::Deflate.deflate(plain, Zlib::BEST_COMPRESSION), :compression => Setting.wiki_compression + rescue + text_hash :text => plain, :compression => '' + end else - self.data = plain - self.compression = '' + text_hash :text => plain, :compression => '' end plain end - + + def text_hash(hash) + changes.delete("text") + changes["data"] = hash[:text] + changes["compression"] = hash[:compression] + update_attribute(:changes, changes.to_yaml) + end + def text - @text ||= case compression + @text ||= case changes[:compression] when 'gzip' Zlib::Inflate.inflate(data) else # uncompressed data - data - end + changes["data"] + end end - - def project - page.project - end - + # Returns the previous version or nil def previous - @previous ||= WikiContent::Version.find(:first, - :order => 'version DESC', - :include => :author, - :conditions => ["wiki_content_id = ? AND version < ?", wiki_content_id, version]) + @previous ||= versioned.journals.at(version - 1) end end -end +end \ No newline at end of file diff --git a/app/views/wiki/edit.rhtml b/app/views/wiki/edit.rhtml index 9b125e99..f2bc4919 100644 --- a/app/views/wiki/edit.rhtml +++ b/app/views/wiki/edit.rhtml @@ -1,7 +1,7 @@

    <%=h @page.pretty_title %>

    <% form_for :content, @content, :url => {:action => 'edit', :page => @page.title}, :html => {:multipart => true, :id => 'wiki_form'} do |f| %> -<%= f.hidden_field :version %> +<%= f.hidden_field :lock_version %> <%= error_messages_for 'content' %>

    <%= f.text_area :text, :cols => 100, :rows => 25, :class => 'wiki-edit', :accesskey => accesskey(:edit) %>

    diff --git a/app/views/wiki/history.rhtml b/app/views/wiki/history.rhtml index e3c4ecc6..72f5ff33 100644 --- a/app/views/wiki/history.rhtml +++ b/app/views/wiki/history.rhtml @@ -21,9 +21,9 @@ <%= link_to ver.version, :action => 'index', :page => @page.title, :version => ver.version %> <%= radio_button_tag('version', ver.version, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < @versions.size) %> <%= radio_button_tag('version_from', ver.version, (line_num==2), :id => "cbto-#{line_num}") if show_diff && (line_num > 1) %> - <%= format_time(ver.updated_on) %> - <%= link_to_user ver.author %> - <%=h ver.comments %> + <%= format_time(ver.updated_at) %> + <%= link_to_user ver.user %> + <%=h ver.notes %> <%= link_to l(:button_annotate), :action => 'annotate', :page => @page.title, :version => ver.version %> <% line_num += 1 %> diff --git a/lib/redmine.rb b/lib/redmine.rb index 8c95f084..03925370 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -186,7 +186,7 @@ Redmine::Activity.map do |activity| activity.register :news activity.register :documents, :class_name => %w(Document Attachment) activity.register :files, :class_name => 'Attachment' - activity.register :wiki_edits, :class_name => 'WikiContent::Version', :default => false + activity.register :wiki_edits, :class_name => 'WikiContent', :default => false activity.register :messages, :default => false activity.register :time_entries, :default => false end diff --git a/lib/redmine/wiki_formatting/macros.rb b/lib/redmine/wiki_formatting/macros.rb index 6f8d09d6..abc07b94 100644 --- a/lib/redmine/wiki_formatting/macros.rb +++ b/lib/redmine/wiki_formatting/macros.rb @@ -95,7 +95,7 @@ module Redmine page = nil if args.size > 0 page = Wiki.find_page(args.first.to_s, :project => @project) - elsif obj.is_a?(WikiContent) || obj.is_a?(WikiContent::Version) + elsif obj.is_a?(WikiContent) page = obj.page else raise 'With no argument, this macro can be called from wiki pages only.' diff --git a/vendor/plugins/acts_as_versioned/CHANGELOG b/vendor/plugins/acts_as_versioned/CHANGELOG deleted file mode 100644 index a5d339cc..00000000 --- a/vendor/plugins/acts_as_versioned/CHANGELOG +++ /dev/null @@ -1,74 +0,0 @@ -*SVN* (version numbers are overrated) - -* (5 Oct 2006) Allow customization of #versions association options [Dan Peterson] - -*0.5.1* - -* (8 Aug 2006) Versioned models now belong to the unversioned model. @article_version.article.class => Article [Aslak Hellesoy] - -*0.5* # do versions even matter for plugins? - -* (21 Apr 2006) Added without_locking and without_revision methods. - - Foo.without_revision do - @foo.update_attributes ... - end - -*0.4* - -* (28 March 2006) Rename non_versioned_fields to non_versioned_columns (old one is kept for compatibility). -* (28 March 2006) Made explicit documentation note that string column names are required for non_versioned_columns. - -*0.3.1* - -* (7 Jan 2006) explicitly set :foreign_key option for the versioned model's belongs_to assocation for STI [Caged] -* (7 Jan 2006) added tests to prove has_many :through joins work - -*0.3* - -* (2 Jan 2006) added ability to share a mixin with versioned class -* (2 Jan 2006) changed the dynamic version model to MyModel::Version - -*0.2.4* - -* (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig] - -*0.2.3* - -* (12 Nov 2005) fixed bug with old behavior of #blank? [Michael Schuerig] -* (12 Nov 2005) updated tests to use ActiveRecord Schema - -*0.2.2* - -* (3 Nov 2005) added documentation note to #acts_as_versioned [Martin Jul] - -*0.2.1* - -* (6 Oct 2005) renamed dirty? to changed? to keep it uniform. it was aliased to keep it backwards compatible. - -*0.2* - -* (6 Oct 2005) added find_versions and find_version class methods. - -* (6 Oct 2005) removed transaction from create_versioned_table(). - this way you can specify your own transaction around a group of operations. - -* (30 Sep 2005) fixed bug where find_versions() would order by 'version' twice. (found by Joe Clark) - -* (26 Sep 2005) added :sequence_name option to acts_as_versioned to set the sequence name on the versioned model - -*0.1.3* (18 Sep 2005) - -* First RubyForge release - -*0.1.2* - -* check if module is already included when acts_as_versioned is called - -*0.1.1* - -* Adding tests and rdocs - -*0.1* - -* Initial transfer from Rails ticket: http://dev.rubyonrails.com/ticket/1974 \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/MIT-LICENSE b/vendor/plugins/acts_as_versioned/MIT-LICENSE deleted file mode 100644 index 5851fdae..00000000 --- a/vendor/plugins/acts_as_versioned/MIT-LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2005 Rick Olson - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/README b/vendor/plugins/acts_as_versioned/README deleted file mode 100644 index 8961f052..00000000 --- a/vendor/plugins/acts_as_versioned/README +++ /dev/null @@ -1,28 +0,0 @@ -= acts_as_versioned - -This library adds simple versioning to an ActiveRecord module. ActiveRecord is required. - -== Resources - -Install - -* gem install acts_as_versioned - -Rubyforge project - -* http://rubyforge.org/projects/ar-versioned - -RDocs - -* http://ar-versioned.rubyforge.org - -Subversion - -* http://techno-weenie.net/svn/projects/acts_as_versioned - -Collaboa - -* http://collaboa.techno-weenie.net/repository/browse/acts_as_versioned - -Special thanks to Dreamer on ##rubyonrails for help in early testing. His ServerSideWiki (http://serversidewiki.com) -was the first project to use acts_as_versioned in the wild. \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/RUNNING_UNIT_TESTS b/vendor/plugins/acts_as_versioned/RUNNING_UNIT_TESTS deleted file mode 100644 index a6e55b84..00000000 --- a/vendor/plugins/acts_as_versioned/RUNNING_UNIT_TESTS +++ /dev/null @@ -1,41 +0,0 @@ -== Creating the test database - -The default name for the test databases is "activerecord_versioned". If you -want to use another database name then be sure to update the connection -adapter setups you want to test with in test/connections//connection.rb. -When you have the database online, you can import the fixture tables with -the test/fixtures/db_definitions/*.sql files. - -Make sure that you create database objects with the same user that you specified in i -connection.rb otherwise (on Postgres, at least) tests for default values will fail. - -== Running with Rake - -The easiest way to run the unit tests is through Rake. The default task runs -the entire test suite for all the adapters. You can also run the suite on just -one adapter by using the tasks test_mysql_ruby, test_ruby_mysql, test_sqlite, -or test_postresql. For more information, checkout the full array of rake tasks with "rake -T" - -Rake can be found at http://rake.rubyforge.org - -== Running by hand - -Unit tests are located in test directory. If you only want to run a single test suite, -or don't want to bother with Rake, you can do so with something like: - - cd test; ruby -I "connections/native_mysql" base_test.rb - -That'll run the base suite using the MySQL-Ruby adapter. Change the adapter -and test suite name as needed. - -== Faster tests - -If you are using a database that supports transactions, you can set the -"AR_TX_FIXTURES" environment variable to "yes" to use transactional fixtures. -This gives a very large speed boost. With rake: - - rake AR_TX_FIXTURES=yes - -Or, by hand: - - AR_TX_FIXTURES=yes ruby -I connections/native_sqlite3 base_test.rb diff --git a/vendor/plugins/acts_as_versioned/Rakefile b/vendor/plugins/acts_as_versioned/Rakefile deleted file mode 100644 index 5bccb5d8..00000000 --- a/vendor/plugins/acts_as_versioned/Rakefile +++ /dev/null @@ -1,182 +0,0 @@ -require 'rubygems' - -Gem::manage_gems - -require 'rake/rdoctask' -require 'rake/packagetask' -require 'rake/gempackagetask' -require 'rake/testtask' -require 'rake/contrib/rubyforgepublisher' - -PKG_NAME = 'acts_as_versioned' -PKG_VERSION = '0.3.1' -PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}" -PROD_HOST = "technoweenie@bidwell.textdrive.com" -RUBY_FORGE_PROJECT = 'ar-versioned' -RUBY_FORGE_USER = 'technoweenie' - -desc 'Default: run unit tests.' -task :default => :test - -desc 'Test the calculations plugin.' -Rake::TestTask.new(:test) do |t| - t.libs << 'lib' - t.pattern = 'test/**/*_test.rb' - t.verbose = true -end - -desc 'Generate documentation for the calculations plugin.' -Rake::RDocTask.new(:rdoc) do |rdoc| - rdoc.rdoc_dir = 'rdoc' - rdoc.title = "#{PKG_NAME} -- Simple versioning with active record models" - rdoc.options << '--line-numbers --inline-source' - rdoc.rdoc_files.include('README', 'CHANGELOG', 'RUNNING_UNIT_TESTS') - rdoc.rdoc_files.include('lib/**/*.rb') -end - -spec = Gem::Specification.new do |s| - s.name = PKG_NAME - s.version = PKG_VERSION - s.platform = Gem::Platform::RUBY - s.summary = "Simple versioning with active record models" - s.files = FileList["{lib,test}/**/*"].to_a + %w(README MIT-LICENSE CHANGELOG RUNNING_UNIT_TESTS) - s.files.delete "acts_as_versioned_plugin.sqlite.db" - s.files.delete "acts_as_versioned_plugin.sqlite3.db" - s.files.delete "test/debug.log" - s.require_path = 'lib' - s.autorequire = 'acts_as_versioned' - s.has_rdoc = true - s.test_files = Dir['test/**/*_test.rb'] - s.add_dependency 'activerecord', '>= 1.10.1' - s.add_dependency 'activesupport', '>= 1.1.1' - s.author = "Rick Olson" - s.email = "technoweenie@gmail.com" - s.homepage = "http://techno-weenie.net" -end - -Rake::GemPackageTask.new(spec) do |pkg| - pkg.need_tar = true -end - -desc "Publish the API documentation" -task :pdoc => [:rdoc] do - Rake::RubyForgePublisher.new(RUBY_FORGE_PROJECT, RUBY_FORGE_USER).upload -end - -desc 'Publish the gem and API docs' -task :publish => [:pdoc, :rubyforge_upload] - -desc "Publish the release files to RubyForge." -task :rubyforge_upload => :package do - files = %w(gem tgz).map { |ext| "pkg/#{PKG_FILE_NAME}.#{ext}" } - - if RUBY_FORGE_PROJECT then - require 'net/http' - require 'open-uri' - - project_uri = "http://rubyforge.org/projects/#{RUBY_FORGE_PROJECT}/" - project_data = open(project_uri) { |data| data.read } - group_id = project_data[/[?&]group_id=(\d+)/, 1] - raise "Couldn't get group id" unless group_id - - # This echos password to shell which is a bit sucky - if ENV["RUBY_FORGE_PASSWORD"] - password = ENV["RUBY_FORGE_PASSWORD"] - else - print "#{RUBY_FORGE_USER}@rubyforge.org's password: " - password = STDIN.gets.chomp - end - - login_response = Net::HTTP.start("rubyforge.org", 80) do |http| - data = [ - "login=1", - "form_loginname=#{RUBY_FORGE_USER}", - "form_pw=#{password}" - ].join("&") - http.post("/account/login.php", data) - end - - cookie = login_response["set-cookie"] - raise "Login failed" unless cookie - headers = { "Cookie" => cookie } - - release_uri = "http://rubyforge.org/frs/admin/?group_id=#{group_id}" - release_data = open(release_uri, headers) { |data| data.read } - package_id = release_data[/[?&]package_id=(\d+)/, 1] - raise "Couldn't get package id" unless package_id - - first_file = true - release_id = "" - - files.each do |filename| - basename = File.basename(filename) - file_ext = File.extname(filename) - file_data = File.open(filename, "rb") { |file| file.read } - - puts "Releasing #{basename}..." - - release_response = Net::HTTP.start("rubyforge.org", 80) do |http| - release_date = Time.now.strftime("%Y-%m-%d %H:%M") - type_map = { - ".zip" => "3000", - ".tgz" => "3110", - ".gz" => "3110", - ".gem" => "1400" - }; type_map.default = "9999" - type = type_map[file_ext] - boundary = "rubyqMY6QN9bp6e4kS21H4y0zxcvoor" - - query_hash = if first_file then - { - "group_id" => group_id, - "package_id" => package_id, - "release_name" => PKG_FILE_NAME, - "release_date" => release_date, - "type_id" => type, - "processor_id" => "8000", # Any - "release_notes" => "", - "release_changes" => "", - "preformatted" => "1", - "submit" => "1" - } - else - { - "group_id" => group_id, - "release_id" => release_id, - "package_id" => package_id, - "step2" => "1", - "type_id" => type, - "processor_id" => "8000", # Any - "submit" => "Add This File" - } - end - - query = "?" + query_hash.map do |(name, value)| - [name, URI.encode(value)].join("=") - end.join("&") - - data = [ - "--" + boundary, - "Content-Disposition: form-data; name=\"userfile\"; filename=\"#{basename}\"", - "Content-Type: application/octet-stream", - "Content-Transfer-Encoding: binary", - "", file_data, "" - ].join("\x0D\x0A") - - release_headers = headers.merge( - "Content-Type" => "multipart/form-data; boundary=#{boundary}" - ) - - target = first_file ? "/frs/admin/qrs.php" : "/frs/admin/editrelease.php" - http.post(target + query, data, release_headers) - end - - if first_file then - release_id = release_response.body[/release_id=(\d+)/, 1] - raise("Couldn't get release id") unless release_id - end - - first_file = false - end - end -end \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/init.rb b/vendor/plugins/acts_as_versioned/init.rb deleted file mode 100644 index 5937bbc7..00000000 --- a/vendor/plugins/acts_as_versioned/init.rb +++ /dev/null @@ -1 +0,0 @@ -require 'acts_as_versioned' \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb b/vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb deleted file mode 100644 index bba10c43..00000000 --- a/vendor/plugins/acts_as_versioned/lib/acts_as_versioned.rb +++ /dev/null @@ -1,564 +0,0 @@ -# Copyright (c) 2005 Rick Olson -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -module ActiveRecord #:nodoc: - module Acts #:nodoc: - # Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a - # versioned table ready and that your model has a version field. This works with optimistic locking if the lock_version - # column is present as well. - # - # The class for the versioned model is derived the first time it is seen. Therefore, if you change your database schema you have to restart - # your container for the changes to be reflected. In development mode this usually means restarting WEBrick. - # - # class Page < ActiveRecord::Base - # # assumes pages_versions table - # acts_as_versioned - # end - # - # Example: - # - # page = Page.create(:title => 'hello world!') - # page.version # => 1 - # - # page.title = 'hello world' - # page.save - # page.version # => 2 - # page.versions.size # => 2 - # - # page.revert_to(1) # using version number - # page.title # => 'hello world!' - # - # page.revert_to(page.versions.last) # using versioned instance - # page.title # => 'hello world' - # - # page.versions.earliest # efficient query to find the first version - # page.versions.latest # efficient query to find the most recently created version - # - # - # Simple Queries to page between versions - # - # page.versions.before(version) - # page.versions.after(version) - # - # Access the previous/next versions from the versioned model itself - # - # version = page.versions.latest - # version.previous # go back one version - # version.next # go forward one version - # - # See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options - module Versioned - CALLBACKS = [:set_new_version, :save_version_on_create, :save_version?, :clear_altered_attributes] - def self.included(base) # :nodoc: - base.extend ClassMethods - end - - module ClassMethods - # == Configuration options - # - # * class_name - versioned model class name (default: PageVersion in the above example) - # * table_name - versioned model table name (default: page_versions in the above example) - # * foreign_key - foreign key used to relate the versioned model to the original model (default: page_id in the above example) - # * inheritance_column - name of the column to save the model's inheritance_column value for STI. (default: versioned_type) - # * version_column - name of the column in the model that keeps the version number (default: version) - # * sequence_name - name of the custom sequence to be used by the versioned model. - # * limit - number of revisions to keep, defaults to unlimited - # * if - symbol of method to check before saving a new version. If this method returns false, a new version is not saved. - # For finer control, pass either a Proc or modify Model#version_condition_met? - # - # acts_as_versioned :if => Proc.new { |auction| !auction.expired? } - # - # or... - # - # class Auction - # def version_condition_met? # totally bypasses the :if option - # !expired? - # end - # end - # - # * if_changed - Simple way of specifying attributes that are required to be changed before saving a model. This takes - # either a symbol or array of symbols. WARNING - This will attempt to overwrite any attribute setters you may have. - # Use this instead if you want to write your own attribute setters (and ignore if_changed): - # - # def name=(new_name) - # write_changed_attribute :name, new_name - # end - # - # * extend - Lets you specify a module to be mixed in both the original and versioned models. You can also just pass a block - # to create an anonymous mixin: - # - # class Auction - # acts_as_versioned do - # def started? - # !started_at.nil? - # end - # end - # end - # - # or... - # - # module AuctionExtension - # def started? - # !started_at.nil? - # end - # end - # class Auction - # acts_as_versioned :extend => AuctionExtension - # end - # - # Example code: - # - # @auction = Auction.find(1) - # @auction.started? - # @auction.versions.first.started? - # - # == Database Schema - # - # The model that you're versioning needs to have a 'version' attribute. The model is versioned - # into a table called #{model}_versions where the model name is singlular. The _versions table should - # contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field. - # - # A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance, - # then that field is reflected in the versioned model as 'versioned_type' by default. - # - # Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table - # method, perfect for a migration. It will also create the version column if the main model does not already have it. - # - # class AddVersions < ActiveRecord::Migration - # def self.up - # # create_versioned_table takes the same options hash - # # that create_table does - # Post.create_versioned_table - # end - # - # def self.down - # Post.drop_versioned_table - # end - # end - # - # == Changing What Fields Are Versioned - # - # By default, acts_as_versioned will version all but these fields: - # - # [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column] - # - # You can add or change those by modifying #non_versioned_columns. Note that this takes strings and not symbols. - # - # class Post < ActiveRecord::Base - # acts_as_versioned - # self.non_versioned_columns << 'comments_count' - # end - # - def acts_as_versioned(options = {}, &extension) - # don't allow multiple calls - return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods) - - send :include, ActiveRecord::Acts::Versioned::ActMethods - - cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column, - :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns, - :version_association_options - - # legacy - alias_method :non_versioned_fields, :non_versioned_columns - alias_method :non_versioned_fields=, :non_versioned_columns= - - class << self - alias_method :non_versioned_fields, :non_versioned_columns - alias_method :non_versioned_fields=, :non_versioned_columns= - end - - send :attr_accessor, :altered_attributes - - self.versioned_class_name = options[:class_name] || "Version" - self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key - self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}" - self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}" - self.version_column = options[:version_column] || 'version' - self.version_sequence_name = options[:sequence_name] - self.max_version_limit = options[:limit].to_i - self.version_condition = options[:if] || true - self.non_versioned_columns = [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column] - self.version_association_options = { - :class_name => "#{self.to_s}::#{versioned_class_name}", - :foreign_key => versioned_foreign_key, - :dependent => :delete_all - }.merge(options[:association_options] || {}) - - if block_given? - extension_module_name = "#{versioned_class_name}Extension" - silence_warnings do - self.const_set(extension_module_name, Module.new(&extension)) - end - - options[:extend] = self.const_get(extension_module_name) - end - - class_eval do - has_many :versions, version_association_options do - # finds earliest version of this record - def earliest - @earliest ||= find(:first, :order => 'version') - end - - # find latest version of this record - def latest - @latest ||= find(:first, :order => 'version desc') - end - end - before_save :set_new_version - after_create :save_version_on_create - after_update :save_version - after_save :clear_old_versions - after_save :clear_altered_attributes - - unless options[:if_changed].nil? - self.track_altered_attributes = true - options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array) - options[:if_changed].each do |attr_name| - define_method("#{attr_name}=") do |value| - write_changed_attribute attr_name, value - end - end - end - - include options[:extend] if options[:extend].is_a?(Module) - end - - # create the dynamic versioned model - const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do - def self.reloadable? ; false ; end - # find first version before the given version - def self.before(version) - find :first, :order => 'version desc', - :conditions => ["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version] - end - - # find first version after the given version. - def self.after(version) - find :first, :order => 'version', - :conditions => ["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version] - end - - def previous - self.class.before(self) - end - - def next - self.class.after(self) - end - - def versions_count - page.version - end - end - - versioned_class.cattr_accessor :original_class - versioned_class.original_class = self - versioned_class.set_table_name versioned_table_name - versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym, - :class_name => "::#{self.to_s}", - :foreign_key => versioned_foreign_key - versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module) - versioned_class.set_sequence_name version_sequence_name if version_sequence_name - end - end - - module ActMethods - def self.included(base) # :nodoc: - base.extend ClassMethods - end - - # Finds a specific version of this record - def find_version(version = nil) - self.class.find_version(id, version) - end - - # Saves a version of the model if applicable - def save_version - save_version_on_create if save_version? - end - - # Saves a version of the model in the versioned table. This is called in the after_save callback by default - def save_version_on_create - rev = self.class.versioned_class.new - self.clone_versioned_model(self, rev) - rev.version = send(self.class.version_column) - rev.send("#{self.class.versioned_foreign_key}=", self.id) - rev.save - end - - # Clears old revisions if a limit is set with the :limit option in acts_as_versioned. - # Override this method to set your own criteria for clearing old versions. - def clear_old_versions - return if self.class.max_version_limit == 0 - excess_baggage = send(self.class.version_column).to_i - self.class.max_version_limit - if excess_baggage > 0 - sql = "DELETE FROM #{self.class.versioned_table_name} WHERE version <= #{excess_baggage} AND #{self.class.versioned_foreign_key} = #{self.id}" - self.class.versioned_class.connection.execute sql - end - end - - def versions_count - version - end - - # Reverts a model to a given version. Takes either a version number or an instance of the versioned model - def revert_to(version) - if version.is_a?(self.class.versioned_class) - return false unless version.send(self.class.versioned_foreign_key) == self.id and !version.new_record? - else - return false unless version = versions.find_by_version(version) - end - self.clone_versioned_model(version, self) - self.send("#{self.class.version_column}=", version.version) - true - end - - # Reverts a model to a given version and saves the model. - # Takes either a version number or an instance of the versioned model - def revert_to!(version) - revert_to(version) ? save_without_revision : false - end - - # Temporarily turns off Optimistic Locking while saving. Used when reverting so that a new version is not created. - def save_without_revision - save_without_revision! - true - rescue - false - end - - def save_without_revision! - without_locking do - without_revision do - save! - end - end - end - - # Returns an array of attribute keys that are versioned. See non_versioned_columns - def versioned_attributes - self.attributes.keys.select { |k| !self.class.non_versioned_columns.include?(k) } - end - - # If called with no parameters, gets whether the current model has changed and needs to be versioned. - # If called with a single parameter, gets whether the parameter has changed. - def changed?(attr_name = nil) - attr_name.nil? ? - (!self.class.track_altered_attributes || (altered_attributes && altered_attributes.length > 0)) : - (altered_attributes && altered_attributes.include?(attr_name.to_s)) - end - - # keep old dirty? method - alias_method :dirty?, :changed? - - # Clones a model. Used when saving a new version or reverting a model's version. - def clone_versioned_model(orig_model, new_model) - self.versioned_attributes.each do |key| - new_model.send("#{key}=", orig_model.send(key)) if orig_model.has_attribute?(key) - end - - if orig_model.is_a?(self.class.versioned_class) - new_model[new_model.class.inheritance_column] = orig_model[self.class.versioned_inheritance_column] - elsif new_model.is_a?(self.class.versioned_class) - new_model[self.class.versioned_inheritance_column] = orig_model[orig_model.class.inheritance_column] - end - end - - # Checks whether a new version shall be saved or not. Calls version_condition_met? and changed?. - def save_version? - version_condition_met? && changed? - end - - # Checks condition set in the :if option to check whether a revision should be created or not. Override this for - # custom version condition checking. - def version_condition_met? - case - when version_condition.is_a?(Symbol) - send(version_condition) - when version_condition.respond_to?(:call) && (version_condition.arity == 1 || version_condition.arity == -1) - version_condition.call(self) - else - version_condition - end - end - - # Executes the block with the versioning callbacks disabled. - # - # @foo.without_revision do - # @foo.save - # end - # - def without_revision(&block) - self.class.without_revision(&block) - end - - # Turns off optimistic locking for the duration of the block - # - # @foo.without_locking do - # @foo.save - # end - # - def without_locking(&block) - self.class.without_locking(&block) - end - - def empty_callback() end #:nodoc: - - protected - # sets the new version before saving, unless you're using optimistic locking. In that case, let it take care of the version. - def set_new_version - self.send("#{self.class.version_column}=", self.next_version) if new_record? || (!locking_enabled? && save_version?) - end - - # Gets the next available version for the current record, or 1 for a new record - def next_version - return 1 if new_record? - (versions.calculate(:max, :version) || 0) + 1 - end - - # clears current changed attributes. Called after save. - def clear_altered_attributes - self.altered_attributes = [] - end - - def write_changed_attribute(attr_name, attr_value) - # Convert to db type for comparison. Avoids failing Float<=>String comparisons. - attr_value_for_db = self.class.columns_hash[attr_name.to_s].type_cast(attr_value) - (self.altered_attributes ||= []) << attr_name.to_s unless self.changed?(attr_name) || self.send(attr_name) == attr_value_for_db - write_attribute(attr_name, attr_value_for_db) - end - - module ClassMethods - # Finds a specific version of a specific row of this model - def find_version(id, version = nil) - return find(id) unless version - - conditions = ["#{versioned_foreign_key} = ? AND version = ?", id, version] - options = { :conditions => conditions, :limit => 1 } - - if result = find_versions(id, options).first - result - else - raise RecordNotFound, "Couldn't find #{name} with ID=#{id} and VERSION=#{version}" - end - end - - # Finds versions of a specific model. Takes an options hash like find - def find_versions(id, options = {}) - versioned_class.find :all, { - :conditions => ["#{versioned_foreign_key} = ?", id], - :order => 'version' }.merge(options) - end - - # Returns an array of columns that are versioned. See non_versioned_columns - def versioned_columns - self.columns.select { |c| !non_versioned_columns.include?(c.name) } - end - - # Returns an instance of the dynamic versioned model - def versioned_class - const_get versioned_class_name - end - - # Rake migration task to create the versioned table using options passed to acts_as_versioned - def create_versioned_table(create_table_options = {}) - # create version column in main table if it does not exist - if !self.content_columns.find { |c| %w(version lock_version).include? c.name } - self.connection.add_column table_name, :version, :integer - end - - self.connection.create_table(versioned_table_name, create_table_options) do |t| - t.column versioned_foreign_key, :integer - t.column :version, :integer - end - - updated_col = nil - self.versioned_columns.each do |col| - updated_col = col if !updated_col && %(updated_at updated_on).include?(col.name) - self.connection.add_column versioned_table_name, col.name, col.type, - :limit => col.limit, - :default => col.default, - :scale => col.scale, - :precision => col.precision - end - - if type_col = self.columns_hash[inheritance_column] - self.connection.add_column versioned_table_name, versioned_inheritance_column, type_col.type, - :limit => type_col.limit, - :default => type_col.default, - :scale => type_col.scale, - :precision => type_col.precision - end - - if updated_col.nil? - self.connection.add_column versioned_table_name, :updated_at, :timestamp - end - end - - # Rake migration task to drop the versioned table - def drop_versioned_table - self.connection.drop_table versioned_table_name - end - - # Executes the block with the versioning callbacks disabled. - # - # Foo.without_revision do - # @foo.save - # end - # - def without_revision(&block) - class_eval do - CALLBACKS.each do |attr_name| - alias_method "orig_#{attr_name}".to_sym, attr_name - alias_method attr_name, :empty_callback - end - end - block.call - ensure - class_eval do - CALLBACKS.each do |attr_name| - alias_method attr_name, "orig_#{attr_name}".to_sym - end - end - end - - # Turns off optimistic locking for the duration of the block - # - # Foo.without_locking do - # @foo.save - # end - # - def without_locking(&block) - current = ActiveRecord::Base.lock_optimistically - ActiveRecord::Base.lock_optimistically = false if current - result = block.call - ActiveRecord::Base.lock_optimistically = true if current - result - end - end - end - end - end -end - -ActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/test/abstract_unit.rb b/vendor/plugins/acts_as_versioned/test/abstract_unit.rb deleted file mode 100644 index 86f50620..00000000 --- a/vendor/plugins/acts_as_versioned/test/abstract_unit.rb +++ /dev/null @@ -1,41 +0,0 @@ -$:.unshift(File.dirname(__FILE__) + '/../../../rails/activesupport/lib') -$:.unshift(File.dirname(__FILE__) + '/../../../rails/activerecord/lib') -$:.unshift(File.dirname(__FILE__) + '/../lib') -require 'test/unit' -begin - require 'active_support' - require 'active_record' - require 'active_record/fixtures' -rescue LoadError - require 'rubygems' - retry -end -require 'acts_as_versioned' - -config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml')) -ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log") -ActiveRecord::Base.configurations = {'test' => config[ENV['DB'] || 'sqlite3']} -ActiveRecord::Base.establish_connection(ActiveRecord::Base.configurations['test']) - -load(File.dirname(__FILE__) + "/schema.rb") - -# set up custom sequence on widget_versions for DBs that support sequences -if ENV['DB'] == 'postgresql' - ActiveRecord::Base.connection.execute "DROP SEQUENCE widgets_seq;" rescue nil - ActiveRecord::Base.connection.remove_column :widget_versions, :id - ActiveRecord::Base.connection.execute "CREATE SEQUENCE widgets_seq START 101;" - ActiveRecord::Base.connection.execute "ALTER TABLE widget_versions ADD COLUMN id INTEGER PRIMARY KEY DEFAULT nextval('widgets_seq');" -end - -Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/" -$:.unshift(Test::Unit::TestCase.fixture_path) - -class Test::Unit::TestCase #:nodoc: - # Turn off transactional fixtures if you're working with MyISAM tables in MySQL - self.use_transactional_fixtures = true - - # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david) - self.use_instantiated_fixtures = false - - # Add more helper methods to be used by all tests here... -end \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/test/database.yml b/vendor/plugins/acts_as_versioned/test/database.yml deleted file mode 100644 index 506e6bd3..00000000 --- a/vendor/plugins/acts_as_versioned/test/database.yml +++ /dev/null @@ -1,18 +0,0 @@ -sqlite: - :adapter: sqlite - :dbfile: acts_as_versioned_plugin.sqlite.db -sqlite3: - :adapter: sqlite3 - :dbfile: acts_as_versioned_plugin.sqlite3.db -postgresql: - :adapter: postgresql - :username: postgres - :password: postgres - :database: acts_as_versioned_plugin_test - :min_messages: ERROR -mysql: - :adapter: mysql - :host: localhost - :username: rails - :password: - :database: acts_as_versioned_plugin_test \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/authors.yml b/vendor/plugins/acts_as_versioned/test/fixtures/authors.yml deleted file mode 100644 index bd7a5aed..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/authors.yml +++ /dev/null @@ -1,6 +0,0 @@ -caged: - id: 1 - name: caged -mly: - id: 2 - name: mly \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/landmark.rb b/vendor/plugins/acts_as_versioned/test/fixtures/landmark.rb deleted file mode 100644 index cb9b9305..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/landmark.rb +++ /dev/null @@ -1,3 +0,0 @@ -class Landmark < ActiveRecord::Base - acts_as_versioned :if_changed => [ :name, :longitude, :latitude ] -end diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/landmark_versions.yml b/vendor/plugins/acts_as_versioned/test/fixtures/landmark_versions.yml deleted file mode 100644 index 2dbd54ed..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/landmark_versions.yml +++ /dev/null @@ -1,7 +0,0 @@ -washington: - id: 1 - landmark_id: 1 - version: 1 - name: Washington, D.C. - latitude: 38.895 - longitude: -77.036667 diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/landmarks.yml b/vendor/plugins/acts_as_versioned/test/fixtures/landmarks.yml deleted file mode 100644 index 46d96176..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/landmarks.yml +++ /dev/null @@ -1,6 +0,0 @@ -washington: - id: 1 - name: Washington, D.C. - latitude: 38.895 - longitude: -77.036667 - version: 1 diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/locked_pages.yml b/vendor/plugins/acts_as_versioned/test/fixtures/locked_pages.yml deleted file mode 100644 index 318e776c..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/locked_pages.yml +++ /dev/null @@ -1,10 +0,0 @@ -welcome: - id: 1 - title: Welcome to the weblog - lock_version: 24 - type: LockedPage -thinking: - id: 2 - title: So I was thinking - lock_version: 24 - type: SpecialLockedPage diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/locked_pages_revisions.yml b/vendor/plugins/acts_as_versioned/test/fixtures/locked_pages_revisions.yml deleted file mode 100644 index 5c978e62..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/locked_pages_revisions.yml +++ /dev/null @@ -1,27 +0,0 @@ -welcome_1: - id: 1 - page_id: 1 - title: Welcome to the weblg - version: 23 - version_type: LockedPage - -welcome_2: - id: 2 - page_id: 1 - title: Welcome to the weblog - version: 24 - version_type: LockedPage - -thinking_1: - id: 3 - page_id: 2 - title: So I was thinking!!! - version: 23 - version_type: SpecialLockedPage - -thinking_2: - id: 4 - page_id: 2 - title: So I was thinking - version: 24 - version_type: SpecialLockedPage diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/migrations/1_add_versioned_tables.rb b/vendor/plugins/acts_as_versioned/test/fixtures/migrations/1_add_versioned_tables.rb deleted file mode 100644 index 9512b5e8..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/migrations/1_add_versioned_tables.rb +++ /dev/null @@ -1,13 +0,0 @@ -class AddVersionedTables < ActiveRecord::Migration - def self.up - create_table("things") do |t| - t.column :title, :text - end - Thing.create_versioned_table - end - - def self.down - Thing.drop_versioned_table - drop_table "things" rescue nil - end -end \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/page.rb b/vendor/plugins/acts_as_versioned/test/fixtures/page.rb deleted file mode 100644 index f133e351..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/page.rb +++ /dev/null @@ -1,43 +0,0 @@ -class Page < ActiveRecord::Base - belongs_to :author - has_many :authors, :through => :versions, :order => 'name' - belongs_to :revisor, :class_name => 'Author' - has_many :revisors, :class_name => 'Author', :through => :versions, :order => 'name' - acts_as_versioned :if => :feeling_good? do - def self.included(base) - base.cattr_accessor :feeling_good - base.feeling_good = true - base.belongs_to :author - base.belongs_to :revisor, :class_name => 'Author' - end - - def feeling_good? - @@feeling_good == true - end - end -end - -module LockedPageExtension - def hello_world - 'hello_world' - end -end - -class LockedPage < ActiveRecord::Base - acts_as_versioned \ - :inheritance_column => :version_type, - :foreign_key => :page_id, - :table_name => :locked_pages_revisions, - :class_name => 'LockedPageRevision', - :version_column => :lock_version, - :limit => 2, - :if_changed => :title, - :extend => LockedPageExtension -end - -class SpecialLockedPage < LockedPage -end - -class Author < ActiveRecord::Base - has_many :pages -end \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/page_versions.yml b/vendor/plugins/acts_as_versioned/test/fixtures/page_versions.yml deleted file mode 100644 index ef565fa4..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/page_versions.yml +++ /dev/null @@ -1,16 +0,0 @@ -welcome_2: - id: 1 - page_id: 1 - title: Welcome to the weblog - body: Such a lovely day - version: 24 - author_id: 1 - revisor_id: 1 -welcome_1: - id: 2 - page_id: 1 - title: Welcome to the weblg - body: Such a lovely day - version: 23 - author_id: 2 - revisor_id: 2 diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/pages.yml b/vendor/plugins/acts_as_versioned/test/fixtures/pages.yml deleted file mode 100644 index 07ac51f9..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/pages.yml +++ /dev/null @@ -1,7 +0,0 @@ -welcome: - id: 1 - title: Welcome to the weblog - body: Such a lovely day - version: 24 - author_id: 1 - revisor_id: 1 \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/test/fixtures/widget.rb b/vendor/plugins/acts_as_versioned/test/fixtures/widget.rb deleted file mode 100644 index 086ac2b4..00000000 --- a/vendor/plugins/acts_as_versioned/test/fixtures/widget.rb +++ /dev/null @@ -1,6 +0,0 @@ -class Widget < ActiveRecord::Base - acts_as_versioned :sequence_name => 'widgets_seq', :association_options => { - :dependent => :nullify, :order => 'version desc' - } - non_versioned_columns << 'foo' -end \ No newline at end of file diff --git a/vendor/plugins/acts_as_versioned/test/migration_test.rb b/vendor/plugins/acts_as_versioned/test/migration_test.rb deleted file mode 100644 index 4ead4a8f..00000000 --- a/vendor/plugins/acts_as_versioned/test/migration_test.rb +++ /dev/null @@ -1,46 +0,0 @@ -require File.join(File.dirname(__FILE__), 'abstract_unit') - -if ActiveRecord::Base.connection.supports_migrations? - class Thing < ActiveRecord::Base - attr_accessor :version - acts_as_versioned - end - - class MigrationTest < Test::Unit::TestCase - self.use_transactional_fixtures = false - def teardown - if ActiveRecord::Base.connection.respond_to?(:initialize_schema_information) - ActiveRecord::Base.connection.initialize_schema_information - ActiveRecord::Base.connection.update "UPDATE schema_info SET version = 0" - else - ActiveRecord::Base.connection.initialize_schema_migrations_table - ActiveRecord::Base.connection.assume_migrated_upto_version(0) - end - - Thing.connection.drop_table "things" rescue nil - Thing.connection.drop_table "thing_versions" rescue nil - Thing.reset_column_information - end - - def test_versioned_migration - assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' } - # take 'er up - ActiveRecord::Migrator.up(File.dirname(__FILE__) + '/fixtures/migrations/') - t = Thing.create :title => 'blah blah', :price => 123.45, :type => 'Thing' - assert_equal 1, t.versions.size - - # check that the price column has remembered its value correctly - assert_equal t.price, t.versions.first.price - assert_equal t.title, t.versions.first.title - assert_equal t[:type], t.versions.first[:type] - - # make sure that the precision of the price column has been preserved - assert_equal 7, Thing::Version.columns.find{|c| c.name == "price"}.precision - assert_equal 2, Thing::Version.columns.find{|c| c.name == "price"}.scale - - # now lets take 'er back down - ActiveRecord::Migrator.down(File.dirname(__FILE__) + '/fixtures/migrations/') - assert_raises(ActiveRecord::StatementInvalid) { Thing.create :title => 'blah blah' } - end - end -end diff --git a/vendor/plugins/acts_as_versioned/test/schema.rb b/vendor/plugins/acts_as_versioned/test/schema.rb deleted file mode 100644 index 7d5153d0..00000000 --- a/vendor/plugins/acts_as_versioned/test/schema.rb +++ /dev/null @@ -1,68 +0,0 @@ -ActiveRecord::Schema.define(:version => 0) do - create_table :pages, :force => true do |t| - t.column :version, :integer - t.column :title, :string, :limit => 255 - t.column :body, :text - t.column :updated_on, :datetime - t.column :author_id, :integer - t.column :revisor_id, :integer - end - - create_table :page_versions, :force => true do |t| - t.column :page_id, :integer - t.column :version, :integer - t.column :title, :string, :limit => 255 - t.column :body, :text - t.column :updated_on, :datetime - t.column :author_id, :integer - t.column :revisor_id, :integer - end - - create_table :authors, :force => true do |t| - t.column :page_id, :integer - t.column :name, :string - end - - create_table :locked_pages, :force => true do |t| - t.column :lock_version, :integer - t.column :title, :string, :limit => 255 - t.column :type, :string, :limit => 255 - end - - create_table :locked_pages_revisions, :force => true do |t| - t.column :page_id, :integer - t.column :version, :integer - t.column :title, :string, :limit => 255 - t.column :version_type, :string, :limit => 255 - t.column :updated_at, :datetime - end - - create_table :widgets, :force => true do |t| - t.column :name, :string, :limit => 50 - t.column :foo, :string - t.column :version, :integer - t.column :updated_at, :datetime - end - - create_table :widget_versions, :force => true do |t| - t.column :widget_id, :integer - t.column :name, :string, :limit => 50 - t.column :version, :integer - t.column :updated_at, :datetime - end - - create_table :landmarks, :force => true do |t| - t.column :name, :string - t.column :latitude, :float - t.column :longitude, :float - t.column :version, :integer - end - - create_table :landmark_versions, :force => true do |t| - t.column :landmark_id, :integer - t.column :name, :string - t.column :latitude, :float - t.column :longitude, :float - t.column :version, :integer - end -end diff --git a/vendor/plugins/acts_as_versioned/test/versioned_test.rb b/vendor/plugins/acts_as_versioned/test/versioned_test.rb deleted file mode 100644 index a7bc2082..00000000 --- a/vendor/plugins/acts_as_versioned/test/versioned_test.rb +++ /dev/null @@ -1,347 +0,0 @@ -require File.join(File.dirname(__FILE__), 'abstract_unit') -require File.join(File.dirname(__FILE__), 'fixtures/page') -require File.join(File.dirname(__FILE__), 'fixtures/widget') - -class VersionedTest < Test::Unit::TestCase - fixtures :pages, :page_versions, :locked_pages, :locked_pages_revisions, :authors, :landmarks, :landmark_versions - set_fixture_class :page_versions => Page::Version - - def test_saves_versioned_copy - p = Page.create! :title => 'first title', :body => 'first body' - assert !p.new_record? - assert_equal 1, p.versions.size - assert_equal 1, p.version - assert_instance_of Page.versioned_class, p.versions.first - end - - def test_saves_without_revision - p = pages(:welcome) - old_versions = p.versions.count - - p.save_without_revision - - p.without_revision do - p.update_attributes :title => 'changed' - end - - assert_equal old_versions, p.versions.count - end - - def test_rollback_with_version_number - p = pages(:welcome) - assert_equal 24, p.version - assert_equal 'Welcome to the weblog', p.title - - assert p.revert_to!(p.versions.first.version), "Couldn't revert to 23" - assert_equal 23, p.version - assert_equal 'Welcome to the weblg', p.title - end - - def test_versioned_class_name - assert_equal 'Version', Page.versioned_class_name - assert_equal 'LockedPageRevision', LockedPage.versioned_class_name - end - - def test_versioned_class - assert_equal Page::Version, Page.versioned_class - assert_equal LockedPage::LockedPageRevision, LockedPage.versioned_class - end - - def test_special_methods - assert_nothing_raised { pages(:welcome).feeling_good? } - assert_nothing_raised { pages(:welcome).versions.first.feeling_good? } - assert_nothing_raised { locked_pages(:welcome).hello_world } - assert_nothing_raised { locked_pages(:welcome).versions.first.hello_world } - end - - def test_rollback_with_version_class - p = pages(:welcome) - assert_equal 24, p.version - assert_equal 'Welcome to the weblog', p.title - - assert p.revert_to!(p.versions.first), "Couldn't revert to 23" - assert_equal 23, p.version - assert_equal 'Welcome to the weblg', p.title - end - - def test_rollback_fails_with_invalid_revision - p = locked_pages(:welcome) - assert !p.revert_to!(locked_pages(:thinking)) - end - - def test_saves_versioned_copy_with_options - p = LockedPage.create! :title => 'first title' - assert !p.new_record? - assert_equal 1, p.versions.size - assert_instance_of LockedPage.versioned_class, p.versions.first - end - - def test_rollback_with_version_number_with_options - p = locked_pages(:welcome) - assert_equal 'Welcome to the weblog', p.title - assert_equal 'LockedPage', p.versions.first.version_type - - assert p.revert_to!(p.versions.first.version), "Couldn't revert to 23" - assert_equal 'Welcome to the weblg', p.title - assert_equal 'LockedPage', p.versions.first.version_type - end - - def test_rollback_with_version_class_with_options - p = locked_pages(:welcome) - assert_equal 'Welcome to the weblog', p.title - assert_equal 'LockedPage', p.versions.first.version_type - - assert p.revert_to!(p.versions.first), "Couldn't revert to 1" - assert_equal 'Welcome to the weblg', p.title - assert_equal 'LockedPage', p.versions.first.version_type - end - - def test_saves_versioned_copy_with_sti - p = SpecialLockedPage.create! :title => 'first title' - assert !p.new_record? - assert_equal 1, p.versions.size - assert_instance_of LockedPage.versioned_class, p.versions.first - assert_equal 'SpecialLockedPage', p.versions.first.version_type - end - - def test_rollback_with_version_number_with_sti - p = locked_pages(:thinking) - assert_equal 'So I was thinking', p.title - - assert p.revert_to!(p.versions.first.version), "Couldn't revert to 1" - assert_equal 'So I was thinking!!!', p.title - assert_equal 'SpecialLockedPage', p.versions.first.version_type - end - - def test_lock_version_works_with_versioning - p = locked_pages(:thinking) - p2 = LockedPage.find(p.id) - - p.title = 'fresh title' - p.save - assert_equal 2, p.versions.size # limit! - - assert_raises(ActiveRecord::StaleObjectError) do - p2.title = 'stale title' - p2.save - end - end - - def test_version_if_condition - p = Page.create! :title => "title" - assert_equal 1, p.version - - Page.feeling_good = false - p.save - assert_equal 1, p.version - Page.feeling_good = true - end - - def test_version_if_condition2 - # set new if condition - Page.class_eval do - def new_feeling_good() title[0..0] == 'a'; end - alias_method :old_feeling_good, :feeling_good? - alias_method :feeling_good?, :new_feeling_good - end - - p = Page.create! :title => "title" - assert_equal 1, p.version # version does not increment - assert_equal 1, p.versions(true).size - - p.update_attributes(:title => 'new title') - assert_equal 1, p.version # version does not increment - assert_equal 1, p.versions(true).size - - p.update_attributes(:title => 'a title') - assert_equal 2, p.version - assert_equal 2, p.versions(true).size - - # reset original if condition - Page.class_eval { alias_method :feeling_good?, :old_feeling_good } - end - - def test_version_if_condition_with_block - # set new if condition - old_condition = Page.version_condition - Page.version_condition = Proc.new { |page| page.title[0..0] == 'b' } - - p = Page.create! :title => "title" - assert_equal 1, p.version # version does not increment - assert_equal 1, p.versions(true).size - - p.update_attributes(:title => 'a title') - assert_equal 1, p.version # version does not increment - assert_equal 1, p.versions(true).size - - p.update_attributes(:title => 'b title') - assert_equal 2, p.version - assert_equal 2, p.versions(true).size - - # reset original if condition - Page.version_condition = old_condition - end - - def test_version_no_limit - p = Page.create! :title => "title", :body => 'first body' - p.save - p.save - 5.times do |i| - assert_page_title p, i - end - end - - def test_version_max_limit - p = LockedPage.create! :title => "title" - p.update_attributes(:title => "title1") - p.update_attributes(:title => "title2") - 5.times do |i| - assert_page_title p, i, :lock_version - assert p.versions(true).size <= 2, "locked version can only store 2 versions" - end - end - - def test_track_altered_attributes_default_value - assert !Page.track_altered_attributes - assert LockedPage.track_altered_attributes - assert SpecialLockedPage.track_altered_attributes - end - - def test_version_order - assert_equal 23, pages(:welcome).versions.first.version - assert_equal 24, pages(:welcome).versions.last.version - end - - def test_track_altered_attributes - p = LockedPage.create! :title => "title" - assert_equal 1, p.lock_version - assert_equal 1, p.versions(true).size - - p.title = 'title' - assert !p.save_version? - p.save - assert_equal 2, p.lock_version # still increments version because of optimistic locking - assert_equal 1, p.versions(true).size - - p.title = 'updated title' - assert p.save_version? - p.save - assert_equal 3, p.lock_version - assert_equal 1, p.versions(true).size # version 1 deleted - - p.title = 'updated title!' - assert p.save_version? - p.save - assert_equal 4, p.lock_version - assert_equal 2, p.versions(true).size # version 1 deleted - end - - def assert_page_title(p, i, version_field = :version) - p.title = "title#{i}" - p.save - assert_equal "title#{i}", p.title - assert_equal (i+4), p.send(version_field) - end - - def test_find_versions - assert_equal 2, locked_pages(:welcome).versions.size - assert_equal 1, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%weblog%']).length - assert_equal 2, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%web%']).length - assert_equal 0, locked_pages(:thinking).versions.find(:all, :conditions => ['title LIKE ?', '%web%']).length - assert_equal 2, locked_pages(:welcome).versions.length - end - - def test_find_version - assert_equal page_versions(:welcome_1), Page.find_version(pages(:welcome).id, 23) - assert_equal page_versions(:welcome_2), Page.find_version(pages(:welcome).id, 24) - assert_equal pages(:welcome), Page.find_version(pages(:welcome).id) - - assert_equal page_versions(:welcome_1), pages(:welcome).find_version(23) - assert_equal page_versions(:welcome_2), pages(:welcome).find_version(24) - assert_equal pages(:welcome), pages(:welcome).find_version - - assert_raise(ActiveRecord::RecordNotFound) { Page.find_version(pages(:welcome).id, 1) } - assert_raise(ActiveRecord::RecordNotFound) { Page.find_version(0, 23) } - end - - def test_with_sequence - assert_equal 'widgets_seq', Widget.versioned_class.sequence_name - 3.times { Widget.create! :name => 'new widget' } - assert_equal 3, Widget.count - assert_equal 3, Widget.versioned_class.count - end - - def test_has_many_through - assert_equal [authors(:caged), authors(:mly)], pages(:welcome).authors - end - - def test_has_many_through_with_custom_association - assert_equal [authors(:caged), authors(:mly)], pages(:welcome).revisors - end - - def test_referential_integrity - pages(:welcome).destroy - assert_equal 0, Page.count - assert_equal 0, Page::Version.count - end - - def test_association_options - association = Page.reflect_on_association(:versions) - options = association.options - assert_equal :delete_all, options[:dependent] - assert_equal 'version', options[:order] - - association = Widget.reflect_on_association(:versions) - options = association.options - assert_equal :nullify, options[:dependent] - assert_equal 'version desc', options[:order] - assert_equal 'widget_id', options[:foreign_key] - - widget = Widget.create! :name => 'new widget' - assert_equal 1, Widget.count - assert_equal 1, Widget.versioned_class.count - widget.destroy - assert_equal 0, Widget.count - assert_equal 1, Widget.versioned_class.count - end - - def test_versioned_records_should_belong_to_parent - page = pages(:welcome) - page_version = page.versions.last - assert_equal page, page_version.page - end - - def test_unaltered_attributes - landmarks(:washington).attributes = landmarks(:washington).attributes.except("id") - assert !landmarks(:washington).changed? - end - - def test_unchanged_string_attributes - landmarks(:washington).attributes = landmarks(:washington).attributes.except("id").inject({}) { |params, (key, value)| params.update(key => value.to_s) } - assert !landmarks(:washington).changed? - end - - def test_should_find_earliest_version - assert_equal page_versions(:welcome_1), pages(:welcome).versions.earliest - end - - def test_should_find_latest_version - assert_equal page_versions(:welcome_2), pages(:welcome).versions.latest - end - - def test_should_find_previous_version - assert_equal page_versions(:welcome_1), page_versions(:welcome_2).previous - assert_equal page_versions(:welcome_1), pages(:welcome).versions.before(page_versions(:welcome_2)) - end - - def test_should_find_next_version - assert_equal page_versions(:welcome_2), page_versions(:welcome_1).next - assert_equal page_versions(:welcome_2), pages(:welcome).versions.after(page_versions(:welcome_1)) - end - - def test_should_find_version_count - assert_equal 24, pages(:welcome).versions_count - assert_equal 24, page_versions(:welcome_1).versions_count - assert_equal 24, page_versions(:welcome_2).versions_count - end -end \ No newline at end of file From 81e97d23a8307eb410b579eb8ea821de23ee22ed Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Wed, 4 Aug 2010 19:02:49 +0200 Subject: [PATCH 049/777] fix document activity url --- app/models/document.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/document.rb b/app/models/document.rb index 414772ea..fc5d15dd 100644 --- a/app/models/document.rb +++ b/app/models/document.rb @@ -21,7 +21,7 @@ class Document < ActiveRecord::Base acts_as_attachable :delete_permission => :manage_documents acts_as_journalized :event_title => Proc.new {|o| "#{l(:label_document)}: #{o.title}"}, - :event_url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.id} }, + :event_url => Proc.new {|o| {:controller => 'documents', :action => 'show', :id => o.versioned_id}}, :event_author => (Proc.new do |o| o.attachments.find(:first, :order => "#{Attachment.table_name}.created_on ASC").try(:author) end) From 1f9eda4e0df55310c9e3fe3ff3806af4dd4a9809 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 5 Aug 2010 19:05:04 +0200 Subject: [PATCH 050/777] update tests to work with the new data model, where neccessary --- app/models/attachment.rb | 20 +- app/models/issue.rb | 10 +- app/models/mail_handler.rb | 56 ++-- app/models/mailer.rb | 1 + app/models/message.rb | 3 +- app/models/wiki_content.rb | 3 +- app/views/mailer/issue_edit.text.html.rhtml | 2 +- app/views/mailer/issue_edit.text.plain.rhtml | 2 +- db/migrate/041_rename_comment_to_comments.rb | 2 +- lib/redmine/activity/fetcher.rb | 12 +- test/fixtures/journal_details.yml | 22 -- test/fixtures/journals.yml | 193 +++++++++-- test/fixtures/wiki_content_versions.yml | 56 ---- test/fixtures/wiki_contents.yml | 51 ++- test/functional/issues_controller_test.rb | 314 +++++++++--------- .../issues_controller_transaction_test.rb | 3 +- test/functional/journals_controller_test.rb | 4 +- test/functional/projects_controller_test.rb | 2 +- test/functional/wiki_controller_test.rb | 72 ++-- test/integration/issues_api_test.rb | 1 - test/integration/projects_api_test.rb | 2 +- test/test_helper.rb | 36 +- test/unit/activity_test.rb | 30 +- test/unit/issue_test.rb | 175 +++++----- test/unit/journal_test.rb | 14 +- test/unit/mail_handler_test.rb | 2 +- test/unit/mailer_test.rb | 4 +- test/unit/search_test.rb | 1 - test/unit/wiki_content_test.rb | 28 +- test/unit/wiki_page_test.rb | 41 +-- test/unit/wiki_test.rb | 20 +- .../lib/acts_as_activity_provider.rb | 6 +- 32 files changed, 644 insertions(+), 544 deletions(-) delete mode 100644 test/fixtures/journal_details.yml delete mode 100644 test/fixtures/wiki_content_versions.yml diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 669dc55c..502e529c 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -19,8 +19,14 @@ require "digest/md5" class Attachment < ActiveRecord::Base belongs_to :container, :polymorphic => true + + # FIXME: Remove these once the Versions, Documents and Projects themselves can provide file events + belongs_to :version, :foreign_key => "container_id" + belongs_to :document, :foreign_key => "container_id" + belongs_to :project, :foreign_key => "container_id" + belongs_to :author, :class_name => "User", :foreign_key => "author_id" - + validates_presence_of :container, :filename, :author validates_length_of :filename, :maximum => 255 validates_length_of :disk_filename, :maximum => 255 @@ -31,16 +37,24 @@ class Attachment < ActiveRecord::Base :id => o.versioned_id, :filename => o.filename } end), :activity_type => 'files', - :activity_permission => :view_files + :activity_permission => :view_files, + :activity_find_options => { :include => { :version => :project } } - acts_as_activity :type => 'documents', :permission => :view_documents + acts_as_activity :type => 'documents', :permission => :view_documents, + :find_options => { :include => { :document => :project } } + # This method is called on save by the AttachmentJournal in order to + # decide which kind of activity we are dealing with. When that activity + # is retrieved later, we don't need to check the container_type in + # SQL anymore as that will be just the one we have specified here. def activity_type case container_type when "Document" "documents" when "Version" "files" + when "Project" + "files" else super end diff --git a/app/models/issue.rb b/app/models/issue.rb index 72443107..45446588 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -774,6 +774,14 @@ class Issue < ActiveRecord::Base and i.project_id=#{project.id} group by s.id, s.is_closed, j.id") end - + + IssueJournal.class_eval do + # Shortcut + def new_status + if details.keys.include? 'status_id' + (newval = details['status_id'].last) ? IssueStatus.find_by_id(newval.to_i) : nil + end + end + end end diff --git a/app/models/mail_handler.rb b/app/models/mail_handler.rb index ad71f756..c620c9dc 100644 --- a/app/models/mail_handler.rb +++ b/app/models/mail_handler.rb @@ -5,12 +5,12 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -20,25 +20,25 @@ class MailHandler < ActionMailer::Base class UnauthorizedAction < StandardError; end class MissingInformation < StandardError; end - + attr_reader :email, :user def self.receive(email, options={}) @@handler_options = options.dup - + @@handler_options[:issue] ||= {} - + @@handler_options[:allow_override] = @@handler_options[:allow_override].split(',').collect(&:strip) if @@handler_options[:allow_override].is_a?(String) @@handler_options[:allow_override] ||= [] # Project needs to be overridable if not specified @@handler_options[:allow_override] << 'project' unless @@handler_options[:issue].has_key?(:project) # Status overridable by default - @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status) - + @@handler_options[:allow_override] << 'status' unless @@handler_options[:issue].has_key?(:status) + @@handler_options[:no_permission_check] = (@@handler_options[:no_permission_check].to_s == '1' ? true : false) super email end - + # Processes incoming emails # Returns the created object (eg. an issue, a message) or false def receive(email) @@ -77,13 +77,13 @@ class MailHandler < ActionMailer::Base User.current = @user dispatch end - + private MESSAGE_ID_RE = %r{^ true) start_date = get_keyword(:start_date, :override => true) assigned_to = (get_keyword(:assigned_to, :override => true) && find_user_from_keyword(get_keyword(:assigned_to, :override => true))) - + issue = Issue.find_by_id(issue_id) return unless issue # check permission @@ -188,16 +188,16 @@ class MailHandler < ActionMailer::Base issue.start_date = start_date if start_date issue.due_date = due_date if due_date issue.assigned_to = assigned_to if assigned_to - + issue.save! logger.info "MailHandler: issue ##{issue.id} updated by #{user}" if logger && logger.info journal end - + # Reply will be added to the issue def receive_journal_reply(journal_id) journal = Journal.find_by_id(journal_id) - if journal && journal.versioned.is_a? Issue + if journal and journal.versioned.is_a? Issue receive_issue_reply(journal.versioned_id) end end @@ -207,11 +207,11 @@ class MailHandler < ActionMailer::Base message = Message.find_by_id(message_id) if message message = message.root - + unless @@handler_options[:no_permission_check] raise UnauthorizedAction unless user.allowed_to?(:add_messages, message.project) end - + if !message.locked? reply = Message.new(:subject => email.subject.gsub(%r{^.*msg\d+\]}, '').strip, :content => cleaned_up_text_body) @@ -225,7 +225,7 @@ class MailHandler < ActionMailer::Base end end end - + def add_attachments(obj) if email.has_attachments? email.attachments.each do |attachment| @@ -236,7 +236,7 @@ class MailHandler < ActionMailer::Base end end end - + # Adds To and Cc as watchers of the given object if the sender has the # appropriate permission def add_watchers(obj) @@ -248,7 +248,7 @@ class MailHandler < ActionMailer::Base end end end - + def get_keyword(attr, options={}) @keywords ||= {} if @keywords.has_key?(attr) @@ -263,7 +263,7 @@ class MailHandler < ActionMailer::Base end end end - + # Returns the text/plain part of the email # If not found (eg. HTML-only email), returns the body with tags removed def plain_text_body @@ -284,7 +284,7 @@ class MailHandler < ActionMailer::Base @plain_text_body.strip! @plain_text_body end - + def cleaned_up_text_body cleanup_body(plain_text_body) end @@ -292,19 +292,19 @@ class MailHandler < ActionMailer::Base def self.full_sanitizer @full_sanitizer ||= HTML::FullSanitizer.new end - + # Creates a user account for the +email+ sender def self.create_user_from_email(email) addr = email.from_addrs.to_a.first if addr && !addr.spec.blank? user = User.new user.mail = addr.spec - + names = addr.name.blank? ? addr.spec.gsub(/@.*$/, '').split('.') : addr.name.split user.firstname = names.shift user.lastname = names.join(' ') user.lastname = '-' if user.lastname.blank? - + user.login = user.mail user.password = ActiveSupport::SecureRandom.hex(5) user.language = Setting.default_language @@ -313,7 +313,7 @@ class MailHandler < ActionMailer::Base end private - + # Removes the email body of text after the truncation configurations. def cleanup_body(body) delimiters = Setting.mail_handler_body_delimiters.to_s.split(/[\r\n]+/).reject(&:blank?).map {|s| Regexp.escape(s)} diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 83d7b7c1..cebd83e3 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -19,6 +19,7 @@ class Mailer < ActionMailer::Base layout 'mailer' helper :application helper :issues + helper :journals helper :custom_fields include ActionController::UrlWriter diff --git a/app/models/message.rb b/app/models/message.rb index b36119a6..5eae0654 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -31,7 +31,8 @@ class Message < ActiveRecord::Base else {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"} end.reverse_merge :controller => 'messages', :action => 'show', :board_id => o.board_id - end) + end), + :activity_find_options => { :include => { :board => :project } } acts_as_searchable :columns => ['subject', 'content'], :include => {:board => :project}, diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb index aeeec1e6..a2e4dcaf 100644 --- a/app/models/wiki_content.rb +++ b/app/models/wiki_content.rb @@ -27,7 +27,8 @@ class WikiContent < ActiveRecord::Base :event_title => Proc.new {|o| "#{l(:label_wiki_edit)}: #{o.page.title} (##{o.version})"}, :event_url => Proc.new {|o| {:controller => 'wiki', :id => o.page.wiki.project_id, :page => o.page.title, :version => o.version}}, :activity_type => 'wiki_edits', - :activity_permission => :view_wiki_edits + :activity_permission => :view_wiki_edits, + :activity_find_options => { :include => { :page => { :wiki => :project } } } def activity_type 'wiki_edits' diff --git a/app/views/mailer/issue_edit.text.html.rhtml b/app/views/mailer/issue_edit.text.html.rhtml index 05c67208..0a8a0252 100644 --- a/app/views/mailer/issue_edit.text.html.rhtml +++ b/app/views/mailer/issue_edit.text.html.rhtml @@ -2,7 +2,7 @@
      <% for detail in @journal.details %> -
    • <%= show_detail(detail, true) %>
    • +
    • <%= @journal.render_detail(detail, true) %>
    • <% end %>
    diff --git a/app/views/mailer/issue_edit.text.plain.rhtml b/app/views/mailer/issue_edit.text.plain.rhtml index 870f8fa3..fc6645d1 100644 --- a/app/views/mailer/issue_edit.text.plain.rhtml +++ b/app/views/mailer/issue_edit.text.plain.rhtml @@ -1,7 +1,7 @@ <%= l(:text_issue_updated, :id => "##{@issue.id}", :author => @journal.user) %> <% for detail in @journal.details -%> -<%= show_detail(detail, true) %> +<%= @journal.render_detail(detail, true) %> <% end -%> <%= @journal.notes if @journal.notes? %> diff --git a/db/migrate/041_rename_comment_to_comments.rb b/db/migrate/041_rename_comment_to_comments.rb index 93677e57..fdacff93 100644 --- a/db/migrate/041_rename_comment_to_comments.rb +++ b/db/migrate/041_rename_comment_to_comments.rb @@ -2,7 +2,7 @@ class RenameCommentToComments < ActiveRecord::Migration def self.up rename_column(:comments, :comment, :comments) if ActiveRecord::Base.connection.columns(Comment.table_name).detect{|c| c.name == "comment"} rename_column(:wiki_contents, :comment, :comments) if ActiveRecord::Base.connection.columns(WikiContent.table_name).detect{|c| c.name == "comment"} - rename_column(:wiki_content_versions, :comment, :comments) if ActiveRecord::Base.connection.columns(WikiContent.versioned_table_name).detect{|c| c.name == "comment"} + rename_column(:wiki_content_versions, :comment, :comments) if ActiveRecord::Base.connection.columns("wiki_content_versions").detect{|c| c.name == "comment"} rename_column(:time_entries, :comment, :comments) if ActiveRecord::Base.connection.columns(TimeEntry.table_name).detect{|c| c.name == "comment"} rename_column(:changesets, :comment, :comments) if ActiveRecord::Base.connection.columns(Changeset.table_name).detect{|c| c.name == "comment"} end diff --git a/lib/redmine/activity/fetcher.rb b/lib/redmine/activity/fetcher.rb index 6dca3275..8fa339c2 100644 --- a/lib/redmine/activity/fetcher.rb +++ b/lib/redmine/activity/fetcher.rb @@ -36,13 +36,13 @@ module Redmine # Returns an array of available event types def event_types return @event_types unless @event_types.nil? - + @event_types = Redmine::Activity.available_event_types - @event_types = @event_types.select do |o| - permissions = constantized_providers(o).collect do |p| - p.activity_provider_options[o].try(:[], :permission) - end.compact - if @project + if @project + @event_types = @event_types.select do |o| + permissions = constantized_providers(o).collect do |p| + p.activity_provider_options[o].try(:[], :permission) + end.compact return @user.allowed_to?("view_#{o}".to_sym, @project) if permissions.blank? permissions.all? {|p| @user.allowed_to?(p, @project) } if @project end diff --git a/test/fixtures/journal_details.yml b/test/fixtures/journal_details.yml deleted file mode 100644 index 046202dd..00000000 --- a/test/fixtures/journal_details.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- -journal_details_001: - old_value: "1" - property: attr - id: 1 - value: "2" - prop_key: status_id - journal_id: 1 -journal_details_002: - old_value: "40" - property: attr - id: 2 - value: "30" - prop_key: done_ratio - journal_id: 1 -journal_details_003: - old_value: nil - property: attr - id: 3 - value: "6" - prop_key: fixed_version_id - journal_id: 4 diff --git a/test/fixtures/journals.yml b/test/fixtures/journals.yml index 48280f84..a113d0f7 100644 --- a/test/fixtures/journals.yml +++ b/test/fixtures/journals.yml @@ -1,29 +1,180 @@ ---- -journals_001: - created_on: <%= 2.days.ago.to_date.to_s(:db) %> - notes: "Journal notes" +--- +journals_001: id: 1 - journalized_type: Issue + type: "IssueJournal" + activity_type: "issues" + created_at: <%= 2.days.ago.to_date.to_s(:db) %> + version: 1 user_id: 1 - journalized_id: 1 -journals_002: - created_on: <%= 1.days.ago.to_date.to_s(:db) %> - notes: "Some notes with Redmine links: #2, r2." + notes: "Journal notes" + versioned_id: 1 + changes: | + --- + status_id: + - 1 + - 2 + done_ratio: + - 40 + - 30 +journals_002: id: 2 - journalized_type: Issue + type: "IssueJournal" + activity_type: "issues" + created_at: <%= 1.days.ago.to_date.to_s(:db) %> + version: 2 user_id: 2 - journalized_id: 1 -journals_003: - created_on: <%= 1.days.ago.to_date.to_s(:db) %> - notes: "A comment with inline image: !picture.jpg!" + notes: "Some notes with Redmine links: #2, r2." + versioned_id: 1 + changes: "--- {}" +journals_003: id: 3 - journalized_type: Issue + type: "IssueJournal" + activity_type: "issues" + created_at: <%= 1.days.ago.to_date.to_s(:db) %> + version: 1 user_id: 2 - journalized_id: 2 -journals_004: - created_on: <%= 1.days.ago.to_date.to_s(:db) %> - notes: "A comment with a private version." + notes: "A comment with inline image: !picture.jpg!" + versioned_id: 2 + changes: "--- {}" +journals_004: id: 4 - journalized_type: Issue + type: "IssueJournal" + activity_type: "issues" + created_at: <%= 1.days.ago.to_date.to_s(:db) %> + version: 1 + user_id: 2 + notes: "A comment with a private version." + versioned_id: 6 + changes: | + --- + fixed_version_id: + - + - 6 +journals_005: + id: 5 + type: "IssueJournal" + activity_type: "issues" + created_at: <%= 1.days.ago.to_date.to_s(:db) %> + version: 0 user_id: 1 - journalized_id: 6 + notes: + versioned_id: 5 + changes: "--- {}" +journals_006: + id: 6 + type: "WikiContentJournal" + activity_type: "wiki_edits" + created_at: 2007-03-07 00:08:07 +01:00 + version: 1 + user_id: 2 + notes: Page creation + versioned_id: 1 + changes: | + --- + compression: "" + data: |- + h1. CookBook documentation + + + + Some [[documentation]] here... +journals_007: + id: 7 + type: "WikiContentJournal" + activity_type: "wiki_edits" + created_at: 2007-03-07 00:08:34 +01:00 + version: 2 + user_id: 1 + notes: Small update + versioned_id: 1 + changes: | + --- + compression: "" + data: |- + h1. CookBook documentation + + + + Some updated [[documentation]] here... +journals_008: + id: 8 + type: "WikiContentJournal" + activity_type: "wiki_edits" + created_at: 2007-03-07 00:10:51 +01:00 + version: 3 + user_id: 1 + notes: "" + versioned_id: 1 + changes: | + --- + compression: "" + data: |- + h1. CookBook documentation + Some updated [[documentation]] here... +journals_009: + id: 9 + type: "WikiContentJournal" + activity_type: "wiki_edits" + created_at: 2007-03-08 00:18:07 +01:00 + version: 1 + user_id: 1 + notes: + versioned_id: 2 + changes: | + --- + data: |- + h1. Another page + + This is a link to a ticket: #2 + + +journals_010: + id: 10 + type: "MessageJournal" + activity_type: "messages" + created_at: <%= 2.days.ago.to_date.to_s(:db) %> + version: 1 + user_id: 1 + notes: + versioned_id: 5 + changes: --- {} +journals_011: + id: 11 + type: "AttachmentJournal" + activity_type: "files" + created_at: <%= 2.days.ago.to_date.to_s(:db) %> + version: 1 + user_id: 2 + notes: "An attachment on a version" + versioned_id: 9 + changes: --- {} +journals_012: + id: 12 + type: "AttachmentJournal" + activity_type: "files" + created_at: <%= 2.days.ago.to_date.to_s(:db) %> + version: 1 + user_id: 2 + notes: "An attachment on a project" + versioned_id: 8 + changes: --- {} +journals_013: + id: 13 + type: "AttachmentJournal" + activity_type: "files" + created_at: <%= 2.days.ago.to_date.to_s(:db) %> + version: 1 + user_id: 2 + notes: "An attachment on an issue" + versioned_id: 7 + changes: --- {} +journals_014: + id: 14 + type: "AttachmentJournal" + activity_type: "documents" + created_at: <%= 2.days.ago.to_date.to_s(:db) %> + version: 1 + user_id: 2 + notes: "An attachment on a document" + versioned_id: 2 + changes: --- {} \ No newline at end of file diff --git a/test/fixtures/wiki_content_versions.yml b/test/fixtures/wiki_content_versions.yml deleted file mode 100644 index 652f0fb3..00000000 --- a/test/fixtures/wiki_content_versions.yml +++ /dev/null @@ -1,56 +0,0 @@ ---- -wiki_content_versions_001: - updated_on: 2007-03-07 00:08:07 +01:00 - page_id: 1 - id: 1 - version: 1 - author_id: 2 - comments: Page creation - wiki_content_id: 1 - compression: "" - data: |- - h1. CookBook documentation - - - - Some [[documentation]] here... -wiki_content_versions_002: - updated_on: 2007-03-07 00:08:34 +01:00 - page_id: 1 - id: 2 - version: 2 - author_id: 1 - comments: Small update - wiki_content_id: 1 - compression: "" - data: |- - h1. CookBook documentation - - - - Some updated [[documentation]] here... -wiki_content_versions_003: - updated_on: 2007-03-07 00:10:51 +01:00 - page_id: 1 - id: 3 - version: 3 - author_id: 1 - comments: "" - wiki_content_id: 1 - compression: "" - data: |- - h1. CookBook documentation - Some updated [[documentation]] here... -wiki_content_versions_004: - data: |- - h1. Another page - - This is a link to a ticket: #2 - updated_on: 2007-03-08 00:18:07 +01:00 - page_id: 2 - wiki_content_id: 2 - id: 4 - version: 1 - author_id: 1 - comments: - diff --git a/test/fixtures/wiki_contents.yml b/test/fixtures/wiki_contents.yml index e0bf1991..d1be82cc 100644 --- a/test/fixtures/wiki_contents.yml +++ b/test/fixtures/wiki_contents.yml @@ -9,10 +9,10 @@ wiki_contents_001: updated_on: 2007-03-07 00:10:51 +01:00 page_id: 1 id: 1 - version: 3 + lock_version: 3 author_id: 1 comments: Gzip compression activated -wiki_contents_002: +wiki_contents_002: text: |- h1. Another page @@ -22,10 +22,10 @@ wiki_contents_002: updated_on: 2007-03-08 00:18:07 +01:00 page_id: 2 id: 2 - version: 1 + lock_version: 1 author_id: 1 - comments: -wiki_contents_003: + comments: +wiki_contents_003: text: |- h1. Start page @@ -33,10 +33,10 @@ wiki_contents_003: updated_on: 2007-03-08 00:18:07 +01:00 page_id: 3 id: 3 - version: 1 + lock_version: 1 author_id: 1 - comments: -wiki_contents_004: + comments: +wiki_contents_004: text: |- h1. Page with an inline image @@ -46,10 +46,10 @@ wiki_contents_004: updated_on: 2007-03-08 00:18:07 +01:00 page_id: 4 id: 4 - version: 1 + lock_version: 1 author_id: 1 - comments: -wiki_contents_005: + comments: +wiki_contents_005: text: |- h1. Child page 1 @@ -57,10 +57,10 @@ wiki_contents_005: updated_on: 2007-03-08 00:18:07 +01:00 page_id: 5 id: 5 - version: 1 + lock_version: 1 author_id: 1 - comments: -wiki_contents_006: + comments: +wiki_contents_006: text: |- h1. Child page 2 @@ -68,31 +68,30 @@ wiki_contents_006: updated_on: 2007-03-08 00:18:07 +01:00 page_id: 6 id: 6 - version: 1 + lock_version: 1 author_id: 1 - comments: -wiki_contents_007: + comments: +wiki_contents_007: text: This is a child page updated_on: 2007-03-08 00:18:07 +01:00 page_id: 7 id: 7 - version: 1 + lock_version: 1 author_id: 1 - comments: -wiki_contents_008: + comments: +wiki_contents_008: text: This is a parent page updated_on: 2007-03-08 00:18:07 +01:00 page_id: 8 id: 8 - version: 1 + lock_version: 1 author_id: 1 - comments: -wiki_contents_009: + comments: +wiki_contents_009: text: This is a child page updated_on: 2007-03-08 00:18:07 +01:00 page_id: 9 id: 9 - version: 1 + lock_version: 1 author_id: 1 - comments: - \ No newline at end of file + comments: diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 670fb2d7..4b40ef3e 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -5,12 +5,12 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -43,19 +43,18 @@ class IssuesControllerTest < ActionController::TestCase :custom_fields_trackers, :time_entries, :journals, - :journal_details, :queries - + def setup @controller = IssuesController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_index Setting.default_language = 'en' - + get :index assert_response :success assert_template 'index.rhtml' @@ -69,7 +68,7 @@ class IssuesControllerTest < ActionController::TestCase # project column assert_tag :tag => 'th', :content => /Project/ end - + def test_index_should_not_list_issues_when_module_disabled EnabledModule.delete_all("name = 'issue_tracking' AND project_id = 1") get :index @@ -91,7 +90,7 @@ class IssuesControllerTest < ActionController::TestCase assert_no_tag :tag => 'a', :content => /Can't print recipes/ assert_tag :tag => 'a', :content => /Subproject issue/ end - + def test_index_with_project Setting.display_subprojects_issues = 0 get :index, :project_id => 1 @@ -101,7 +100,7 @@ class IssuesControllerTest < ActionController::TestCase assert_tag :tag => 'a', :content => /Can't print recipes/ assert_no_tag :tag => 'a', :content => /Subproject issue/ end - + def test_index_with_project_and_subprojects Setting.display_subprojects_issues = 1 get :index, :project_id => 1 @@ -112,7 +111,7 @@ class IssuesControllerTest < ActionController::TestCase assert_tag :tag => 'a', :content => /Subproject issue/ assert_no_tag :tag => 'a', :content => /Issue of a private subproject/ end - + def test_index_with_project_and_subprojects_should_show_private_subprojects @request.session[:user_id] = 2 Setting.display_subprojects_issues = 1 @@ -124,14 +123,14 @@ class IssuesControllerTest < ActionController::TestCase assert_tag :tag => 'a', :content => /Subproject issue/ assert_tag :tag => 'a', :content => /Issue of a private subproject/ end - + def test_index_with_project_and_filter get :index, :project_id => 1, :set_filter => 1 assert_response :success assert_template 'index.rhtml' assert_not_nil assigns(:issues) end - + def test_index_with_query get :index, :project_id => 1, :query_id => 5 assert_response :success @@ -139,7 +138,7 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:issues) assert_nil assigns(:issue_count_by_group) end - + def test_index_with_query_grouped_by_tracker get :index, :project_id => 1, :query_id => 6 assert_response :success @@ -147,7 +146,7 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:issues) assert_not_nil assigns(:issue_count_by_group) end - + def test_index_with_query_grouped_by_list_custom_field get :index, :project_id => 1, :query_id => 9 assert_response :success @@ -155,15 +154,15 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:issues) assert_not_nil assigns(:issue_count_by_group) end - + def test_index_sort_by_field_not_included_in_columns Setting.issue_list_default_columns = %w(subject author) get :index, :sort => 'tracker' end - + def test_index_csv_with_project Setting.default_language = 'en' - + get :index, :format => 'csv' assert_response :success assert_not_nil assigns(:issues) @@ -175,24 +174,24 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:issues) assert_equal 'text/csv', @response.content_type end - + def test_index_pdf get :index, :format => 'pdf' assert_response :success assert_not_nil assigns(:issues) assert_equal 'application/pdf', @response.content_type - + get :index, :project_id => 1, :format => 'pdf' assert_response :success assert_not_nil assigns(:issues) assert_equal 'application/pdf', @response.content_type - + get :index, :project_id => 1, :query_id => 6, :format => 'pdf' assert_response :success assert_not_nil assigns(:issues) assert_equal 'application/pdf', @response.content_type end - + def test_index_pdf_with_query_grouped_by_list_custom_field get :index, :project_id => 1, :query_id => 9, :format => 'pdf' assert_response :success @@ -200,31 +199,31 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:issue_count_by_group) assert_equal 'application/pdf', @response.content_type end - + def test_index_sort get :index, :sort => 'tracker,id:desc' assert_response :success - + sort_params = @request.session['issues_index_sort'] assert sort_params.is_a?(String) assert_equal 'tracker,id:desc', sort_params - + issues = assigns(:issues) assert_not_nil issues assert !issues.empty? assert_equal issues.sort {|a,b| a.tracker == b.tracker ? b.id <=> a.id : a.tracker <=> b.tracker }.collect(&:id), issues.collect(&:id) end - + def test_index_with_columns columns = ['tracker', 'subject', 'assigned_to'] get :index, :set_filter => 1, :query => { 'column_names' => columns} assert_response :success - + # query should use specified columns query = assigns(:query) assert_kind_of Query, query assert_equal columns, query.column_names.map(&:to_s) - + # columns should be stored in session assert_kind_of Hash, session[:query] assert_kind_of Array, session[:query][:column_names] @@ -237,73 +236,73 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:journals) assert_equal 'application/atom+xml', @response.content_type end - + def test_show_by_anonymous get :show, :id => 1 assert_response :success assert_template 'show.rhtml' assert_not_nil assigns(:issue) assert_equal Issue.find(1), assigns(:issue) - + # anonymous role is allowed to add a note assert_tag :tag => 'form', :descendant => { :tag => 'fieldset', - :child => { :tag => 'legend', + :child => { :tag => 'legend', :content => /Notes/ } } end - + def test_show_by_manager @request.session[:user_id] = 2 get :show, :id => 1 assert_response :success - + assert_tag :tag => 'form', :descendant => { :tag => 'fieldset', - :child => { :tag => 'legend', + :child => { :tag => 'legend', :content => /Change properties/ } }, :descendant => { :tag => 'fieldset', - :child => { :tag => 'legend', + :child => { :tag => 'legend', :content => /Log time/ } }, :descendant => { :tag => 'fieldset', - :child => { :tag => 'legend', + :child => { :tag => 'legend', :content => /Notes/ } } end - + def test_show_should_deny_anonymous_access_without_permission Role.anonymous.remove_permission!(:view_issues) get :show, :id => 1 assert_response :redirect end - + def test_show_should_deny_non_member_access_without_permission Role.non_member.remove_permission!(:view_issues) @request.session[:user_id] = 9 get :show, :id => 1 assert_response 403 end - + def test_show_should_deny_member_access_without_permission Role.find(1).remove_permission!(:view_issues) @request.session[:user_id] = 2 get :show, :id => 1 assert_response 403 end - + def test_show_should_not_disclose_relations_to_invisible_issues Setting.cross_project_issue_relations = '1' IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => 'relates') # Relation to a private project issue IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(4), :relation_type => 'relates') - + get :show, :id => 1 assert_response :success - + assert_tag :div, :attributes => { :id => 'relations' }, :descendant => { :tag => 'a', :content => /#2$/ } assert_no_tag :div, :attributes => { :id => 'relations' }, :descendant => { :tag => 'a', :content => /#4$/ } end - + def test_show_atom get :show, :id => 2, :format => 'atom' assert_response :success @@ -311,7 +310,7 @@ class IssuesControllerTest < ActionController::TestCase # Inline image assert_select 'content', :text => Regexp.new(Regexp.quote('http://test.host/attachments/download/10')) end - + def test_show_export_to_pdf get :show, :id => 3, :format => 'pdf' assert_response :success @@ -325,7 +324,7 @@ class IssuesControllerTest < ActionController::TestCase get :new, :project_id => 1, :tracker_id => 1 assert_response :success assert_template 'new' - + assert_tag :tag => 'input', :attributes => { :name => 'issue[custom_field_values][2]', :value => 'Default string' } end @@ -335,55 +334,55 @@ class IssuesControllerTest < ActionController::TestCase get :new, :project_id => 1 assert_response :success assert_template 'new' - + issue = assigns(:issue) assert_not_nil issue assert_equal Project.find(1).trackers.first, issue.tracker end - + def test_get_new_with_no_default_status_should_display_an_error @request.session[:user_id] = 2 IssueStatus.delete_all - + get :new, :project_id => 1 assert_response 500 assert_not_nil flash[:error] assert_tag :tag => 'div', :attributes => { :class => /error/ }, :content => /No default issue/ end - + def test_get_new_with_no_tracker_should_display_an_error @request.session[:user_id] = 2 Tracker.delete_all - + get :new, :project_id => 1 assert_response 500 assert_not_nil flash[:error] assert_tag :tag => 'div', :attributes => { :class => /error/ }, :content => /No tracker/ end - + def test_update_new_form @request.session[:user_id] = 2 xhr :post, :update_form, :project_id => 1, - :issue => {:tracker_id => 2, + :issue => {:tracker_id => 2, :subject => 'This is the test_new issue', :description => 'This is the description', :priority_id => 5} assert_response :success assert_template 'attributes' - + issue = assigns(:issue) assert_kind_of Issue, issue assert_equal 1, issue.project_id assert_equal 2, issue.tracker_id assert_equal 'This is the test_new issue', issue.subject end - + def test_post_create @request.session[:user_id] = 2 assert_difference 'Issue.count' do - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 3, :status_id => 2, :subject => 'This is the test_new issue', @@ -393,7 +392,7 @@ class IssuesControllerTest < ActionController::TestCase :custom_field_values => {'2' => 'Value for field 2'}} end assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id - + issue = Issue.find_by_subject('This is the test_new issue') assert_not_nil issue assert_equal 2, issue.author_id @@ -404,21 +403,21 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil v assert_equal 'Value for field 2', v.value end - + def test_post_create_and_continue @request.session[:user_id] = 2 - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 3, :subject => 'This is first issue', :priority_id => 5}, :continue => '' assert_redirected_to :controller => 'issues', :action => 'new', :issue => {:tracker_id => 3} end - + def test_post_create_without_custom_fields_param @request.session[:user_id] = 2 assert_difference 'Issue.count' do - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 1, :subject => 'This is the test_new issue', :description => 'This is the description', @@ -432,7 +431,7 @@ class IssuesControllerTest < ActionController::TestCase field.update_attribute(:is_required, true) @request.session[:user_id] = 2 - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 1, :subject => 'This is the test_new issue', :description => 'This is the description', @@ -443,13 +442,13 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil issue assert_equal I18n.translate('activerecord.errors.messages.invalid'), issue.errors.on(:custom_values) end - + def test_post_create_with_watchers @request.session[:user_id] = 2 ActionMailer::Base.deliveries.clear - + assert_difference 'Watcher.count', 2 do - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 1, :subject => 'This is a new issue with watchers', :description => 'This is the description', @@ -459,7 +458,7 @@ class IssuesControllerTest < ActionController::TestCase issue = Issue.find_by_subject('This is a new issue with watchers') assert_not_nil issue assert_redirected_to :controller => 'issues', :action => 'show', :id => issue - + # Watchers added assert_equal [2, 3], issue.watcher_user_ids.sort assert issue.watched_by?(User.find(3)) @@ -468,12 +467,12 @@ class IssuesControllerTest < ActionController::TestCase assert_kind_of TMail::Mail, mail assert [mail.bcc, mail.cc].flatten.include?(User.find(3).mail) end - + def test_post_create_subissue @request.session[:user_id] = 2 - + assert_difference 'Issue.count' do - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 1, :subject => 'This is a child issue', :parent_issue_id => 2} @@ -482,12 +481,12 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil issue assert_equal Issue.find(2), issue.parent end - + def test_post_create_should_send_a_notification ActionMailer::Base.deliveries.clear @request.session[:user_id] = 2 assert_difference 'Issue.count' do - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 3, :subject => 'This is the test_new issue', :description => 'This is the description', @@ -496,13 +495,13 @@ class IssuesControllerTest < ActionController::TestCase :custom_field_values => {'2' => 'Value for field 2'}} end assert_redirected_to :controller => 'issues', :action => 'show', :id => Issue.last.id - + assert_equal 1, ActionMailer::Base.deliveries.size end - + def test_post_create_should_preserve_fields_values_on_validation_failure @request.session[:user_id] = 2 - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 1, # empty subject :subject => '', @@ -511,35 +510,35 @@ class IssuesControllerTest < ActionController::TestCase :custom_field_values => {'1' => 'Oracle', '2' => 'Value for field 2'}} assert_response :success assert_template 'new' - + assert_tag :textarea, :attributes => { :name => 'issue[description]' }, :content => 'This is a description' assert_tag :select, :attributes => { :name => 'issue[priority_id]' }, :child => { :tag => 'option', :attributes => { :selected => 'selected', :value => '6' }, - :content => 'High' } + :content => 'High' } # Custom fields assert_tag :select, :attributes => { :name => 'issue[custom_field_values][1]' }, :child => { :tag => 'option', :attributes => { :selected => 'selected', :value => 'Oracle' }, - :content => 'Oracle' } + :content => 'Oracle' } assert_tag :input, :attributes => { :name => 'issue[custom_field_values][2]', :value => 'Value for field 2'} end - + def test_post_create_should_ignore_non_safe_attributes @request.session[:user_id] = 2 assert_nothing_raised do post :create, :project_id => 1, :issue => { :tracker => "A param can not be a Tracker" } end end - + context "without workflow privilege" do setup do Workflow.delete_all(["role_id = ?", Role.anonymous.id]) Role.anonymous.add_permission! :add_issues end - + context "#new" do should "propose default status only" do get :new, :project_id => 1 @@ -550,10 +549,10 @@ class IssuesControllerTest < ActionController::TestCase :children => {:count => 1}, :child => {:tag => 'option', :attributes => {:value => IssueStatus.default.id.to_s}} end - + should "accept default status" do assert_difference 'Issue.count' do - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 1, :subject => 'This is an issue', :status_id => 1} @@ -561,10 +560,10 @@ class IssuesControllerTest < ActionController::TestCase issue = Issue.last(:order => 'id') assert_equal IssueStatus.default, issue.status end - + should "ignore unauthorized status" do assert_difference 'Issue.count' do - post :create, :project_id => 1, + post :create, :project_id => 1, :issue => {:tracker_id => 1, :subject => 'This is an issue', :status_id => 3} @@ -574,7 +573,7 @@ class IssuesControllerTest < ActionController::TestCase end end end - + def test_copy_issue @request.session[:user_id] = 2 get :new, :project_id => 1, :copy_from => 1 @@ -583,7 +582,7 @@ class IssuesControllerTest < ActionController::TestCase orig = Issue.find(1) assert_equal orig.subject, assigns(:issue).subject end - + def test_get_edit @request.session[:user_id] = 2 get :edit, :id => 1 @@ -592,25 +591,25 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:issue) assert_equal Issue.find(1), assigns(:issue) end - + def test_get_edit_with_params @request.session[:user_id] = 2 get :edit, :id => 1, :issue => { :status_id => 5, :priority_id => 7 } assert_response :success assert_template 'edit' - + issue = assigns(:issue) assert_not_nil issue - + assert_equal 5, issue.status_id assert_tag :select, :attributes => { :name => 'issue[status_id]' }, - :child => { :tag => 'option', + :child => { :tag => 'option', :content => 'Closed', :attributes => { :selected => 'selected' } } - + assert_equal 7, issue.priority_id assert_tag :select, :attributes => { :name => 'issue[priority_id]' }, - :child => { :tag => 'option', + :child => { :tag => 'option', :content => 'Urgent', :attributes => { :selected => 'selected' } } end @@ -619,13 +618,13 @@ class IssuesControllerTest < ActionController::TestCase @request.session[:user_id] = 2 xhr :post, :update_form, :project_id => 1, :id => 1, - :issue => {:tracker_id => 2, + :issue => {:tracker_id => 2, :subject => 'This is the test_new issue', :description => 'This is the description', :priority_id => 5} assert_response :success assert_template 'attributes' - + issue = assigns(:issue) assert_kind_of Issue, issue assert_equal 1, issue.id @@ -633,7 +632,7 @@ class IssuesControllerTest < ActionController::TestCase assert_equal 2, issue.tracker_id assert_equal 'This is the test_new issue', issue.subject end - + def test_reply_to_issue @request.session[:user_id] = 2 get :reply, :id => 1 @@ -665,55 +664,60 @@ class IssuesControllerTest < ActionController::TestCase def test_put_update_without_custom_fields_param @request.session[:user_id] = 2 ActionMailer::Base.deliveries.clear - + issue = Issue.find(1) assert_equal '125', issue.custom_value_for(2).value old_subject = issue.subject new_subject = 'Subject modified by IssuesControllerTest#test_post_edit' - - assert_difference('Journal.count') do - assert_difference('JournalDetail.count', 2) do - put :update, :id => 1, :issue => {:subject => new_subject, - :priority_id => '6', - :category_id => '1' # no change - } - end + + assert_difference('IssueJournal.count') do + put :update, :id => 1, :issue => {:subject => new_subject, + :priority_id => '6', + :category_id => '1' # no change + } end + assert Issue.current_journal.changes.has_key? "subject" + assert Issue.current_journal.changes.has_key? "priority_id" + assert !Issue.current_journal.changes.has_key? "category_id" + assert_redirected_to :action => 'show', :id => '1' issue.reload assert_equal new_subject, issue.subject # Make sure custom fields were not cleared assert_equal '125', issue.custom_value_for(2).value - + mail = ActionMailer::Base.deliveries.last assert_kind_of TMail::Mail, mail assert mail.subject.starts_with?("[#{issue.project.name} - #{issue.tracker.name} ##{issue.id}]") assert mail.body.include?("Subject changed from #{old_subject} to #{new_subject}") end - + def test_put_update_with_custom_field_change @request.session[:user_id] = 2 issue = Issue.find(1) assert_equal '125', issue.custom_value_for(2).value - + assert_difference('Journal.count') do - assert_difference('JournalDetail.count', 3) do - put :update, :id => 1, :issue => {:subject => 'Custom field change', - :priority_id => '6', - :category_id => '1', # no change - :custom_field_values => { '2' => 'New custom value' } - } - end + put :update, :id => 1, :issue => {:subject => 'Custom field change', + :priority_id => '6', + :category_id => '1', # no change + :custom_field_values => { '2' => 'New custom value' } + } end + assert Issue.current_journal.changes.has_key? "subject" + assert Issue.current_journal.changes.has_key? "priority_id" + assert !Issue.current_journal.changes.has_key? "category_id" + assert Issue.current_journal.changes.has_key? "2" + assert_redirected_to :action => 'show', :id => '1' issue.reload assert_equal 'New custom value', issue.custom_value_for(2).value - + mail = ActionMailer::Base.deliveries.last assert_kind_of TMail::Mail, mail assert mail.body.include?("Searchable field changed from 125 to New custom value") end - + def test_put_update_with_status_and_assignee_change issue = Issue.find(1) assert_equal 1, issue.status_id @@ -731,13 +735,13 @@ class IssuesControllerTest < ActionController::TestCase j = Journal.find(:first, :order => 'id DESC') assert_equal 'Assigned to dlopper', j.notes assert_equal 2, j.details.size - + mail = ActionMailer::Base.deliveries.last assert mail.body.include?("Status changed from New to Assigned") # subject should contain the new status assert mail.subject.include?("(#{ IssueStatus.find(2).name })") end - + def test_put_update_with_note_only notes = 'Note added by IssuesControllerTest#test_update_with_note_only' # anonymous user @@ -749,11 +753,11 @@ class IssuesControllerTest < ActionController::TestCase assert_equal notes, j.notes assert_equal 0, j.details.size assert_equal User.anonymous, j.user - + mail = ActionMailer::Base.deliveries.last assert mail.body.include?(notes) end - + def test_put_update_with_note_and_spent_time @request.session[:user_id] = 2 spent_hours_before = Issue.find(1).spent_hours @@ -764,22 +768,22 @@ class IssuesControllerTest < ActionController::TestCase :time_entry => { :hours => '2.5', :comments => 'test_put_update_with_note_and_spent_time', :activity_id => TimeEntryActivity.first.id } end assert_redirected_to :action => 'show', :id => '1' - + issue = Issue.find(1) - + j = Journal.find(:first, :order => 'id DESC') assert_equal '2.5 hours added', j.notes assert_equal 0, j.details.size - + t = issue.time_entries.find_by_comments('test_put_update_with_note_and_spent_time') assert_not_nil t assert_equal 2.5, t.hours assert_equal spent_hours_before + 2.5, issue.spent_hours end - + def test_put_update_with_attachment_only set_tmp_attachments_directory - + # Delete all fixtured journals, a race condition can occur causing the wrong # journal to get fetched in the next find. Journal.delete_all @@ -795,21 +799,21 @@ class IssuesControllerTest < ActionController::TestCase assert_equal 1, j.details.size assert_equal 'testfile.txt', j.details.first.value assert_equal User.anonymous, j.user - + mail = ActionMailer::Base.deliveries.last assert mail.body.include?('testfile.txt') end def test_put_update_with_attachment_that_fails_to_save set_tmp_attachments_directory - + # Delete all fixtured journals, a race condition can occur causing the wrong # journal to get fetched in the next find. Journal.delete_all # Mock out the unsaved attachment Attachment.any_instance.stubs(:create).returns(Attachment.new) - + # anonymous user put :update, :id => 1, @@ -824,12 +828,12 @@ class IssuesControllerTest < ActionController::TestCase issue = Issue.find(1) issue.journals.clear ActionMailer::Base.deliveries.clear - + put :update, :id => 1, :notes => '' assert_redirected_to :action => 'show', :id => '1' - + issue.reload assert issue.journals.empty? # No email should be sent @@ -842,18 +846,18 @@ class IssuesControllerTest < ActionController::TestCase issue = Issue.find(1) old_subject = issue.subject new_subject = 'Subject modified by IssuesControllerTest#test_post_edit' - + put :update, :id => 1, :issue => {:subject => new_subject, :priority_id => '6', :category_id => '1' # no change } assert_equal 1, ActionMailer::Base.deliveries.size end - + def test_put_update_with_invalid_spent_time @request.session[:user_id] = 2 notes = 'Note added by IssuesControllerTest#test_post_edit_with_invalid_spent_time' - + assert_no_difference('Journal.count') do put :update, :id => 1, @@ -862,12 +866,12 @@ class IssuesControllerTest < ActionController::TestCase end assert_response :success assert_template 'edit' - + assert_tag :textarea, :attributes => { :name => 'notes' }, :content => notes assert_tag :input, :attributes => { :name => 'time_entry[hours]', :value => "2z" } end - + def test_put_update_should_allow_fixed_version_to_be_set_to_a_subproject issue = Issue.find(2) @request.session[:user_id] = 2 @@ -898,7 +902,7 @@ class IssuesControllerTest < ActionController::TestCase assert_response :redirect assert_redirected_to '/issues' end - + def test_put_update_should_not_redirect_back_using_the_back_url_parameter_off_the_host issue = Issue.find(2) @request.session[:user_id] = 2 @@ -913,19 +917,19 @@ class IssuesControllerTest < ActionController::TestCase assert_response :redirect assert_redirected_to :controller => 'issues', :action => 'show', :id => issue.id end - + def test_get_bulk_edit @request.session[:user_id] = 2 get :bulk_edit, :ids => [1, 2] assert_response :success assert_template 'bulk_edit' - + # Project specific custom field, date type field = CustomField.find(9) assert !field.is_for_all? assert_equal 'date', field.field_format assert_tag :input, :attributes => {:name => 'issue[custom_field_values][9]'} - + # System wide custom field assert CustomField.find(1).is_for_all? assert_tag :select, :attributes => {:name => 'issue[custom_field_values][1]'} @@ -938,11 +942,11 @@ class IssuesControllerTest < ActionController::TestCase :issue => {:priority_id => 7, :assigned_to_id => '', :custom_field_values => {'2' => ''}} - + assert_response 302 # check that the issues were updated assert_equal [7, 7], Issue.find_all_by_id([1, 2]).collect {|i| i.priority.id} - + issue = Issue.find(1) journal = issue.journals.find(:first, :order => 'created_on DESC') assert_equal '125', issue.custom_value_for(2).value @@ -975,7 +979,7 @@ class IssuesControllerTest < ActionController::TestCase :issue => {:priority_id => '', :assigned_to_id => '', :status_id => '5'} - + assert_response 302 issue = Issue.find(1) assert issue.closed? @@ -988,9 +992,9 @@ class IssuesControllerTest < ActionController::TestCase :issue => {:priority_id => '', :assigned_to_id => '', :custom_field_values => {'2' => '777'}} - + assert_response 302 - + issue = Issue.find(1) journal = issue.journals.find(:first, :order => 'created_on DESC') assert_equal '777', issue.custom_value_for(2).value @@ -1008,7 +1012,7 @@ class IssuesControllerTest < ActionController::TestCase # check that the issues were updated assert_nil Issue.find(2).assigned_to end - + def test_post_bulk_edit_should_allow_fixed_version_to_be_set_to_a_subproject @request.session[:user_id] = 2 @@ -1062,7 +1066,7 @@ class IssuesControllerTest < ActionController::TestCase assert_equal 1, Issue.find(1).tracker_id assert_equal 2, Issue.find(2).tracker_id end - + def test_bulk_move_to_another_tracker @request.session[:user_id] = 2 post :move, :ids => [1, 2], :new_tracker_id => 2 @@ -1095,12 +1099,12 @@ class IssuesControllerTest < ActionController::TestCase assert_equal issue_before_move.status_id, issue_after_move.status_id assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id end - + should "allow changing the issue's attributes" do # Fixes random test failure with Mysql # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) doesn't return the expected results Issue.delete_all("project_id=2") - + @request.session[:user_id] = 2 assert_difference 'Issue.count', 2 do assert_no_difference 'Project.find(1).issues.count' do @@ -1119,14 +1123,14 @@ class IssuesControllerTest < ActionController::TestCase end end end - + def test_copy_to_another_project_should_follow_when_needed @request.session[:user_id] = 2 post :move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1' issue = Issue.first(:order => 'id DESC') assert_redirected_to :controller => 'issues', :action => 'show', :id => issue end - + def test_context_menu_one_issue @request.session[:user_id] = 2 get :context_menu, :ids => [1] @@ -1174,7 +1178,7 @@ class IssuesControllerTest < ActionController::TestCase :attributes => { :href => '#', :class => 'icon-del disabled' } end - + def test_context_menu_multiple_issues_of_same_project @request.session[:user_id] = 2 get :context_menu, :ids => [1, 2] @@ -1209,7 +1213,7 @@ class IssuesControllerTest < ActionController::TestCase :attributes => { :href => '#', :class => 'icon-del disabled' } end - + def test_preview_new_issue @request.session[:user_id] = 2 post :preview, :project_id => '1', :issue => {:description => 'Foo'} @@ -1217,7 +1221,7 @@ class IssuesControllerTest < ActionController::TestCase assert_template 'preview' assert_not_nil assigns(:description) end - + def test_preview_notes @request.session[:user_id] = 2 post :preview, :project_id => '1', :id => 1, :issue => {:description => Issue.find(1).description}, :notes => 'Foo' @@ -1232,14 +1236,14 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:issues) assert assigns(:issues).detect {|issue| issue.subject.match /recipe/} end - + def test_auto_complete_should_return_issue_with_given_id get :auto_complete, :project_id => 'subproject1', :q => '13' assert_response :success assert_not_nil assigns(:issues) assert assigns(:issues).include?(Issue.find(13)) end - + def test_destroy_issue_with_no_time_entries assert_nil TimeEntry.find_by_issue_id(2) @request.session[:user_id] = 2 @@ -1273,7 +1277,7 @@ class IssuesControllerTest < ActionController::TestCase assert_nil TimeEntry.find(1).issue_id assert_nil TimeEntry.find(2).issue_id end - + def test_destroy_issues_and_reassign_time_entries_to_another_issue @request.session[:user_id] = 2 post :destroy, :ids => [1, 3], :todo => 'reassign', :reassign_to_id => 2 @@ -1282,7 +1286,7 @@ class IssuesControllerTest < ActionController::TestCase assert_equal 2, TimeEntry.find(1).issue_id assert_equal 2, TimeEntry.find(2).issue_id end - + def test_default_search_scope get :index assert_tag :div, :attributes => {:id => 'quick-search'}, diff --git a/test/functional/issues_controller_transaction_test.rb b/test/functional/issues_controller_transaction_test.rb index dbd085bf..b9cd0c78 100644 --- a/test/functional/issues_controller_transaction_test.rb +++ b/test/functional/issues_controller_transaction_test.rb @@ -43,11 +43,10 @@ class IssuesControllerTransactionTest < ActionController::TestCase :custom_fields_trackers, :time_entries, :journals, - :journal_details, :queries self.use_transactional_fixtures = false - + def setup @controller = IssuesController.new @request = ActionController::TestRequest.new diff --git a/test/functional/journals_controller_test.rb b/test/functional/journals_controller_test.rb index 0a11bab3..6638530b 100644 --- a/test/functional/journals_controller_test.rb +++ b/test/functional/journals_controller_test.rb @@ -22,8 +22,8 @@ require 'journals_controller' class JournalsController; def rescue_action(e) raise e end; end class JournalsControllerTest < ActionController::TestCase - fixtures :projects, :users, :members, :member_roles, :roles, :issues, :journals, :journal_details, :enabled_modules - + fixtures :projects, :users, :members, :member_roles, :roles, :issues, :journals, :enabled_modules + def setup @controller = JournalsController.new @request = ActionController::TestRequest.new diff --git a/test/functional/projects_controller_test.rb b/test/functional/projects_controller_test.rb index 988496ce..906d3902 100644 --- a/test/functional/projects_controller_test.rb +++ b/test/functional/projects_controller_test.rb @@ -22,7 +22,7 @@ require 'projects_controller' class ProjectsController; def rescue_action(e) raise e end; end class ProjectsControllerTest < ActionController::TestCase - fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details, + fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, :attachments, :custom_fields, :custom_values, :time_entries diff --git a/test/functional/wiki_controller_test.rb b/test/functional/wiki_controller_test.rb index 76aa0246..ddda2069 100644 --- a/test/functional/wiki_controller_test.rb +++ b/test/functional/wiki_controller_test.rb @@ -5,12 +5,12 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -22,15 +22,15 @@ require 'wiki_controller' class WikiController; def rescue_action(e) raise e end; end class WikiControllerTest < ActionController::TestCase - fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :attachments - + fixtures :projects, :users, :roles, :members, :member_roles, :enabled_modules, :wikis, :wiki_pages, :wiki_contents, :journals, :attachments + def setup @controller = WikiController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil end - + def test_show_start_page get :index, :id => 'ecookbook' assert_response :success @@ -43,7 +43,7 @@ class WikiControllerTest < ActionController::TestCase :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Page_with_an_inline_image' }, :content => 'Page with an inline image' } } end - + def test_show_page_with_name get :index, :id => 1, :page => 'Another_page' assert_response :success @@ -54,30 +54,30 @@ class WikiControllerTest < ActionController::TestCase assert_tag :tag => 'img', :attributes => { :src => '/attachments/download/3', :alt => 'This is a logo' } end - + def test_show_with_sidebar page = Project.find(1).wiki.pages.new(:title => 'Sidebar') page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar') page.save! - + get :index, :id => 1, :page => 'Another_page' assert_response :success assert_tag :tag => 'div', :attributes => {:id => 'sidebar'}, :content => /Side bar content for test_show_with_sidebar/ end - + def test_show_unexistent_page_without_edit_right get :index, :id => 1, :page => 'Unexistent page' assert_response 404 end - + def test_show_unexistent_page_with_edit_right @request.session[:user_id] = 2 get :index, :id => 1, :page => 'Unexistent page' assert_response :success assert_template 'edit' end - + def test_create_page @request.session[:user_id] = 2 post :edit, :id => 1, @@ -91,7 +91,7 @@ class WikiControllerTest < ActionController::TestCase assert_not_nil page.content assert_equal 'Created the page', page.content.comments end - + def test_create_page_with_attachments @request.session[:user_id] = 2 assert_difference 'WikiPage.count' do @@ -108,7 +108,7 @@ class WikiControllerTest < ActionController::TestCase assert_equal 1, page.attachments.count assert_equal 'testfile.txt', page.attachments.first.filename end - + def test_preview @request.session[:user_id] = 2 xhr :post, :preview, :id => 1, :page => 'CookBook_documentation', @@ -119,7 +119,7 @@ class WikiControllerTest < ActionController::TestCase assert_template 'common/_preview' assert_tag :tag => 'strong', :content => /previewed text/ end - + def test_preview_new_page @request.session[:user_id] = 2 xhr :post, :preview, :id => 1, :page => 'New page', @@ -130,7 +130,7 @@ class WikiControllerTest < ActionController::TestCase assert_template 'common/_preview' assert_tag :tag => 'h1', :content => /New page/ end - + def test_history get :history, :id => 1, :page => 'CookBook_documentation' assert_response :success @@ -148,7 +148,7 @@ class WikiControllerTest < ActionController::TestCase assert_equal 1, assigns(:versions).size assert_select "input[type=submit][name=commit]", false end - + def test_diff get :diff, :id => 1, :page => 'CookBook_documentation', :version => 2, :version_from => 1 assert_response :success @@ -156,7 +156,7 @@ class WikiControllerTest < ActionController::TestCase assert_tag :tag => 'span', :attributes => { :class => 'diff_in'}, :content => /updated/ end - + def test_annotate get :annotate, :id => 1, :page => 'CookBook_documentation', :version => 2 assert_response :success @@ -170,7 +170,7 @@ class WikiControllerTest < ActionController::TestCase :child => { :tag => 'td', :attributes => {:class => 'author'}, :content => /redMine Admin/ }, :child => { :tag => 'td', :content => /Some updated \[\[documentation\]\] here/ } end - + def test_rename_with_redirect @request.session[:user_id] = 2 post :rename, :id => 1, :page => 'Another_page', @@ -193,13 +193,13 @@ class WikiControllerTest < ActionController::TestCase # Check that there's no redirects assert_nil wiki.find_page('Another page') end - + def test_destroy_child @request.session[:user_id] = 2 post :destroy, :id => 1, :page => 'Child_1' assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index' end - + def test_destroy_parent @request.session[:user_id] = 2 assert_no_difference('WikiPage.count') do @@ -208,7 +208,7 @@ class WikiControllerTest < ActionController::TestCase assert_response :success assert_template 'destroy' end - + def test_destroy_parent_with_nullify @request.session[:user_id] = 2 assert_difference('WikiPage.count', -1) do @@ -217,7 +217,7 @@ class WikiControllerTest < ActionController::TestCase assert_redirected_to :action => 'special', :id => 'ecookbook', :page => 'Page_index' assert_nil WikiPage.find_by_id(2) end - + def test_destroy_parent_with_cascade @request.session[:user_id] = 2 assert_difference('WikiPage.count', -3) do @@ -227,7 +227,7 @@ class WikiControllerTest < ActionController::TestCase assert_nil WikiPage.find_by_id(2) assert_nil WikiPage.find_by_id(5) end - + def test_destroy_parent_with_reassign @request.session[:user_id] = 2 assert_difference('WikiPage.count', -1) do @@ -237,7 +237,7 @@ class WikiControllerTest < ActionController::TestCase assert_nil WikiPage.find_by_id(2) assert_equal WikiPage.find(1), WikiPage.find_by_id(5).parent end - + def test_page_index get :special, :id => 'ecookbook', :page => 'Page_index' assert_response :success @@ -245,7 +245,7 @@ class WikiControllerTest < ActionController::TestCase pages = assigns(:pages) assert_not_nil pages assert_equal Project.find(1).wiki.pages.size, pages.size - + assert_tag :ul, :attributes => { :class => 'pages-hierarchy' }, :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/CookBook_documentation' }, :content => 'CookBook documentation' }, @@ -256,12 +256,12 @@ class WikiControllerTest < ActionController::TestCase :child => { :tag => 'li', :child => { :tag => 'a', :attributes => { :href => '/projects/ecookbook/wiki/Another_page' }, :content => 'Another page' } } end - + def test_not_found get :index, :id => 999 assert_response 404 end - + def test_protect_page page = WikiPage.find_by_wiki_id_and_title(1, 'Another_page') assert !page.protected? @@ -270,7 +270,7 @@ class WikiControllerTest < ActionController::TestCase assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'Another_page' assert page.reload.protected? end - + def test_unprotect_page page = WikiPage.find_by_wiki_id_and_title(1, 'CookBook_documentation') assert page.protected? @@ -279,7 +279,7 @@ class WikiControllerTest < ActionController::TestCase assert_redirected_to :action => 'index', :id => 'ecookbook', :page => 'CookBook_documentation' assert !page.reload.protected? end - + def test_show_page_with_edit_link @request.session[:user_id] = 2 get :index, :id => 1 @@ -287,15 +287,15 @@ class WikiControllerTest < ActionController::TestCase assert_template 'show' assert_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } end - + def test_show_page_without_edit_link @request.session[:user_id] = 4 get :index, :id => 1 assert_response :success assert_template 'show' assert_no_tag :tag => 'a', :attributes => { :href => '/projects/1/wiki/CookBook_documentation/edit' } - end - + end + def test_edit_unprotected_page # Non members can edit unprotected wiki pages @request.session[:user_id] = 4 @@ -303,21 +303,21 @@ class WikiControllerTest < ActionController::TestCase assert_response :success assert_template 'edit' end - + def test_edit_protected_page_by_nonmember # Non members can't edit protected wiki pages @request.session[:user_id] = 4 get :edit, :id => 1, :page => 'CookBook_documentation' assert_response 403 end - + def test_edit_protected_page_by_member @request.session[:user_id] = 2 get :edit, :id => 1, :page => 'CookBook_documentation' assert_response :success - assert_template 'edit' + assert_template 'edit' end - + def test_history_of_non_existing_page_should_return_404 get :history, :id => 1, :page => 'Unknown_page' assert_response 404 diff --git a/test/integration/issues_api_test.rb b/test/integration/issues_api_test.rb index a1e2cb70..21dc9d00 100644 --- a/test/integration/issues_api_test.rb +++ b/test/integration/issues_api_test.rb @@ -39,7 +39,6 @@ class IssuesApiTest < ActionController::IntegrationTest :custom_fields_trackers, :time_entries, :journals, - :journal_details, :queries def setup diff --git a/test/integration/projects_api_test.rb b/test/integration/projects_api_test.rb index e254c513..389f4de8 100644 --- a/test/integration/projects_api_test.rb +++ b/test/integration/projects_api_test.rb @@ -18,7 +18,7 @@ require "#{File.dirname(__FILE__)}/../test_helper" class ProjectsApiTest < ActionController::IntegrationTest - fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details, + fixtures :projects, :versions, :users, :roles, :members, :member_roles, :issues, :journals, :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages, :attachments, :custom_fields, :custom_values, :time_entries diff --git a/test/test_helper.rb b/test/test_helper.rb index 1f735f5f..e127c477 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -5,12 +5,12 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -47,7 +47,7 @@ class ActiveSupport::TestCase self.use_instantiated_fixtures = false # Add more helper methods to be used by all tests here... - + def log_user(login, password) User.anonymous get "/login" @@ -57,7 +57,7 @@ class ActiveSupport::TestCase post "/login", :username => login, :password => password assert_equal login, User.find(session[:user_id]).login end - + def uploaded_test_file(name, mime) ActionController::TestUploadedFile.new(ActiveSupport::TestCase.fixture_path + "/files/#{name}", mime) end @@ -71,14 +71,14 @@ class ActiveSupport::TestCase file.stubs(:read).returns(false) file end - + # Use a temporary directory for attachment related tests def set_tmp_attachments_directory Dir.mkdir "#{RAILS_ROOT}/tmp/test" unless File.directory?("#{RAILS_ROOT}/tmp/test") Dir.mkdir "#{RAILS_ROOT}/tmp/test/attachments" unless File.directory?("#{RAILS_ROOT}/tmp/test/attachments") Attachment.storage_path = "#{RAILS_ROOT}/tmp/test/attachments" end - + def with_settings(options, &block) saved_settings = options.keys.inject({}) {|h, k| h[k] = Setting[k].dup; h} options.each {|k, v| Setting[k] = v} @@ -93,12 +93,12 @@ class ActiveSupport::TestCase # LDAP is not listening return nil end - + # Returns the path to the test +vendor+ repository def self.repository_path(vendor) File.join(RAILS_ROOT.gsub(%r{config\/\.\.}, ''), "/tmp/test/#{vendor.downcase}_repository") end - + # Returns true if the +vendor+ test repository is configured def self.repository_configured?(vendor) File.directory?(repository_path(vendor)) @@ -144,21 +144,17 @@ class ActiveSupport::TestCase end should "use the new value's name" do - @detail = JournalDetail.generate!(:property => 'attr', - :old_value => @old_value.id, - :value => @new_value.id, - :prop_key => prop_key) - - assert_match @new_value.name, show_detail(@detail, true) + @detail = IssueJournal.generate(:version => 1) + @detail.update_attribute(:changes, {prop_key => [@old_value.id, @new_value.id]}.to_yaml) + + assert_match @new_value.name, @detail.render_detail(prop_key, true) end should "use the old value's name" do - @detail = JournalDetail.generate!(:property => 'attr', - :old_value => @old_value.id, - :value => @new_value.id, - :prop_key => prop_key) - - assert_match @old_value.name, show_detail(@detail, true) + @detail = IssueJournal.generate(:version => 1) + @detail.update_attribute(:changes, {prop_key => [@old_value.id, @new_value.id]}.to_yaml) + + assert_match @old_value.name, @detail.render_detail(prop_key, true) end end end diff --git a/test/unit/activity_test.rb b/test/unit/activity_test.rb index 86a07e6a..67c90c1a 100644 --- a/test/unit/activity_test.rb +++ b/test/unit/activity_test.rb @@ -18,7 +18,7 @@ require File.dirname(__FILE__) + '/../test_helper' class ActivityTest < ActiveSupport::TestCase - fixtures :projects, :versions, :attachments, :users, :roles, :members, :member_roles, :issues, :journals, :journal_details, + fixtures :projects, :versions, :attachments, :users, :roles, :members, :member_roles, :issues, :journals, :trackers, :projects_trackers, :issue_statuses, :enabled_modules, :enumerations, :boards, :messages def setup @@ -28,7 +28,6 @@ class ActivityTest < ActiveSupport::TestCase def test_activity_without_subprojects events = find_events(User.anonymous, :project => @project) assert_not_nil events - assert events.include?(Issue.find(1)) assert !events.include?(Issue.find(4)) # subproject issue @@ -43,40 +42,40 @@ class ActivityTest < ActiveSupport::TestCase # subproject issue assert events.include?(Issue.find(5)) end - + def test_global_activity_anonymous events = find_events(User.anonymous) assert_not_nil events - + assert events.include?(Issue.find(1)) assert events.include?(Message.find(5)) # Issue of a private project - assert !events.include?(Issue.find(4)) + assert !events.include?(Issue.find(6)) end - + def test_global_activity_logged_user events = find_events(User.find(2)) # manager assert_not_nil events - + assert events.include?(Issue.find(1)) # Issue of a private project the user belongs to - assert events.include?(Issue.find(4)) + assert events.include?(Issue.find(6)) end - + def test_user_activity user = User.find(2) events = Redmine::Activity::Fetcher.new(User.anonymous, :author => user).events(nil, nil, :limit => 10) - + assert(events.size > 0) assert(events.size <= 10) assert_nil(events.detect {|e| e.event_author != user}) end - + def test_files_activity f = Redmine::Activity::Fetcher.new(User.anonymous, :project => Project.find(1)) f.scope = ['files'] events = f.events - + assert_kind_of Array, events assert events.include?(Attachment.find_by_container_type_and_container_id('Project', 1)) assert events.include?(Attachment.find_by_container_type_and_container_id('Version', 1)) @@ -85,8 +84,11 @@ class ActivityTest < ActiveSupport::TestCase end private - + def find_events(user, options={}) - Redmine::Activity::Fetcher.new(user, options).events(Date.today - 30, Date.today + 1) + events = Redmine::Activity::Fetcher.new(user, options).events(Date.today - 30, Date.today + 1) + # Because events are provided by the journals, but we want to test for + # their targets here, transform that + events.group_by(&:versioned).keys end end diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index e0eb479d..46e12b52 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -5,12 +5,12 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -22,7 +22,7 @@ class IssueTest < ActiveSupport::TestCase :trackers, :projects_trackers, :enabled_modules, :versions, - :issue_statuses, :issue_categories, :issue_relations, :workflows, + :issue_statuses, :issue_categories, :issue_relations, :workflows, :enumerations, :issues, :custom_fields, :custom_fields_projects, :custom_fields_trackers, :custom_values, @@ -34,17 +34,17 @@ class IssueTest < ActiveSupport::TestCase issue.reload assert_equal 1.5, issue.estimated_hours end - + def test_create_minimal issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create') assert issue.save assert issue.description.nil? end - + def test_create_with_required_custom_field field = IssueCustomField.find_by_name('Database') field.update_attribute(:is_required, true) - + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field') assert issue.available_custom_fields.include?(field) # No value for the custom field @@ -64,7 +64,7 @@ class IssueTest < ActiveSupport::TestCase issue.reload assert_equal 'PostgreSQL', issue.custom_value_for(field).value end - + def test_visible_scope_for_anonymous # Anonymous user should see issues of public projects only issues = Issue.visible(User.anonymous).all @@ -75,7 +75,7 @@ class IssueTest < ActiveSupport::TestCase issues = Issue.visible(User.anonymous).all assert issues.empty? end - + def test_visible_scope_for_user user = User.find(9) assert user.projects.empty? @@ -95,7 +95,7 @@ class IssueTest < ActiveSupport::TestCase assert issues.any? assert_nil issues.detect {|issue| issue.project_id != 2} end - + def test_visible_scope_for_admin user = User.find(1) user.members.each(&:destroy) @@ -105,24 +105,24 @@ class IssueTest < ActiveSupport::TestCase # Admin should see issues on private projects that he does not belong to assert issues.detect {|issue| !issue.project.is_public?} end - + def test_errors_full_messages_should_include_custom_fields_errors field = IssueCustomField.find_by_name('Database') - + issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :subject => 'test_create', :description => 'IssueTest#test_create_with_required_custom_field') assert issue.available_custom_fields.include?(field) # Invalid value issue.custom_field_values = { field.id => 'SQLServer' } - + assert !issue.valid? assert_equal 1, issue.errors.full_messages.size assert_equal "Database #{I18n.translate('activerecord.errors.messages.inclusion')}", issue.errors.full_messages.first end - + def test_update_issue_with_required_custom_field field = IssueCustomField.find_by_name('Database') field.update_attribute(:is_required, true) - + issue = Issue.find(1) assert_nil issue.custom_value_for(field) assert issue.available_custom_fields.include?(field) @@ -137,23 +137,23 @@ class IssueTest < ActiveSupport::TestCase issue.reload assert_equal 'PostgreSQL', issue.custom_value_for(field).value end - + def test_should_not_update_attributes_if_custom_fields_validation_fails issue = Issue.find(1) field = IssueCustomField.find_by_name('Database') assert issue.available_custom_fields.include?(field) - + issue.custom_field_values = { field.id => 'Invalid' } issue.subject = 'Should be not be saved' assert !issue.save - + issue.reload assert_equal "Can't print recipes", issue.subject end - + def test_should_not_recreate_custom_values_objects_on_update field = IssueCustomField.find_by_name('Database') - + issue = Issue.find(1) issue.custom_field_values = { field.id => 'PostgreSQL' } assert issue.save @@ -164,14 +164,14 @@ class IssueTest < ActiveSupport::TestCase issue.reload assert_equal custom_value.id, issue.custom_value_for(field).id end - + def test_assigning_tracker_id_should_reload_custom_fields_values issue = Issue.new(:project => Project.find(1)) assert issue.custom_field_values.empty? issue.tracker_id = 1 assert issue.custom_field_values.any? end - + def test_assigning_attributes_should_assign_tracker_id_first attributes = ActiveSupport::OrderedHash.new attributes['custom_field_values'] = { '1' => 'MySQL' } @@ -181,35 +181,35 @@ class IssueTest < ActiveSupport::TestCase assert_not_nil issue.custom_value_for(1) assert_equal 'MySQL', issue.custom_value_for(1).value end - + def test_should_update_issue_with_disabled_tracker p = Project.find(1) issue = Issue.find(1) - + p.trackers.delete(issue.tracker) assert !p.trackers.include?(issue.tracker) - + issue.reload issue.subject = 'New subject' assert issue.save end - + def test_should_not_set_a_disabled_tracker p = Project.find(1) p.trackers.delete(Tracker.find(2)) - + issue = Issue.find(1) issue.tracker_id = 2 issue.subject = 'New subject' assert !issue.save assert_not_nil issue.errors.on(:tracker_id) end - + def test_category_based_assignment issue = Issue.create(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Assignment test', :description => 'Assignment test', :category_id => 1) assert_equal IssueCategory.find(1).assigned_to, issue.assigned_to end - + def test_copy issue = Issue.new.copy_from(1) assert issue.save @@ -223,13 +223,13 @@ class IssueTest < ActiveSupport::TestCase def test_copy_should_copy_status orig = Issue.find(8) assert orig.status != IssueStatus.default - + issue = Issue.new.copy_from(orig) assert issue.save issue.reload assert_equal orig.status, issue.status end - + def test_should_close_duplicates # Create 3 issues issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test') @@ -238,37 +238,37 @@ class IssueTest < ActiveSupport::TestCase assert issue2.save issue3 = issue1.clone assert issue3.save - + # 2 is a dupe of 1 IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) # And 3 is a dupe of 2 IssueRelation.create(:issue_from => issue3, :issue_to => issue2, :relation_type => IssueRelation::TYPE_DUPLICATES) # And 3 is a dupe of 1 (circular duplicates) IssueRelation.create(:issue_from => issue3, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) - + assert issue1.reload.duplicates.include?(issue2) - + # Closing issue 1 issue1.init_journal(User.find(:first), "Closing issue1") issue1.status = IssueStatus.find :first, :conditions => {:is_closed => true} assert issue1.save # 2 and 3 should be also closed assert issue2.reload.closed? - assert issue3.reload.closed? + assert issue3.reload.closed? end - + def test_should_not_close_duplicated_issue # Create 3 issues issue1 = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'Duplicates test', :description => 'Duplicates test') assert issue1.save issue2 = issue1.clone assert issue2.save - + # 2 is a dupe of 1 IssueRelation.create(:issue_from => issue2, :issue_to => issue1, :relation_type => IssueRelation::TYPE_DUPLICATES) # 2 is a dup of 1 but 1 is not a duplicate of 2 assert !issue2.reload.duplicates.include?(issue1) - + # Closing issue 2 issue2.init_journal(User.find(:first), "Closing issue2") issue2.status = IssueStatus.find :first, :conditions => {:is_closed => true} @@ -276,57 +276,57 @@ class IssueTest < ActiveSupport::TestCase # 1 should not be also closed assert !issue1.reload.closed? end - + def test_assignable_versions issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') assert_equal ['open'], issue.assignable_versions.collect(&:status).uniq end - + def test_should_not_be_able_to_assign_a_new_issue_to_a_closed_version issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 1, :subject => 'New issue') assert !issue.save assert_not_nil issue.errors.on(:fixed_version_id) end - + def test_should_not_be_able_to_assign_a_new_issue_to_a_locked_version issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 2, :subject => 'New issue') assert !issue.save assert_not_nil issue.errors.on(:fixed_version_id) end - + def test_should_be_able_to_assign_a_new_issue_to_an_open_version issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 1, :status_id => 1, :fixed_version_id => 3, :subject => 'New issue') assert issue.save end - + def test_should_be_able_to_update_an_issue_assigned_to_a_closed_version issue = Issue.find(11) assert_equal 'closed', issue.fixed_version.status issue.subject = 'Subject changed' assert issue.save end - + def test_should_not_be_able_to_reopen_an_issue_assigned_to_a_closed_version issue = Issue.find(11) issue.status_id = 1 assert !issue.save assert_not_nil issue.errors.on_base end - + def test_should_be_able_to_reopen_and_reassign_an_issue_assigned_to_a_closed_version issue = Issue.find(11) issue.status_id = 1 issue.fixed_version_id = 3 assert issue.save end - + def test_should_be_able_to_reopen_an_issue_assigned_to_a_locked_version issue = Issue.find(12) assert_equal 'locked', issue.fixed_version.status issue.status_id = 1 assert issue.save end - + def test_move_to_another_project_with_same_category issue = Issue.find(1) assert issue.move_to_project(Project.find(2)) @@ -337,7 +337,7 @@ class IssueTest < ActiveSupport::TestCase # Make sure time entries were move to the target project assert_equal 2, issue.time_entries.first.project_id end - + def test_move_to_another_project_without_same_category issue = Issue.find(2) assert issue.move_to_project(Project.find(2)) @@ -346,7 +346,7 @@ class IssueTest < ActiveSupport::TestCase # Category cleared assert_nil issue.category_id end - + def test_move_to_another_project_should_clear_fixed_version_when_not_shared issue = Issue.find(1) issue.update_attribute(:fixed_version_id, 1) @@ -356,7 +356,7 @@ class IssueTest < ActiveSupport::TestCase # Cleared fixed_version assert_equal nil, issue.fixed_version end - + def test_move_to_another_project_should_keep_fixed_version_when_shared_with_the_target_project issue = Issue.find(1) issue.update_attribute(:fixed_version_id, 4) @@ -366,7 +366,7 @@ class IssueTest < ActiveSupport::TestCase # Keep fixed_version assert_equal 4, issue.fixed_version_id end - + def test_move_to_another_project_should_clear_fixed_version_when_not_shared_with_the_target_project issue = Issue.find(1) issue.update_attribute(:fixed_version_id, 1) @@ -376,7 +376,7 @@ class IssueTest < ActiveSupport::TestCase # Cleared fixed_version assert_equal nil, issue.fixed_version end - + def test_move_to_another_project_should_keep_fixed_version_when_shared_systemwide issue = Issue.find(1) issue.update_attribute(:fixed_version_id, 7) @@ -386,7 +386,7 @@ class IssueTest < ActiveSupport::TestCase # Keep fixed_version assert_equal 7, issue.fixed_version_id end - + def test_move_to_another_project_with_disabled_tracker issue = Issue.find(1) target = Project.find(2) @@ -396,7 +396,7 @@ class IssueTest < ActiveSupport::TestCase issue.reload assert_equal 1, issue.project_id end - + def test_copy_to_the_same_project issue = Issue.find(1) copy = nil @@ -407,7 +407,7 @@ class IssueTest < ActiveSupport::TestCase assert_equal issue.project, copy.project assert_equal "125", copy.custom_value_for(2).value end - + def test_copy_to_another_project_and_tracker issue = Issue.find(1) copy = nil @@ -453,7 +453,7 @@ class IssueTest < ActiveSupport::TestCase end end end - + def test_recipients_should_not_include_users_that_cannot_view_the_issue issue = Issue.find(12) assert issue.recipients.include?(issue.author.mail) @@ -470,39 +470,39 @@ class IssueTest < ActiveSupport::TestCase assert issue.watched_by?(user) assert !issue.watcher_recipients.include?(user.mail) end - + def test_issue_destroy Issue.find(1).destroy assert_nil Issue.find_by_id(1) assert_nil TimeEntry.find_by_issue_id(1) end - + def test_blocked blocked_issue = Issue.find(9) blocking_issue = Issue.find(10) - + assert blocked_issue.blocked? assert !blocking_issue.blocked? end - + def test_blocked_issues_dont_allow_closed_statuses blocked_issue = Issue.find(9) - + allowed_statuses = blocked_issue.new_statuses_allowed_to(users(:users_002)) assert !allowed_statuses.empty? closed_statuses = allowed_statuses.select {|st| st.is_closed?} assert closed_statuses.empty? end - + def test_unblocked_issues_allow_closed_statuses blocking_issue = Issue.find(10) - + allowed_statuses = blocking_issue.new_statuses_allowed_to(users(:users_002)) assert !allowed_statuses.empty? closed_statuses = allowed_statuses.select {|st| st.is_closed?} assert !closed_statuses.empty? end - + def test_overdue assert Issue.new(:due_date => 1.day.ago.to_date).overdue? assert !Issue.new(:due_date => Date.today).overdue? @@ -510,11 +510,11 @@ class IssueTest < ActiveSupport::TestCase assert !Issue.new(:due_date => nil).overdue? assert !Issue.new(:due_date => 1.day.ago.to_date, :status => IssueStatus.find(:first, :conditions => {:is_closed => true})).overdue? end - + def test_assignable_users assert_kind_of User, Issue.find(1).assignable_users.first end - + def test_create_should_send_email_notification ActionMailer::Base.deliveries.clear issue = Issue.new(:project_id => 1, :tracker_id => 1, :author_id => 3, :status_id => 1, :priority => IssuePriority.all.first, :subject => 'test_create', :estimated_hours => '1:30') @@ -522,18 +522,18 @@ class IssueTest < ActiveSupport::TestCase assert issue.save assert_equal 1, ActionMailer::Base.deliveries.size end - + def test_stale_issue_should_not_send_email_notification ActionMailer::Base.deliveries.clear issue = Issue.find(1) stale = Issue.find(1) - + issue.init_journal(User.find(1)) issue.subject = 'Subjet update' assert issue.save assert_equal 1, ActionMailer::Base.deliveries.size ActionMailer::Base.deliveries.clear - + stale.init_journal(User.find(1)) stale.subject = 'Another subjet update' assert_raise ActiveRecord::StaleObjectError do @@ -541,7 +541,7 @@ class IssueTest < ActiveSupport::TestCase end assert ActionMailer::Base.deliveries.empty? end - + def test_saving_twice_should_not_duplicate_journal_details i = Issue.find(:first) i.init_journal(User.find(2), 'Some notes') @@ -551,18 +551,19 @@ class IssueTest < ActiveSupport::TestCase assert_difference 'Journal.count' do assert i.save end + assert i.current_journal.changes.has_key? "subject" + assert i.current_journal.changes.has_key? "done_ratio" + # 1 more change i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id]) - assert_no_difference 'Journal.count' do - assert_difference 'JournalDetail.count', 1 do - i.save - end + assert_difference 'Journal.count' do + i.save end + assert i.current_journal.changes.has_key? "priority_id" + # no more change assert_no_difference 'Journal.count' do - assert_no_difference 'JournalDetail.count' do - i.save - end + i.save end end @@ -572,12 +573,12 @@ class IssueTest < ActiveSupport::TestCase @issue_status = IssueStatus.find(1) @issue_status.update_attribute(:default_done_ratio, 50) end - + context "with Setting.issue_done_ratio using the issue_field" do setup do Setting.issue_done_ratio = 'issue_field' end - + should "read the issue's field" do assert_equal 0, @issue.done_ratio end @@ -587,7 +588,7 @@ class IssueTest < ActiveSupport::TestCase setup do Setting.issue_done_ratio = 'issue_status' end - + should "read the Issue Status's default done ratio" do assert_equal 50, @issue.done_ratio end @@ -600,12 +601,12 @@ class IssueTest < ActiveSupport::TestCase @issue_status = IssueStatus.find(1) @issue_status.update_attribute(:default_done_ratio, 50) end - + context "with Setting.issue_done_ratio using the issue_field" do setup do Setting.issue_done_ratio = 'issue_field' end - + should "not change the issue" do @issue.update_done_ratio_from_issue_status @@ -617,7 +618,7 @@ class IssueTest < ActiveSupport::TestCase setup do Setting.issue_done_ratio = 'issue_status' end - + should "not change the issue's done ratio" do @issue.update_done_ratio_from_issue_status @@ -667,19 +668,19 @@ class IssueTest < ActiveSupport::TestCase assert_equal 2, groups.size assert_equal 5, groups.inject(0) {|sum, group| sum + group['total'].to_i} end - - + + context ".allowed_target_projects_on_move" do should "return all active projects for admin users" do User.current = User.find(1) assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size end - + should "return allowed projects for non admin users" do User.current = User.find(2) Role.non_member.remove_permission! :move_issues assert_equal 3, Issue.allowed_target_projects_on_move.size - + Role.non_member.add_permission! :move_issues assert_equal Project.active.count, Issue.allowed_target_projects_on_move.size end @@ -693,7 +694,7 @@ class IssueTest < ActiveSupport::TestCase def test_on_active_projects_scope assert Project.find(2).archive - + before = Issue.on_active_project.length # test inclusion to results issue = Issue.generate_for_project!(Project.find(1), :tracker => Project.find(2).trackers.first) diff --git a/test/unit/journal_test.rb b/test/unit/journal_test.rb index 87273ad4..cd6aea0f 100644 --- a/test/unit/journal_test.rb +++ b/test/unit/journal_test.rb @@ -18,14 +18,14 @@ require File.dirname(__FILE__) + '/../test_helper' class JournalTest < ActiveSupport::TestCase - fixtures :issues, :issue_statuses, :journals, :journal_details + fixtures :issues, :issue_statuses, :journals def setup - @journal = Journal.find 1 + @journal = IssueJournal.first end def test_journalized_is_an_issue - issue = @journal.issue + issue = @journal.journalized assert_kind_of Issue, issue assert_equal 1, issue.id end @@ -34,16 +34,16 @@ class JournalTest < ActiveSupport::TestCase status = @journal.new_status assert_not_nil status assert_kind_of IssueStatus, status - assert_equal 2, status.id + assert_equal 2, status.id end - + def test_create_should_send_email_notification ActionMailer::Base.deliveries.clear issue = Issue.find(:first) user = User.find(:first) - journal = issue.init_journal(user, issue) - assert journal.save + assert_equal 0, ActionMailer::Base.deliveries.size + issue.update_attribute(:subject, "New subject to trigger automatic journal entry") assert_equal 1, ActionMailer::Base.deliveries.size end diff --git a/test/unit/mail_handler_test.rb b/test/unit/mail_handler_test.rb index e0ff8a2a..4a19e2f6 100644 --- a/test/unit/mail_handler_test.rb +++ b/test/unit/mail_handler_test.rb @@ -259,7 +259,7 @@ class MailHandlerTest < ActiveSupport::TestCase # This email contains: 'Status: Resolved' journal = submit_email('ticket_reply_with_status.eml') assert journal.is_a?(Journal) - issue = Issue.find(journal.issue.id) + issue = Issue.find(journal.journalized.id) assert_equal User.find_by_login('jsmith'), journal.user assert_equal Issue.find(2), journal.journalized assert_match /This is reply/, journal.notes diff --git a/test/unit/mailer_test.rb b/test/unit/mailer_test.rb index f1fc2502..f6f54fad 100644 --- a/test/unit/mailer_test.rb +++ b/test/unit/mailer_test.rb @@ -20,8 +20,8 @@ require File.dirname(__FILE__) + '/../test_helper' class MailerTest < ActiveSupport::TestCase include Redmine::I18n include ActionController::Assertions::SelectorAssertions - fixtures :projects, :enabled_modules, :issues, :users, :members, :member_roles, :roles, :documents, :attachments, :news, :tokens, :journals, :journal_details, :changesets, :trackers, :issue_statuses, :enumerations, :messages, :boards, :repositories - + fixtures :projects, :enabled_modules, :issues, :users, :members, :member_roles, :roles, :documents, :attachments, :news, :tokens, :journals, :changesets, :trackers, :issue_statuses, :enumerations, :messages, :boards, :repositories + def setup ActionMailer::Base.deliveries.clear Setting.host_name = 'mydomain.foo' diff --git a/test/unit/search_test.rb b/test/unit/search_test.rb index 71ed7ad0..ed497e43 100644 --- a/test/unit/search_test.rb +++ b/test/unit/search_test.rb @@ -27,7 +27,6 @@ class SearchTest < ActiveSupport::TestCase :issues, :trackers, :journals, - :journal_details, :repositories, :changesets diff --git a/test/unit/wiki_content_test.rb b/test/unit/wiki_content_test.rb index 0261678a..6aaaffbc 100644 --- a/test/unit/wiki_content_test.rb +++ b/test/unit/wiki_content_test.rb @@ -5,12 +5,12 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -18,19 +18,19 @@ require File.dirname(__FILE__) + '/../test_helper' class WikiContentTest < ActiveSupport::TestCase - fixtures :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions, :users + fixtures :wikis, :wiki_pages, :wiki_contents, :journals, :users def setup @wiki = Wiki.find(1) @page = @wiki.pages.first end - + def test_create - page = WikiPage.new(:wiki => @wiki, :title => "Page") + page = WikiPage.new(:wiki => @wiki, :title => "Page") page.content = WikiContent.new(:text => "Content text", :author => User.find(1), :comments => "My comment") assert page.save page.reload - + content = page.content assert_kind_of WikiContent, content assert_equal 1, content.version @@ -40,14 +40,14 @@ class WikiContentTest < ActiveSupport::TestCase assert_equal User.find(1), content.author assert_equal content.text, content.versions.last.text end - + def test_create_should_send_email_notification Setting.notified_events = ['wiki_content_added'] ActionMailer::Base.deliveries.clear - page = WikiPage.new(:wiki => @wiki, :title => "A new page") + page = WikiPage.new(:wiki => @wiki, :title => "A new page") page.content = WikiContent.new(:text => "Content text", :author => User.find(1), :comments => "My comment") assert page.save - + assert_equal 1, ActionMailer::Base.deliveries.size end @@ -60,26 +60,26 @@ class WikiContentTest < ActiveSupport::TestCase assert_equal version_count+1, content.version assert_equal version_count+1, content.versions.length end - + def test_update_should_send_email_notification Setting.notified_events = ['wiki_content_updated'] ActionMailer::Base.deliveries.clear content = @page.content content.text = "My new content" assert content.save - + assert_equal 1, ActionMailer::Base.deliveries.size end - + def test_fetch_history assert !@page.content.versions.empty? @page.content.versions.each do |version| assert_kind_of String, version.text end end - + def test_large_text_should_not_be_truncated_to_64k - page = WikiPage.new(:wiki => @wiki, :title => "Big page") + page = WikiPage.new(:wiki => @wiki, :title => "Big page") page.content = WikiContent.new(:text => "a" * 500.kilobyte, :author => User.find(1)) assert page.save page.reload diff --git a/test/unit/wiki_page_test.rb b/test/unit/wiki_page_test.rb index c8fd1b29..6789d114 100644 --- a/test/unit/wiki_page_test.rb +++ b/test/unit/wiki_page_test.rb @@ -5,12 +5,12 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -18,51 +18,51 @@ require File.dirname(__FILE__) + '/../test_helper' class WikiPageTest < ActiveSupport::TestCase - fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions + fixtures :projects, :wikis, :wiki_pages, :wiki_contents, :journals def setup @wiki = Wiki.find(1) @page = @wiki.pages.first end - + def test_create page = WikiPage.new(:wiki => @wiki) assert !page.save assert_equal 1, page.errors.count - + page.title = "Page" assert page.save page.reload assert !page.protected? - + @wiki.reload assert @wiki.pages.include?(page) end - + def test_sidebar_should_be_protected_by_default page = @wiki.find_or_new_page('sidebar') assert page.new_record? assert page.protected? end - + def test_find_or_new_page page = @wiki.find_or_new_page("CookBook documentation") assert_kind_of WikiPage, page assert !page.new_record? - + page = @wiki.find_or_new_page("Non existing page") assert_kind_of WikiPage, page assert page.new_record? end - + def test_parent_title page = WikiPage.find_by_title('Another_page') assert_nil page.parent_title - + page = WikiPage.find_by_title('Page_with_an_inline_image') assert_equal 'CookBook documentation', page.parent_title end - + def test_assign_parent page = WikiPage.find_by_title('Another_page') page.parent_title = 'CookBook documentation' @@ -70,7 +70,7 @@ class WikiPageTest < ActiveSupport::TestCase page.reload assert_equal WikiPage.find_by_title('CookBook_documentation'), page.parent end - + def test_unassign_parent page = WikiPage.find_by_title('Page_with_an_inline_image') page.parent_title = '' @@ -78,10 +78,10 @@ class WikiPageTest < ActiveSupport::TestCase page.reload assert_nil page.parent end - + def test_parent_validation page = WikiPage.find_by_title('CookBook_documentation') - + # A page that doesn't exist page.parent_title = 'Unknown title' assert !page.save @@ -98,23 +98,26 @@ class WikiPageTest < ActiveSupport::TestCase page.parent_title = 'Another_page' assert page.save end - + def test_destroy page = WikiPage.find(1) + content_ids = WikiContent.find_all_by_page_id(1).collect(&:id) page.destroy assert_nil WikiPage.find_by_id(1) # make sure that page content and its history are deleted assert WikiContent.find_all_by_page_id(1).empty? - assert WikiContent.versioned_class.find_all_by_page_id(1).empty? + content_ids.each do |wiki_content_id| + assert WikiContent.journal_class.find_all_by_versioned_id(wiki_content_id).empty? + end end - + def test_destroy_should_not_nullify_children page = WikiPage.find(2) child_ids = page.child_ids assert child_ids.any? page.destroy assert_nil WikiPage.find_by_id(2) - + children = WikiPage.find_all_by_id(child_ids) assert_equal child_ids.size, children.size children.each do |child| diff --git a/test/unit/wiki_test.rb b/test/unit/wiki_test.rb index 9303ce78..48d63705 100644 --- a/test/unit/wiki_test.rb +++ b/test/unit/wiki_test.rb @@ -7,12 +7,12 @@ # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # of the License, or (at your option) any later version. -# +# # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -20,13 +20,13 @@ require File.dirname(__FILE__) + '/../test_helper' class WikiTest < ActiveSupport::TestCase - fixtures :wikis, :wiki_pages, :wiki_contents, :wiki_content_versions - + fixtures :wikis, :wiki_pages, :wiki_contents, :journals + def test_create wiki = Wiki.new(:project => Project.find(2)) assert !wiki.save assert_equal 1, wiki.errors.count - + wiki.start_page = "Start page" assert wiki.save end @@ -38,26 +38,26 @@ class WikiTest < ActiveSupport::TestCase @wiki.reload assert_equal "Another start page", @wiki.start_page end - + def test_titleize assert_equal 'Page_title_with_CAPITALES', Wiki.titleize('page title with CAPITALES') assert_equal 'テスト', Wiki.titleize('テスト') end - + context "#sidebar" do setup do @wiki = Wiki.find(1) end - + should "return nil if undefined" do assert_nil @wiki.sidebar end - + should "return a WikiPage if defined" do page = @wiki.pages.new(:title => 'Sidebar') page.content = WikiContent.new(:text => 'Side bar content for test_show_with_sidebar') page.save! - + assert_kind_of WikiPage, @wiki.sidebar assert_equal 'Sidebar', @wiki.sidebar.title end diff --git a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb index 1f145a7b..c8671a71 100644 --- a/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb +++ b/vendor/plugins/acts_as_activity_provider/lib/acts_as_activity_provider.rb @@ -68,11 +68,11 @@ module Redmine scope_options[:conditions] = cond.conditions if options[:limit] # id and creation time should be in same order in most cases - scope_options[:order] = "#{table_name}.id DESC" + scope_options[:order] = "#{journal_class.table_name}.id DESC" scope_options[:limit] = options[:limit] end - - with_scope(:find => scope_options) do + + journal_class.with_scope(:find => scope_options) do journal_class.find(:all, provider_options[:find_options].dup) end end From acc093b0c1b7a9a204ba460b50f4e304015444c4 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Fri, 6 Aug 2010 14:22:49 +0200 Subject: [PATCH 051/777] add a journal entry for messages --- test/fixtures/journals.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/test/fixtures/journals.yml b/test/fixtures/journals.yml index a113d0f7..2433da8a 100644 --- a/test/fixtures/journals.yml +++ b/test/fixtures/journals.yml @@ -177,4 +177,13 @@ journals_014: user_id: 2 notes: "An attachment on a document" versioned_id: 2 - changes: --- {} \ No newline at end of file + changes: --- {} +journals_015: + id: 15 + type: "MessageJournal" + activity_type: "messages" + created_at: <%= 2.days.ago.to_date.to_s(:db) %> + version: 1 + user_id: 2 + notes: "A message journal" + versioned_id: 3 From 9409ae7350ebeeaa10bbbcac9662bba26c0ef1d2 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Fri, 6 Aug 2010 14:56:57 +0200 Subject: [PATCH 052/777] add another journal --- test/fixtures/journals.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/fixtures/journals.yml b/test/fixtures/journals.yml index 2433da8a..e73c300d 100644 --- a/test/fixtures/journals.yml +++ b/test/fixtures/journals.yml @@ -186,4 +186,13 @@ journals_015: version: 1 user_id: 2 notes: "A message journal" + versioned_id: 1 +journals_016: + id: 16 + type: "MessageJournal" + activity_type: "messages" + created_at: <%= 2.days.ago.to_date.to_s(:db) %> + version: 1 + user_id: 2 + notes: "A message journal" versioned_id: 3 From cbfbd662bb4cd3b43b5693fba8d78622a92529d7 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Fri, 6 Aug 2010 14:57:11 +0200 Subject: [PATCH 053/777] fix changed method name --- test/unit/mailer_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/mailer_test.rb b/test/unit/mailer_test.rb index f6f54fad..b3229ac5 100644 --- a/test/unit/mailer_test.rb +++ b/test/unit/mailer_test.rb @@ -171,7 +171,7 @@ class MailerTest < ActiveSupport::TestCase mail = ActionMailer::Base.deliveries.last assert_not_nil mail assert_equal Mailer.message_id_for(journal), mail.message_id - assert_equal Mailer.message_id_for(journal.issue), mail.references.first.to_s + assert_equal Mailer.message_id_for(journal.versioned), mail.references.first.to_s end def test_message_posted_message_id From 7d67365e10526957310e29212733855360e8b87c Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Fri, 6 Aug 2010 18:47:56 +0200 Subject: [PATCH 054/777] smaller fixes for journalized news and attachments --- app/models/attachment.rb | 3 --- app/models/news.rb | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/app/models/attachment.rb b/app/models/attachment.rb index 502e529c..da1fd1c2 100644 --- a/app/models/attachment.rb +++ b/app/models/attachment.rb @@ -23,7 +23,6 @@ class Attachment < ActiveRecord::Base # FIXME: Remove these once the Versions, Documents and Projects themselves can provide file events belongs_to :version, :foreign_key => "container_id" belongs_to :document, :foreign_key => "container_id" - belongs_to :project, :foreign_key => "container_id" belongs_to :author, :class_name => "User", :foreign_key => "author_id" @@ -53,8 +52,6 @@ class Attachment < ActiveRecord::Base "documents" when "Version" "files" - when "Project" - "files" else super end diff --git a/app/models/news.rb b/app/models/news.rb index 91700ebf..46769876 100644 --- a/app/models/news.rb +++ b/app/models/news.rb @@ -24,7 +24,7 @@ class News < ActiveRecord::Base validates_length_of :title, :maximum => 60 validates_length_of :summary, :maximum => 255 - acts_as_journalized :event_url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id} } + acts_as_journalized :event_url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.versioned_id} } acts_as_searchable :columns => ['title', 'summary', "#{table_name}.description"], :include => :project def visible?(user=User.current) From 584462303127309cd2dfbbe889223cf843f9aace Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 10 Aug 2010 12:36:45 +0200 Subject: [PATCH 055/777] add acts_as_journalized into a submodule --- .gitmodules | 3 +++ vendor/plugins/acts_as_journalized | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 vendor/plugins/acts_as_journalized diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..dec27a61 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "vendor/plugins/acts_as_journalized"] + path = vendor/plugins/acts_as_journalized + url = git://github.com/finnlabs/acts_as_journalized diff --git a/vendor/plugins/acts_as_journalized b/vendor/plugins/acts_as_journalized new file mode 160000 index 00000000..de6525fb --- /dev/null +++ b/vendor/plugins/acts_as_journalized @@ -0,0 +1 @@ +Subproject commit de6525fb37efc6807b418bb959f1bdbd9c5576ba From 08a013da44cbc02f328942e9fc977cba5901b376 Mon Sep 17 00:00:00 2001 From: Wieland Lindenthal Date: Tue, 10 Aug 2010 16:10:53 +0200 Subject: [PATCH 056/777] Minor bug fixes to journalized versions --- app/controllers/wiki_controller.rb | 2 +- app/models/message.rb | 2 +- app/models/wiki_content.rb | 7 ++++++- app/views/wiki/history.rhtml | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index 15967a91..5c3f38e7 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -122,7 +122,7 @@ class WikiController < ApplicationController @version_pages = Paginator.new self, @version_count, per_page_option, params['p'] # don't load text @versions = @page.content.versions.find :all, - :select => "id, user_id, notes, updated_at, version", + :select => "id, user_id, notes, created_at, version", :order => 'version DESC', :limit => @version_pages.items_per_page + 1, :offset => @version_pages.current.offset diff --git a/app/models/message.rb b/app/models/message.rb index 5eae0654..8e68d208 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -29,7 +29,7 @@ class Message < ActiveRecord::Base if o.parent_id.nil? {:id => o.id} else - {:id => o.parent_id, :r => o.id, :anchor => "message-#{o.id}"} + {:id => o.parent_id, :r => o.versioned.id, :anchor => "message-#{o.versioned.id}"} end.reverse_merge :controller => 'messages', :action => 'show', :board_id => o.board_id end), :activity_find_options => { :include => { :board => :project } } diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb index a2e4dcaf..945fcaec 100644 --- a/app/models/wiki_content.rb +++ b/app/models/wiki_content.rb @@ -57,11 +57,16 @@ class WikiContent < ActiveRecord::Base WikiContentJournal.class_eval do attr_protected :data after_save :compress_version_text + after_save :move_comments_to_notes # Wiki Content might be large and the data should possibly be compressed def compress_version_text self.text = changes["text"].last if changes["text"] end + + def move_comments_to_notes + self.notes = changes.delete("comments").last if changes["comments"] + end def text=(plain) case Setting.wiki_compression @@ -99,4 +104,4 @@ class WikiContent < ActiveRecord::Base @previous ||= versioned.journals.at(version - 1) end end -end \ No newline at end of file +end diff --git a/app/views/wiki/history.rhtml b/app/views/wiki/history.rhtml index 72f5ff33..d7e12d6c 100644 --- a/app/views/wiki/history.rhtml +++ b/app/views/wiki/history.rhtml @@ -21,7 +21,7 @@ <%= link_to ver.version, :action => 'index', :page => @page.title, :version => ver.version %> <%= radio_button_tag('version', ver.version, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < @versions.size) %> <%= radio_button_tag('version_from', ver.version, (line_num==2), :id => "cbto-#{line_num}") if show_diff && (line_num > 1) %> - <%= format_time(ver.updated_at) %> + <%= format_time(ver.created_at) %> <%= link_to_user ver.user %> <%=h ver.notes %> <%= link_to l(:button_annotate), :action => 'annotate', :page => @page.title, :version => ver.version %> From 331d98c2d26f683e790689bb738fe8f2345bedab Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 10 Aug 2010 17:09:28 +0200 Subject: [PATCH 057/777] fix first version for wiki --- app/controllers/wiki_controller.rb | 1 + app/models/wiki_content.rb | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index 5c3f38e7..de72996c 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -84,6 +84,7 @@ class WikiController < ApplicationController end #@content.text = params[:content][:text] #@content.comments = params[:content][:comments] + @content.init_journal(User.current, params[:content][:comments]) @content.attributes = params[:content] @content.author = User.current # if page is new @page.save will also save content, but not if page isn't a new record diff --git a/app/models/wiki_content.rb b/app/models/wiki_content.rb index 945fcaec..debe8093 100644 --- a/app/models/wiki_content.rb +++ b/app/models/wiki_content.rb @@ -57,15 +57,11 @@ class WikiContent < ActiveRecord::Base WikiContentJournal.class_eval do attr_protected :data after_save :compress_version_text - after_save :move_comments_to_notes # Wiki Content might be large and the data should possibly be compressed def compress_version_text self.text = changes["text"].last if changes["text"] - end - - def move_comments_to_notes - self.notes = changes.delete("comments").last if changes["comments"] + self.text ||= self.versioned.text end def text=(plain) From bbd131ad8da57810bad4240cfaaa39b132a2a23a Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 10 Aug 2010 17:12:28 +0200 Subject: [PATCH 058/777] Update acts_as_journalized --- vendor/plugins/acts_as_journalized | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/plugins/acts_as_journalized b/vendor/plugins/acts_as_journalized index de6525fb..f7a5e2d2 160000 --- a/vendor/plugins/acts_as_journalized +++ b/vendor/plugins/acts_as_journalized @@ -1 +1 @@ -Subproject commit de6525fb37efc6807b418bb959f1bdbd9c5576ba +Subproject commit f7a5e2d2903829f98c8e2e4dcb33e9891b918e49 From 8458dc23d4b89d6f42bf356d9589753f1f0908e5 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:29:46 +0000 Subject: [PATCH 059/777] Merged r3903 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3953 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/functional/account_controller_test.rb | 23 ++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/functional/account_controller_test.rb b/test/functional/account_controller_test.rb index 17d19dfe..ce3d13f1 100644 --- a/test/functional/account_controller_test.rb +++ b/test/functional/account_controller_test.rb @@ -153,4 +153,27 @@ class AccountControllerTest < ActionController::TestCase assert_redirected_to '' assert_nil @request.session[:user_id] end + + context "GET #register" do + context "with self registration on" do + setup do + Setting.self_registration = '3' + get :register + end + + should_respond_with :success + should_render_template :register + should_assign_to :user + end + + context "with self registration off" do + setup do + Setting.self_registration = '0' + get :register + end + + should_redirect_to('/') { home_url } + end + end + end From c731d1120914583e226b9bc315900c72767619cb Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:29:51 +0000 Subject: [PATCH 060/777] Merged r3904 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3954 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/functional/account_controller_test.rb | 44 +++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/test/functional/account_controller_test.rb b/test/functional/account_controller_test.rb index ce3d13f1..61ad9743 100644 --- a/test/functional/account_controller_test.rb +++ b/test/functional/account_controller_test.rb @@ -175,5 +175,47 @@ class AccountControllerTest < ActionController::TestCase should_redirect_to('/') { home_url } end end - + + # See integration/account_test.rb for the full test + context "POST #register" do + context "with self registration on automatic" do + setup do + Setting.self_registration = '3' + post :register, :user => { + :login => 'register', + :password => 'test', + :password_confirmation => 'test', + :firstname => 'John', + :lastname => 'Doe', + :mail => 'register@example.com' + } + end + + should_respond_with :redirect + should_assign_to :user + should_redirect_to('my page') { {:controller => 'my', :action => 'account'} } + + should "create a new user" do + user = User.last(:conditions => {:login => 'register'}) + assert user + assert_kind_of User, user + end + + should 'set the user status to active' do + user = User.last(:conditions => {:login => 'register'}) + assert user + assert_equal User::STATUS_ACTIVE, user.status + end + end + + context "with self registration off" do + setup do + Setting.self_registration = '0' + post :register + end + + should_redirect_to('/') { home_url } + end + end + end From ae3d542664147df35742c9255f3c6f968522baec Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:29:57 +0000 Subject: [PATCH 061/777] Merged r3905 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3955 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/functional/account_controller_test.rb | 6 +----- test/test_helper.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/test/functional/account_controller_test.rb b/test/functional/account_controller_test.rb index 61ad9743..2a8c9c66 100644 --- a/test/functional/account_controller_test.rb +++ b/test/functional/account_controller_test.rb @@ -195,11 +195,7 @@ class AccountControllerTest < ActionController::TestCase should_assign_to :user should_redirect_to('my page') { {:controller => 'my', :action => 'account'} } - should "create a new user" do - user = User.last(:conditions => {:login => 'register'}) - assert user - assert_kind_of User, user - end + should_create_a_new_user { User.last(:conditions => {:login => 'register'}) } should 'set the user status to active' do user = User.last(:conditions => {:login => 'register'}) diff --git a/test/test_helper.rb b/test/test_helper.rb index c934e1bc..15a1f157 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -162,4 +162,13 @@ class ActiveSupport::TestCase end end end + + def self.should_create_a_new_user(&block) + should "create a new user" do + user = instance_eval &block + assert user + assert_kind_of User, user + assert !user.new_record? + end + end end From 8dde6e019d041a79d7adc4e2b3c019b856085a0c Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:30:03 +0000 Subject: [PATCH 062/777] Merged r3906 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3956 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/account_controller.rb | 12 ++++++------ app/models/user.rb | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb index b0a5b42a..5fa56b16 100644 --- a/app/controllers/account_controller.rb +++ b/app/controllers/account_controller.rb @@ -83,9 +83,9 @@ class AccountController < ApplicationController else @user = User.new(params[:user]) @user.admin = false - @user.status = User::STATUS_REGISTERED + @user.register if session[:auth_source_registration] - @user.status = User::STATUS_ACTIVE + @user.activate @user.login = session[:auth_source_registration][:login] @user.auth_source_id = session[:auth_source_registration][:auth_source_id] if @user.save @@ -116,8 +116,8 @@ class AccountController < ApplicationController token = Token.find_by_action_and_value('register', params[:token]) redirect_to(home_url) && return unless token and !token.expired? user = token.user - redirect_to(home_url) && return unless user.status == User::STATUS_REGISTERED - user.status = User::STATUS_ACTIVE + redirect_to(home_url) && return unless user.registered? + user.activate if user.save token.destroy flash[:notice] = l(:notice_account_activated) @@ -170,7 +170,7 @@ class AccountController < ApplicationController user.mail = registration['email'] unless registration['email'].nil? user.firstname, user.lastname = registration['fullname'].split(' ') unless registration['fullname'].nil? user.random_password - user.status = User::STATUS_REGISTERED + user.register case Setting.self_registration when '1' @@ -241,7 +241,7 @@ class AccountController < ApplicationController # Pass a block for behavior when a user fails to save def register_automatically(user, &block) # Automatic activation - user.status = User::STATUS_ACTIVE + user.activate user.last_login_on = Time.now if user.save self.logged_user = user diff --git a/app/models/user.rb b/app/models/user.rb index db18db49..c5c638f9 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -164,6 +164,30 @@ class User < Principal self.status == STATUS_LOCKED end + def activate + self.status = STATUS_ACTIVE + end + + def register + self.status = STATUS_REGISTERED + end + + def lock + self.status = STATUS_LOCKED + end + + def activate! + update_attribute(:status, STATUS_ACTIVE) + end + + def register! + update_attribute(:status, STATUS_REGISTERED) + end + + def lock! + update_attribute(:status, STATUS_LOCKED) + end + def check_password?(clear_password) if auth_source_id.present? auth_source.authenticate(self.login, clear_password) From acaa223cf887949a307a9156045cbf0ad4671351 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:30:23 +0000 Subject: [PATCH 063/777] Merged r3907 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3957 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/mailer.rb | 2 +- config/locales/bg.yml | 2 +- config/locales/bs.yml | 2 +- config/locales/ca.yml | 2 +- config/locales/cs.yml | 2 +- config/locales/da.yml | 2 +- config/locales/de.yml | 2 +- config/locales/el.yml | 2 +- config/locales/en-GB.yml | 2 +- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- config/locales/eu.yml | 2 +- config/locales/fi.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/gl.yml | 2 +- config/locales/he.yml | 2 +- config/locales/hr.yml | 2 +- config/locales/hu.yml | 2 +- config/locales/id.yml | 2 +- config/locales/it.yml | 2 +- config/locales/ja.yml | 2 +- config/locales/ko.yml | 2 +- config/locales/lt.yml | 2 +- config/locales/lv.yml | 2 +- config/locales/mn.yml | 2 +- config/locales/nl.yml | 2 +- config/locales/no.yml | 2 +- config/locales/pl.yml | 2 +- config/locales/pt-BR.yml | 2 +- config/locales/pt.yml | 2 +- config/locales/ro.yml | 2 +- config/locales/ru.yml | 2 +- config/locales/sk.yml | 2 +- config/locales/sl.yml | 2 +- config/locales/sr-CY.yml | 2 +- config/locales/sr.yml | 2 +- config/locales/sv.yml | 2 +- config/locales/th.yml | 2 +- config/locales/tr.yml | 2 +- config/locales/uk.yml | 2 +- config/locales/vi.yml | 2 +- config/locales/zh-TW.yml | 2 +- config/locales/zh.yml | 2 +- test/unit/mailer_test.rb | 1 + 44 files changed, 44 insertions(+), 43 deletions(-) diff --git a/app/models/mailer.rb b/app/models/mailer.rb index f39c5320..8f50b1b7 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -80,7 +80,7 @@ class Mailer < ActionMailer::Base def reminder(user, issues, days) set_language_if_valid user.language recipients user.mail - subject l(:mail_subject_reminder, issues.size) + subject l(:mail_subject_reminder, :count => issues.size, :days => days) body :issues => issues, :days => days, :issues_url => url_for(:controller => 'issues', :action => 'index', :set_filter => 1, :assigned_to_id => user.id, :sort_key => 'due_date', :sort_order => 'asc') diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 051bbdaf..8b2b2370 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -704,7 +704,7 @@ bg: text_subprojects_destroy_warning: "Its subproject(s): {{value}} will be also deleted." label_and_its_subprojects: "{{value}} and its subprojects" mail_body_reminder: "{{count}} issue(s) that are assigned to you are due in the next {{days}} days:" - mail_subject_reminder: "{{count}} issue(s) due in the next days" + mail_subject_reminder: "{{count}} issue(s) due in the next {{days}} days" text_user_wrote: "{{value}} wrote:" label_duplicated_by: duplicated by setting_enabled_scm: Enabled SCM diff --git a/config/locales/bs.yml b/config/locales/bs.yml index d3fe0a12..3d476ae1 100644 --- a/config/locales/bs.yml +++ b/config/locales/bs.yml @@ -184,7 +184,7 @@ bs: mail_body_account_information: Informacija o vašem korisničkom računu mail_subject_account_activation_request: "{{value}} zahtjev za aktivaciju korisničkog računa" mail_body_account_activation_request: "Novi korisnik ({{value}}) se registrovao. Korisnički račun čeka vaše odobrenje za aktivaciju:" - mail_subject_reminder: "{{count}} aktivnost(i) u kašnjenju u narednim danima" + mail_subject_reminder: "{{count}} aktivnost(i) u kašnjenju u narednim {{days}} danima" mail_body_reminder: "{{count}} aktivnost(i) koje su dodjeljenje vama u narednim {{days}} danima:" gui_validation_error: 1 greška diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 5f54930d..1e47d3d6 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -166,7 +166,7 @@ ca: mail_body_account_information: Informació del compte mail_subject_account_activation_request: "Sol·licitud d'activació del compte de {{value}}" mail_body_account_activation_request: "S'ha registrat un usuari nou ({{value}}). El seu compte està pendent d'aprovació:" - mail_subject_reminder: "%d assumptes venceran els següents {{count}} dies" + mail_subject_reminder: "{{count}} assumptes venceran els següents {{days}} dies" mail_body_reminder: "{{count}} assumptes que teniu assignades venceran els següents {{days}} dies:" gui_validation_error: 1 error diff --git a/config/locales/cs.yml b/config/locales/cs.yml index b0052795..de4ad44c 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -710,7 +710,7 @@ cs: text_subprojects_destroy_warning: "Jeho podprojek(y): {{value}} budou také smazány." label_and_its_subprojects: "{{value}} a jeho podprojekty" mail_body_reminder: "{{count}} úkol(ů), které máte přiřazeny má termín během několik dní ({{days}}):" - mail_subject_reminder: "{{count}} úkol(ů) má termín během několik dní" + mail_subject_reminder: "{{count}} úkol(ů) má termín během několik dní ({{days}})" text_user_wrote: "{{value}} napsal:" label_duplicated_by: duplicated by setting_enabled_scm: Povoleno SCM diff --git a/config/locales/da.yml b/config/locales/da.yml index 06967468..b241a52d 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -791,7 +791,7 @@ da: permission_browse_repository: Gennemse repository permission_manage_repository: Administrér repository permission_manage_members: Administrér medlemmer - mail_subject_reminder: "{{count}} sag(er) har deadline i de kommende dage" + mail_subject_reminder: "{{count}} sag(er) har deadline i de kommende dage ({{days}})" permission_add_issue_notes: Tilføj noter permission_edit_messages: Redigér beskeder permission_view_issue_watchers: Se liste over overvågere diff --git a/config/locales/de.yml b/config/locales/de.yml index 05d5d963..f7f9043c 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -207,7 +207,7 @@ de: mail_body_account_information: Ihre Konto-Informationen mail_subject_account_activation_request: "Antrag auf {{value}} Kontoaktivierung" mail_body_account_activation_request: "Ein neuer Benutzer ({{value}}) hat sich registriert. Sein Konto wartet auf Ihre Genehmigung:" - mail_subject_reminder: "{{count}} Tickets müssen in den nächsten Tagen abgegeben werden" + mail_subject_reminder: "{{count}} Tickets müssen in den nächsten {{days}} Tagen abgegeben werden" mail_body_reminder: "{{count}} Tickets, die Ihnen zugewiesen sind, müssen in den nächsten {{days}} Tagen abgegeben werden:" mail_subject_wiki_content_added: "Wiki-Seite '{{page}}' hinzugefügt" mail_body_wiki_content_added: "Die Wiki-Seite '{{page}}' wurde von {{author}} hinzugefügt." diff --git a/config/locales/el.yml b/config/locales/el.yml index 6176a6c8..a9146a61 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -171,7 +171,7 @@ el: mail_body_account_information: Πληροφορίες του λογαριασμού σας mail_subject_account_activation_request: "αίτημα ενεργοποίησης λογαριασμού {{value}}" mail_body_account_activation_request: "'Ένας νέος χρήστης ({{value}}) έχει εγγραφεί. Ο λογαριασμός είναι σε στάδιο αναμονής της έγκρισης σας:" - mail_subject_reminder: "{{count}} θέμα(τα) με προθεσμία στις επόμενες ημέρες" + mail_subject_reminder: "{{count}} θέμα(τα) με προθεσμία στις επόμενες {{days}} ημέρες" mail_body_reminder: "{{count}}θέμα(τα) που έχουν ανατεθεί σε σας, με προθεσμία στις επόμενες {{days}} ημέρες:" mail_subject_wiki_content_added: "'προστέθηκε η σελίδα wiki {{page}}' " mail_body_wiki_content_added: "Η σελίδα wiki '{{page}}' προστέθηκε από τον {{author}}." diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 2c19c4f4..118efbb4 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -180,7 +180,7 @@ en-GB: mail_body_account_information: Your account information mail_subject_account_activation_request: "{{value}} account activation request" mail_body_account_activation_request: "A new user ({{value}}) has registered. The account is pending your approval:" - mail_subject_reminder: "{{count}} issue(s) due in the next days" + mail_subject_reminder: "{{count}} issue(s) due in the next {{days}} days" mail_body_reminder: "{{count}} issue(s) that are assigned to you are due in the next {{days}} days:" mail_subject_wiki_content_added: "'{{page}}' wiki page has been added" mail_body_wiki_content_added: "The '{{page}}' wiki page has been added by {{author}}." diff --git a/config/locales/en.yml b/config/locales/en.yml index 3ab25782..fb085695 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -183,7 +183,7 @@ en: mail_body_account_information: Your account information mail_subject_account_activation_request: "{{value}} account activation request" mail_body_account_activation_request: "A new user ({{value}}) has registered. The account is pending your approval:" - mail_subject_reminder: "{{count}} issue(s) due in the next days" + mail_subject_reminder: "{{count}} issue(s) due in the next {{days}} days" mail_body_reminder: "{{count}} issue(s) that are assigned to you are due in the next {{days}} days:" mail_subject_wiki_content_added: "'{{page}}' wiki page has been added" mail_body_wiki_content_added: "The '{{page}}' wiki page has been added by {{author}}." diff --git a/config/locales/es.yml b/config/locales/es.yml index 0a7a38a9..bc345dcb 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -662,7 +662,7 @@ es: mail_subject_account_activation_request: "Petición de activación de cuenta {{value}}" mail_subject_lost_password: "Tu contraseña del {{value}}" mail_subject_register: "Activación de la cuenta del {{value}}" - mail_subject_reminder: "{{count}} peticion(es) finalizan en los próximos días" + mail_subject_reminder: "{{count}} peticion(es) finalizan en los próximos {{days}} días" notice_account_activated: Su cuenta ha sido activada. Ya puede conectarse. notice_account_invalid_creditentials: Usuario o contraseña inválido. notice_account_lost_email_sent: Se le ha enviado un correo con instrucciones para elegir una nueva contraseña. diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 9f08652f..741d3298 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -180,7 +180,7 @@ eu: mail_body_account_information: Zure kontuaren informazioa mail_subject_account_activation_request: "{{value}} kontu gaitzeko eskaera" mail_body_account_activation_request: "Erabiltzaile berri bat ({{value}}) erregistratu da. Kontua zure onarpenaren zain dago:" - mail_subject_reminder: "{{count}} arazo hurrengo egunetan amaitzen d(ir)a" + mail_subject_reminder: "{{count}} arazo hurrengo {{days}} egunetan amaitzen d(ir)a" mail_body_reminder: "Zuri esleituta dauden {{count}} arazo hurrengo {{days}} egunetan amaitzen d(ir)a:" mail_subject_wiki_content_added: "'{{page}}' wiki orria gehitu da" mail_body_wiki_content_added: "{{author}}-(e)k '{{page}}' wiki orria gehitu du." diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 5556252c..b6b48bac 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -740,7 +740,7 @@ fi: text_subprojects_destroy_warning: "Tämän aliprojekti(t): {{value}} tullaan myös poistamaan." label_and_its_subprojects: "{{value}} ja aliprojektit" mail_body_reminder: "{{count}} sinulle nimettyä tapahtuma(a) erääntyy {{days}} päivä sisään:" - mail_subject_reminder: "{{count}} tapahtuma(a) erääntyy lähipäivinä" + mail_subject_reminder: "{{count}} tapahtuma(a) erääntyy {{days}} lähipäivinä" text_user_wrote: "{{value}} kirjoitti:" label_duplicated_by: kopioinut setting_enabled_scm: Versionhallinta käytettävissä diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 0efe114e..1bc12685 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -200,7 +200,7 @@ fr: mail_body_account_information: Paramètres de connexion de votre compte mail_subject_account_activation_request: "Demande d'activation d'un compte {{value}}" mail_body_account_activation_request: "Un nouvel utilisateur ({{value}}) s'est inscrit. Son compte nécessite votre approbation :" - mail_subject_reminder: "{{count}} demande(s) arrivent à échéance" + mail_subject_reminder: "{{count}} demande(s) arrivent à échéance ({{days}})" mail_body_reminder: "{{count}} demande(s) qui vous sont assignées arrivent à échéance dans les {{days}} prochains jours :" mail_subject_wiki_content_added: "Page wiki '{{page}}' ajoutée" mail_body_wiki_content_added: "La page wiki '{{page}}' a été ajoutée par {{author}}." diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 0652ce9e..2a1d97ed 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -639,7 +639,7 @@ gl: mail_subject_account_activation_request: "Petición de activación de conta {{value}}" mail_subject_lost_password: "O teu contrasinal de {{value}}" mail_subject_register: "Activación da conta de {{value}}" - mail_subject_reminder: "{{count}} petición(s) rematarán nos próximos días" + mail_subject_reminder: "{{count}} petición(s) rematarán nos próximos {{days}} días" notice_account_activated: A súa conta foi activada. Xa pode conectarse. notice_account_invalid_creditentials: Usuario ou contrasinal inválido. notice_account_lost_email_sent: Enviouse un correo con instrucións para elixir un novo contrasinal. diff --git a/config/locales/he.yml b/config/locales/he.yml index f84fd01f..532c6019 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -192,7 +192,7 @@ he: mail_body_account_information: פרטי החשבון שלך mail_subject_account_activation_request: "בקשת הפעלה לחשבון {{value}}" mail_body_account_activation_request: "משתמש חדש ({{value}}) נרשם. החשבון שלו מחכה לאישור שלך:" - mail_subject_reminder: "{{count}} נושאים מיעדים להגשה בימים הקרובים" + mail_subject_reminder: "{{count}} נושאים מיעדים להגשה בימים הקרובים ({{days}})" mail_body_reminder: "{{count}} נושאים שמיועדים אליך מיועדים להגשה בתוך {{days}} ימים:" mail_subject_wiki_content_added: "דף ה־wiki ‏'{{page}}' נוסף" mail_body_wiki_content_added: דף ה־wiki ‏'{{page}}' נוסף ע"י {{author}}. diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 424fc7dc..728a6d8e 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -176,7 +176,7 @@ hr: mail_body_account_information: Vaši korisnički podaci mail_subject_account_activation_request: "{{value}} predmet za aktivaciju korisničkog računa" mail_body_account_activation_request: "Novi korisnik ({{value}}) je registriran. Njegov korisnički račun čeka vaše odobrenje:" - mail_subject_reminder: "{{count}} predmet(a) dospijeva sljedećih dana" + mail_subject_reminder: "{{count}} predmet(a) dospijeva sljedećih {{days}} dana" mail_body_reminder: "{{count}} vama dodijeljen(ih) predmet(a) dospijeva u sljedećih {{days}} dana:" mail_subject_wiki_content_added: "'{{page}}' wiki page has been added" mail_body_wiki_content_added: "The '{{page}}' wiki page has been added by {{author}}." diff --git a/config/locales/hu.yml b/config/locales/hu.yml index a62d0732..088027f1 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -737,7 +737,7 @@ enumeration_doc_categories: Dokumentum kategóriák enumeration_activities: Tevékenységek (idő rögzítés) mail_body_reminder: "{{count}} neked kiosztott feladat határidős az elkövetkező {{days}} napban:" - mail_subject_reminder: "{{count}} feladat határidős az elkövetkező napokban" + mail_subject_reminder: "{{count}} feladat határidős az elkövetkező {{days}} napokban" text_user_wrote: "{{value}} írta:" label_duplicated_by: duplikálta setting_enabled_scm: Forráskódkezelő (SCM) engedélyezése diff --git a/config/locales/id.yml b/config/locales/id.yml index 5a14cda5..ec6688e5 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -177,7 +177,7 @@ id: mail_body_account_information: Informasi akun anda mail_subject_account_activation_request: "Permintaan aktivasi akun {{value}} " mail_body_account_activation_request: "Pengguna baru ({{value}}) sudan didaftarkan. Akun tersebut menunggu persetujuan anda:" - mail_subject_reminder: "{{count}} masalah harus selesai pada hari berikutnya" + mail_subject_reminder: "{{count}} masalah harus selesai pada hari berikutnya ({{days}})" mail_body_reminder: "{{count}} masalah yang ditugaskan pada anda harus selesai dalam {{days}} hari kedepan:" mail_subject_wiki_content_added: "'{{page}}' halaman wiki sudah ditambahkan" mail_body_wiki_content_added: "The '{{page}}' halaman wiki sudah ditambahkan oleh {{author}}." diff --git a/config/locales/it.yml b/config/locales/it.yml index 758928f2..bab1c6a9 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -717,7 +717,7 @@ it: text_subprojects_destroy_warning: "Anche i suoi sottoprogetti: {{value}} verranno eliminati." label_and_its_subprojects: "{{value}} ed i suoi sottoprogetti" mail_body_reminder: "{{count}} segnalazioni che ti sono state assegnate scadranno nei prossimi {{days}} giorni:" - mail_subject_reminder: "{{count}} segnalazioni in scadenza nei prossimi giorni" + mail_subject_reminder: "{{count}} segnalazioni in scadenza nei prossimi {{days}} giorni" text_user_wrote: "{{value}} ha scritto:" label_duplicated_by: duplicato da setting_enabled_scm: SCM abilitato diff --git a/config/locales/ja.yml b/config/locales/ja.yml index dc69c979..c82155b8 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -214,7 +214,7 @@ ja: mail_body_account_information: アカウント情報 mail_subject_account_activation_request: "{{value}} アカウントの承認要求" mail_body_account_activation_request: "新しいユーザ {{value}} が登録されました。このアカウントはあなたの承認待ちです:" - mail_subject_reminder: "{{count}}件のチケットが期日間近です" + mail_subject_reminder: "{{count}}件のチケットが{{days}}期日間近です" mail_body_reminder: "{{count}}件の担当チケットの期日が{{days}}日以内に到来します:" mail_subject_wiki_content_added: "Wikiページ {{page}} が追加されました" mail_body_wiki_content_added: "{{author}} によってWikiページ {{page}} が追加されました。" diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 6ba93edc..d79c86cb 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -228,7 +228,7 @@ ko: mail_subject_account_activation_request: "{{value}} 계정 활성화 요청" mail_body_account_activation_request: "새 사용자({{value}})가 등록되었습니다. 관리자님의 승인을 기다리고 있습니다.:" mail_body_reminder: "당신이 맡고 있는 일감 {{count}}개의 완료 기한이 {{days}}일 후 입니다." - mail_subject_reminder: "내일이 만기인 일감 {{count}}개" + mail_subject_reminder: "내일이 만기인 일감 {{count}}개 ({{days}})" mail_subject_wiki_content_added: "위키페이지 '{{page}}'이(가) 추가되었습니다." mail_subject_wiki_content_updated: "'위키페이지 {{page}}'이(가) 수정되었습니다." mail_body_wiki_content_added: "{{author}}이(가) 위키페이지 '{{page}}'을(를) 추가하였습니다." diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 675c3a14..9bcafc71 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -237,7 +237,7 @@ lt: mail_body_account_information: Informacija apie Jūsų paskyrą mail_subject_account_activation_request: "{{value}} paskyros aktyvavimo prašymas" mail_body_account_activation_request: "Užsiregistravo naujas vartotojas ({{value}}). Jo paskyra laukia jūsų patvirtinimo:" - mail_subject_reminder: "{{count}} darbas(ai) po kelių dienų" + mail_subject_reminder: "{{count}} darbas(ai) po kelių {{days}} dienų" mail_body_reminder: "{{count}} darbas(ai), kurie yra jums priskirti, baigiasi po {{days}} dienų(os):" mail_subject_wiki_content_added: "'{{page}}' pridėtas wiki puslapis" mail_body_wiki_content_added: "The '{{page}}' wiki puslapi pridėjo {{author}}." diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 4d49bd12..351f8528 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -172,7 +172,7 @@ lv: mail_body_account_information: Jūsu konta informācija mail_subject_account_activation_request: "{{value}} konta aktivizācijas pieprasījums" mail_body_account_activation_request: "Jauns lietotājs ({{value}}) ir reģistrēts. Lietotāja konts gaida Jūsu apstiprinājumu:" - mail_subject_reminder: "{{count}} uzdevums(i) sagaidāms(i) tuvākajās dienās" + mail_subject_reminder: "{{count}} uzdevums(i) sagaidāms(i) tuvākajās {{days}} dienās" mail_body_reminder: "{{count}} uzdevums(i), kurš(i) ir nozīmēts(i) Jums, sagaidāms(i) tuvākajās {{days}} dienās:" mail_subject_wiki_content_added: "'{{page}}' Wiki lapa pievienota" mail_body_wiki_content_added: "The '{{page}}' Wiki lapu pievienojis {{author}}." diff --git a/config/locales/mn.yml b/config/locales/mn.yml index 63e80802..568e1f34 100644 --- a/config/locales/mn.yml +++ b/config/locales/mn.yml @@ -176,7 +176,7 @@ mn: mail_body_account_information: Таны дансны тухай мэдээлэл mail_subject_account_activation_request: "{{value}} дансыг идэвхжүүлэх хүсэлт" mail_body_account_activation_request: "Шинэ хэрэглэгч ({{value}}) бүртгүүлсэн байна. Таны баталгаажуулахыг хүлээж байна:" - mail_subject_reminder: "Дараагийн өдрүүдэд {{count}} асуудлыг шийдэх хэрэгтэй" + mail_subject_reminder: "Дараагийн өдрүүдэд {{count}} асуудлыг шийдэх хэрэгтэй ({{days}})" mail_body_reminder: "Танд оноогдсон {{count}} асуудлуудыг дараагийн {{days}} өдрүүдэд шийдэх хэрэгтэй:" mail_subject_wiki_content_added: "'{{page}}' wiki page has been added" mail_body_wiki_content_added: "The '{{page}}' wiki page has been added by {{author}}." diff --git a/config/locales/nl.yml b/config/locales/nl.yml index e24d5cbb..4472a19d 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -601,7 +601,7 @@ nl: mail_subject_account_activation_request: "{{value}} accountactivatieverzoek" mail_subject_lost_password: "uw {{value}} wachtwoord" mail_subject_register: "uw {{value}} accountactivatie" - mail_subject_reminder: "{{count}} issue(s) die voldaan moeten zijn in de komende dagen." + mail_subject_reminder: "{{count}} issue(s) die voldaan moeten zijn in de komende {{days}} dagen." notice_account_activated: uw account is geactiveerd. u kunt nu inloggen. notice_account_invalid_creditentials: Incorrecte gebruikersnaam of wachtwoord notice_account_lost_email_sent: Er is een e-mail naar u verstuurd met instructies over het kiezen van een nieuw wachtwoord. diff --git a/config/locales/no.yml b/config/locales/no.yml index 53bac51b..7d49537d 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -163,7 +163,7 @@ mail_body_account_information: Informasjon om din konto mail_subject_account_activation_request: "{{value}} kontoaktivering" mail_body_account_activation_request: "En ny bruker ({{value}}) er registrert, og avventer din godkjenning:" - mail_subject_reminder: "{{count}} sak(er) har frist de kommende dagene" + mail_subject_reminder: "{{count}} sak(er) har frist de kommende {{days}} dagene" mail_body_reminder: "{{count}} sak(er) som er tildelt deg har frist de kommende {{days}} dager:" gui_validation_error: 1 feil diff --git a/config/locales/pl.yml b/config/locales/pl.yml index efa2415d..2dadc847 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -640,7 +640,7 @@ pl: mail_subject_account_activation_request: "Zapytanie aktywacyjne konta {{value}}" mail_subject_lost_password: "Twoje hasło do {{value}}" mail_subject_register: "Aktywacja konta w {{value}}" - mail_subject_reminder: "Uwaga na terminy, masz zagadnienia do obsłużenia w ciągu następnych {{count}} dni!" + mail_subject_reminder: "Uwaga na terminy, masz zagadnienia do obsłużenia w ciągu następnych {{count}} dni! ({{days}})" notice_account_activated: Twoje konto zostało aktywowane. Możesz się zalogować. notice_account_invalid_creditentials: Zły użytkownik lub hasło notice_account_lost_email_sent: Email z instrukcjami zmiany hasła został wysłany do Ciebie. diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 9365505d..a66f2371 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -196,7 +196,7 @@ pt-BR: mail_body_account_information: Informações sobre sua conta mail_subject_account_activation_request: "{{value}} - Requisição de ativação de conta" mail_body_account_activation_request: "Um novo usuário ({{value}}) se registrou. A conta está aguardando sua aprovação:" - mail_subject_reminder: "{{count}} tarefa(s) com data prevista para os próximos dias" + mail_subject_reminder: "{{count}} tarefa(s) com data prevista para os próximos {{days}} dias" mail_body_reminder: "{{count}} tarefa(s) para você com data prevista para os próximos {{days}} dias:" gui_validation_error: 1 erro diff --git a/config/locales/pt.yml b/config/locales/pt.yml index c8dafd84..615f3164 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -181,7 +181,7 @@ pt: mail_body_account_information: Informação da sua conta mail_subject_account_activation_request: "Pedido de activação da conta {{value}}" mail_body_account_activation_request: "Um novo utilizador ({{value}}) registou-se. A sua conta está à espera de aprovação:" - mail_subject_reminder: "{{count}} tarefa(s) para entregar nos próximos dias" + mail_subject_reminder: "{{count}} tarefa(s) para entregar nos próximos {{days}} dias" mail_body_reminder: "{{count}} tarefa(s) que estão atribuídas a si estão agendadas para estarem completas nos próximos {{days}} dias:" gui_validation_error: 1 erro diff --git a/config/locales/ro.yml b/config/locales/ro.yml index 5733ddeb..45fdd1ea 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -164,7 +164,7 @@ ro: mail_body_account_information: Informații despre contul dumneavoastră mail_subject_account_activation_request: "Cerere de activare a contului {{value}}" mail_body_account_activation_request: "S-a înregistrat un utilizator nou ({{value}}). Contul așteaptă aprobarea dumneavoastră:" - mail_subject_reminder: "{{count}} tichete trebuie rezolvate în următoarele zile" + mail_subject_reminder: "{{count}} tichete trebuie rezolvate în următoarele {{days}} zile" mail_body_reminder: "{{count}} tichete atribuite dumneavoastră trebuie rezolvate în următoarele {{days}} zile:" gui_validation_error: o eroare diff --git a/config/locales/ru.yml b/config/locales/ru.yml index cce12362..064cbc28 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -755,7 +755,7 @@ ru: mail_subject_account_activation_request: "Запрос на активацию пользователя в системе {{value}}" mail_subject_lost_password: "Ваш {{value}} пароль" mail_subject_register: "Активация учетной записи {{value}}" - mail_subject_reminder: "{{count}} назначенных на Вас задач в ближайшие дни" + mail_subject_reminder: "{{count}} назначенных на Вас задач в ближайшие {{days}} дни" notice_account_activated: Ваша учетная запись активирована. Вы можете войти. notice_account_invalid_creditentials: Неправильное имя пользователя или пароль diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 22f5799f..0b2351e6 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -708,7 +708,7 @@ sk: text_subprojects_destroy_warning: "Jeho podprojekt(y): {{value}} budú takisto vymazané." label_and_its_subprojects: "{{value}} a jeho podprojekty" mail_body_reminder: "{{count}} úloha(y), ktorá(é) je(sú) vám priradený(é), ma(jú) byť hotova(é) za {{days}} dní:" - mail_subject_reminder: "{{count}} úloha(y) ma(jú) byť hotova(é) za pár dní" + mail_subject_reminder: "{{count}} úloha(y) ma(jú) byť hotova(é) za pár {{days}} dní" text_user_wrote: "{{value}} napísal:" label_duplicated_by: duplikovaný setting_enabled_scm: Zapnúť SCM diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 77a15575..aac2e433 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -167,7 +167,7 @@ sl: mail_body_account_information: Informacije o vašem računu mail_subject_account_activation_request: "{{value}} zahtevek za aktivacijo računa" mail_body_account_activation_request: "Registriral se je nov uporabnik ({{value}}). Račun čaka na vašo odobritev:" - mail_subject_reminder: "{{count}} zahtevek(zahtevki) zapadejo v naslednjih dneh" + mail_subject_reminder: "{{count}} zahtevek(zahtevki) zapadejo v naslednjih {{days}} dneh" mail_body_reminder: "{{count}} zahtevek(zahtevki), ki so vam dodeljeni bodo zapadli v naslednjih {{days}} dneh:" gui_validation_error: 1 napaka diff --git a/config/locales/sr-CY.yml b/config/locales/sr-CY.yml index 11f55847..39cc5dcb 100644 --- a/config/locales/sr-CY.yml +++ b/config/locales/sr-CY.yml @@ -178,7 +178,7 @@ sr-CY: mail_body_account_information: Информације о вашем налогу mail_subject_account_activation_request: "Захтев за активацију налога {{value}}" mail_body_account_activation_request: "Нови корисник ({{value}}) је регистрован. Налог чека на ваше одобрење:" - mail_subject_reminder: "{{count}} проблема доспева наредних дана" + mail_subject_reminder: "{{count}} проблема доспева наредних {{days}} дана" mail_body_reminder: "{{count}} проблема додељених вама доспева у наредних {{days}} дана:" mail_subject_wiki_content_added: "'{{page}}' wiki страна је додато" mail_body_wiki_content_added: "{{author}} је додао '{{page}}' wiki страна." diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 50140b7d..f52d9e06 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -178,7 +178,7 @@ sr: mail_body_account_information: Informacije o vašem nalogu mail_subject_account_activation_request: "Zahtev za aktivaciju naloga {{value}}" mail_body_account_activation_request: "Novi korisnik ({{value}}) je registrovan. Nalog čeka na vaše odobrenje:" - mail_subject_reminder: "{{count}} problema dospeva narednih dana" + mail_subject_reminder: "{{count}} problema dospeva narednih {{days}} dana" mail_body_reminder: "{{count}} problema dodeljenih vama dospeva u narednih {{days}} dana:" mail_subject_wiki_content_added: "'{{page}}' wiki strana je dodato" mail_body_wiki_content_added: "{{author}} je dodao '{{page}}' wiki strana." diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 23450007..35ebc105 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -234,7 +234,7 @@ sv: mail_body_account_information: Din kontoinformation mail_subject_account_activation_request: "{{value}} begäran om kontoaktivering" mail_body_account_activation_request: "En ny användare ({{value}}) har registrerat sig och avvaktar ditt godkännande:" - mail_subject_reminder: "{{count}} ärende(n) har deadline under de kommande dagarna" + mail_subject_reminder: "{{count}} ärende(n) har deadline under de kommande {{days}} dagarna" mail_body_reminder: "{{count}} ärende(n) som är tilldelat dig har deadline under de {{days}} dagarna:" mail_subject_wiki_content_added: "'{{page}}' wikisida has lagts till" mail_body_wiki_content_added: The '{{page}}' wikisida has lagts till av {{author}}. diff --git a/config/locales/th.yml b/config/locales/th.yml index 5f68696e..2c127f3d 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -707,7 +707,7 @@ th: enumeration_activities: กิจกรรม (ใช้ในการติดตามเวลา) label_and_its_subprojects: "{{value}} and its subprojects" mail_body_reminder: "{{count}} issue(s) that are assigned to you are due in the next {{days}} days:" - mail_subject_reminder: "{{count}} issue(s) due in the next days" + mail_subject_reminder: "{{count}} issue(s) due in the next {{days}} days" text_user_wrote: "{{value}} wrote:" label_duplicated_by: duplicated by setting_enabled_scm: Enabled SCM diff --git a/config/locales/tr.yml b/config/locales/tr.yml index bc7bcbf7..db433092 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -749,7 +749,7 @@ tr: text_user_wrote: "{{value}} wrote:" setting_mail_handler_api_enabled: Enable WS for incoming emails label_and_its_subprojects: "{{value}} and its subprojects" - mail_subject_reminder: "{{count}} issue(s) due in the next days" + mail_subject_reminder: "{{count}} issue(s) due in the next {{days}} days" setting_mail_handler_api_key: API key setting_commit_logs_encoding: Commit messages encoding general_csv_decimal_separator: '.' diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 5ab98332..1a590dc0 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -706,7 +706,7 @@ uk: text_subprojects_destroy_warning: "Its subproject(s): {{value}} will be also deleted." label_and_its_subprojects: "{{value}} and its subprojects" mail_body_reminder: "{{count}} issue(s) that are assigned to you are due in the next {{days}} days:" - mail_subject_reminder: "{{count}} issue(s) due in the next days" + mail_subject_reminder: "{{count}} issue(s) due in the next {{days}} days" text_user_wrote: "{{value}} wrote:" label_duplicated_by: duplicated by setting_enabled_scm: Enabled SCM diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 9d2af5e8..f8ca507b 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -226,7 +226,7 @@ vi: mail_body_account_information: Thông tin về tài khoản mail_subject_account_activation_request: "{{value}}: Yêu cầu chứng thực tài khoản" mail_body_account_activation_request: "Người dùng ({{value}}) mới đăng ký và cần bạn xác nhận:" - mail_subject_reminder: "{{count}} vấn đề hết hạn trong các ngày tới" + mail_subject_reminder: "{{count}} vấn đề hết hạn trong các {{days}} ngày tới" mail_body_reminder: "{{count}} vấn đề gán cho bạn sẽ hết hạn trong {{days}} ngày tới:" gui_validation_error: 1 lỗi diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index fc5f557d..5a08041c 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -273,7 +273,7 @@ mail_body_account_information: 您的 Redmine 帳號資訊 mail_subject_account_activation_request: Redmine 帳號啟用需求通知 mail_body_account_activation_request: "有位新用戶 ({{value}}) 已經完成註冊,正等候您的審核:" - mail_subject_reminder: "您有 {{count}} 個項目即將到期" + mail_subject_reminder: "您有 {{count}} 個項目即將到期 ({{days}})" mail_body_reminder: "{{count}} 個指派給您的項目,將於 {{days}} 天之內到期:" mail_subject_wiki_content_added: "'{{page}}' wiki 頁面已被新增" mail_body_wiki_content_added: "The '{{page}}' wiki 頁面已被 {{author}} 新增。" diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 3f05306b..87d43068 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -200,7 +200,7 @@ zh: mail_body_account_information: 您的帐号信息 mail_subject_account_activation_request: "{{value}}帐号激活请求" mail_body_account_activation_request: "新用户({{value}})已完成注册,正在等候您的审核:" - mail_subject_reminder: "{{count}} 个问题需要尽快解决" + mail_subject_reminder: "{{count}} 个问题需要尽快解决 ({{days}})" mail_body_reminder: "指派给您的 {{count}} 个问题需要在 {{days}} 天内完成:" mail_subject_wiki_content_added: "'{{page}}' wiki页面已添加" mail_body_wiki_content_added: "'{{page}}' wiki页面已由 {{author}} 添加。" diff --git a/test/unit/mailer_test.rb b/test/unit/mailer_test.rb index f1fc2502..a5932d32 100644 --- a/test/unit/mailer_test.rb +++ b/test/unit/mailer_test.rb @@ -352,6 +352,7 @@ class MailerTest < ActiveSupport::TestCase mail = ActionMailer::Base.deliveries.last assert mail.bcc.include?('dlopper@somenet.foo') assert mail.body.include?('Bug #3: Error 281 when updating a recipe') + assert_equal '1 issue(s) due in the next 42 days', mail.subject end def last_email From 7a9fab774865b0db1f2c8485922d7acc3a899b8f Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:30:29 +0000 Subject: [PATCH 064/777] Merged r3908 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3958 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- public/stylesheets/application.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index 59a2c3ed..520ed837 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -287,8 +287,8 @@ fieldset#filters td.add-filter { text-align: right; vertical-align: top; } .buttons { font-size: 0.9em; margin-bottom: 1.4em; margin-top: 1em; } div#issue-changesets {float:right; width:45%; margin-left: 1em; margin-bottom: 1em; background: #fff; padding-left: 1em; font-size: 90%;} -div#issue-changesets .changeset { padding: 4px;} -div#issue-changesets .changeset { border-bottom: 1px solid #ddd; } +div#issue-changesets div.changeset { padding: 4px;} +div#issue-changesets div.changeset { border-bottom: 1px solid #ddd; } div#issue-changesets p { margin-top: 0; margin-bottom: 1em;} div#activity dl, #search-results { margin-left: 2em; } From c20e85e4dd0ed2301a42c442f9a01a43342843be Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:30:35 +0000 Subject: [PATCH 065/777] Merged r3909 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3959 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/admin/_menu.rhtml | 21 +++------------------ lib/redmine.rb | 17 ++++++++++++++++- 2 files changed, 19 insertions(+), 19 deletions(-) diff --git a/app/views/admin/_menu.rhtml b/app/views/admin/_menu.rhtml index a8de8885..bd3abebe 100644 --- a/app/views/admin/_menu.rhtml +++ b/app/views/admin/_menu.rhtml @@ -1,20 +1,5 @@
    -
      -
    • <%= link_to l(:label_project_plural), {:controller => 'admin', :action => 'projects'}, :class => 'projects' %>
    • -
    • <%= link_to l(:label_user_plural), {:controller => 'users'}, :class => 'users' %>
    • -
    • <%= link_to l(:label_group_plural), {:controller => 'groups'}, :class => 'groups' %>
    • -
    • <%= link_to l(:label_role_and_permissions), {:controller => 'roles'}, :class => 'roles' %>
    • -
    • <%= link_to l(:label_tracker_plural), {:controller => 'trackers'}, :class => 'trackers' %>
    • -
    • <%= link_to l(:label_issue_status_plural), {:controller => 'issue_statuses'}, :class => 'issue_statuses' %>
    • -
    • <%= link_to l(:label_workflow), {:controller => 'workflows', :action => 'edit'}, :class => 'workflows' %>
    • -
    • <%= link_to l(:label_custom_field_plural), {:controller => 'custom_fields'}, :class => 'custom_fields' %>
    • -
    • <%= link_to l(:label_enumerations), {:controller => 'enumerations'}, :class => 'enumerations' %>
    • -
    • <%= link_to l(:label_settings), {:controller => 'settings'}, :class => 'settings' %>
    • -
    • <%= link_to l(:label_ldap_authentication), {:controller => 'ldap_auth_sources', :action => 'index'}, :class => 'server_authentication' %>
    • - <% menu_items_for(:admin_menu) do |item| -%> -
    • <%= link_to h(item.caption), item.url, item.html_options %>
    • - <% end -%> -
    • <%= link_to l(:label_plugins), {:controller => 'admin', :action => 'plugins'}, :class => 'plugins' %>
    • -
    • <%= link_to l(:label_information_plural), {:controller => 'admin', :action => 'info'}, :class => 'info' %>
    • -
    +
      + <%= render_menu :admin_menu %> +
    diff --git a/lib/redmine.rb b/lib/redmine.rb index 238ee110..b95166e7 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -157,7 +157,22 @@ Redmine::MenuManager.map :application_menu do |menu| end Redmine::MenuManager.map :admin_menu do |menu| - # Empty + menu.push :projects, {:controller => 'admin', :action => 'projects'}, :caption => :label_project_plural + menu.push :users, {:controller => 'users'}, :caption => :label_user_plural + menu.push :groups, {:controller => 'groups'}, :caption => :label_group_plural + menu.push :roles, {:controller => 'roles'}, :caption => :label_role_and_permissions + menu.push :trackers, {:controller => 'trackers'}, :caption => :label_tracker_plural + menu.push :issue_statuses, {:controller => 'issue_statuses'}, :caption => :label_issue_status_plural, + :html => {:class => 'issue_statuses'} + menu.push :workflows, {:controller => 'workflows', :action => 'edit'}, :caption => :label_workflow + menu.push :custom_fields, {:controller => 'custom_fields'}, :caption => :label_custom_field_plural, + :html => {:class => 'custom_fields'} + menu.push :enumerations, {:controller => 'enumerations'} + menu.push :settings, {:controller => 'settings'} + menu.push :ldap_authentication, {:controller => 'ldap_auth_sources', :action => 'index'}, + :html => {:class => 'server_authentication'} + menu.push :plugins, {:controller => 'admin', :action => 'plugins'}, :last => true + menu.push :info, {:controller => 'admin', :action => 'info'}, :caption => :label_information_plural, :last => true end Redmine::MenuManager.map :project_menu do |menu| From a6408945e53063424f3e43cb950d52a9ad873591 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:30:41 +0000 Subject: [PATCH 066/777] Merged r3910 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3960 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/projects/_form.rhtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/projects/_form.rhtml b/app/views/projects/_form.rhtml index 30848e4c..fbc6714c 100644 --- a/app/views/projects/_form.rhtml +++ b/app/views/projects/_form.rhtml @@ -2,14 +2,14 @@
    -

    <%= f.text_field :name, :required => true %>
    <%= l(:text_caracters_maximum, 30) %>

    +

    <%= f.text_field :name, :required => true, :maxlength => 30 %>
    <%= l(:text_caracters_maximum, 30) %>

    <% unless @project.allowed_parents.compact.empty? %>

    <%= label(:project, :parent_id, l(:field_parent)) %><%= parent_project_select_tag(@project) %>

    <% end %>

    <%= f.text_area :description, :rows => 5, :class => 'wiki-edit' %>

    -

    <%= f.text_field :identifier, :required => true, :disabled => @project.identifier_frozen? %> +

    <%= f.text_field :identifier, :required => true, :disabled => @project.identifier_frozen?, :maxlength => 20 %> <% unless @project.identifier_frozen? %>
    <%= l(:text_length_between, :min => 1, :max => 20) %> <%= l(:text_project_identifier_info) %> <% end %>

    From b02463184a1fca124fc2aab42e1704939d5c21b2 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:30:48 +0000 Subject: [PATCH 067/777] Merged r3911 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3961 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/application_helper.rb | 13 +++++++++++++ app/views/layouts/base.rhtml | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index e4075896..d6fd16a6 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -393,6 +393,19 @@ module ApplicationHelper end end + # Returns the theme, controller name, and action as css classes for the + # HTML body. + def body_css_classes + css = [] + if theme = Redmine::Themes.theme(Setting.ui_theme) + css << 'theme-' + theme.name + end + + css << 'controller-' + params[:controller] + css << 'action-' + params[:action] + css.join(' ') + end + def accesskey(s) Redmine::AccessKeys.key_for s end diff --git a/app/views/layouts/base.rhtml b/app/views/layouts/base.rhtml index 9521457d..2daae7cb 100644 --- a/app/views/layouts/base.rhtml +++ b/app/views/layouts/base.rhtml @@ -19,7 +19,7 @@ <%= yield :header_tags -%> - +
    From 19bbb6e2cb2367f0f5182d0ea8b7e01f87f76d83 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:30:53 +0000 Subject: [PATCH 068/777] Merged r3912 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3962 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/application_controller.rb | 4 ++++ app/controllers/issues_controller.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 6e5634db..c00b6ba4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -218,6 +218,10 @@ class ApplicationController < ActionController::Base end end + def back_url + params[:back_url] || request.env['HTTP_REFERER'] + end + def redirect_back_or_default(default) back_url = CGI.unescape(params[:back_url].to_s) if !back_url.blank? diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 8b5d73fa..d73dfebf 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -349,7 +349,7 @@ class IssuesController < ApplicationController @priorities = IssuePriority.all.reverse @statuses = IssueStatus.find(:all, :order => 'position') - @back = params[:back_url] || request.env['HTTP_REFERER'] + @back = back_url render :layout => false end From 3f1c3fa020bc02f18d81345bbe591eb1c83011a3 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:30:59 +0000 Subject: [PATCH 069/777] Merged r3913 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3963 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/functional/auth_sources_controller_test.rb | 2 +- test/functional/calendars_controller_test.rb | 2 +- test/functional/gantts_controller_test.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/functional/auth_sources_controller_test.rb b/test/functional/auth_sources_controller_test.rb index bd97844e..348e0e09 100644 --- a/test/functional/auth_sources_controller_test.rb +++ b/test/functional/auth_sources_controller_test.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require File.dirname(__FILE__) + '/../test_helper' class AuthSourcesControllerTest < ActionController::TestCase fixtures :all diff --git a/test/functional/calendars_controller_test.rb b/test/functional/calendars_controller_test.rb index 79cfe28a..ad047c66 100644 --- a/test/functional/calendars_controller_test.rb +++ b/test/functional/calendars_controller_test.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require File.dirname(__FILE__) + '/../test_helper' class CalendarsControllerTest < ActionController::TestCase fixtures :all diff --git a/test/functional/gantts_controller_test.rb b/test/functional/gantts_controller_test.rb index 4c27de7c..24c84f2a 100644 --- a/test/functional/gantts_controller_test.rb +++ b/test/functional/gantts_controller_test.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require File.dirname(__FILE__) + '/../test_helper' class GanttsControllerTest < ActionController::TestCase fixtures :all From 4426fd695e9d679f3273097b2644ef494294a392 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:06 +0000 Subject: [PATCH 070/777] Merged r3914 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3964 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/users/_memberships.rhtml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/views/users/_memberships.rhtml b/app/views/users/_memberships.rhtml index 70921f4a..4c71f81b 100644 --- a/app/views/users/_memberships.rhtml +++ b/app/views/users/_memberships.rhtml @@ -14,7 +14,9 @@ <% @user.memberships.each do |membership| %> <% next if membership.new_record? %> - <%=h membership.project %> + + <%= link_to h(membership.project), {:controller => 'projects', :action => 'show', :id => membership.project} %> + <%=h membership.roles.sort.collect(&:to_s).join(', ') %> <% remote_form_for(:membership, :url => { :action => 'edit_membership', :id => @user, :membership_id => membership }, From 7bdf0ab72933fbf92d90796e122e3942dc7ce943 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:12 +0000 Subject: [PATCH 071/777] Merged r3915 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3965 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/issues/_relations.rhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/issues/_relations.rhtml b/app/views/issues/_relations.rhtml index 83a78b1c..71eaaa67 100644 --- a/app/views/issues/_relations.rhtml +++ b/app/views/issues/_relations.rhtml @@ -1,6 +1,6 @@
    <% if authorize_for('issue_relations', 'new') %> - <%= toggle_link l(:button_add), 'new-relation-form'%> + <%= toggle_link l(:button_add), 'new-relation-form', {:focus => 'relation_issue_to_id'} %> <% end %>
    From 102e845391137ce36dd8df8be30b20e3be3d9d23 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:18 +0000 Subject: [PATCH 072/777] Merged r3916 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3966 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/query.rb | 2 +- test/unit/query_test.rb | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/app/models/query.rb b/app/models/query.rb index f697a721..fd7aa347 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -187,7 +187,7 @@ class Query < ActiveRecord::Base if project user_values += project.users.sort.collect{|s| [s.name, s.id.to_s] } else - project_ids = User.current.projects.collect(&:id) + project_ids = Project.all(:conditions => Project.visible_by(User.current)).collect(&:id) if project_ids.any? # members of the user's projects user_values += User.active.find(:all, :conditions => ["#{User.table_name}.id IN (SELECT DISTINCT user_id FROM members WHERE project_id IN (?))", project_ids]).sort.collect{|s| [s.name, s.id.to_s] } diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index 26cba2a5..4b11830e 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -351,4 +351,13 @@ class QueryTest < ActiveSupport::TestCase assert !q.editable_by?(manager) assert !q.editable_by?(developer) end + + context "#available_filters" do + should "include users of visible projects in cross-project view" do + query = Query.new(:name => "_") + users = query.available_filters["assigned_to_id"] + assert_not_nil users + assert users[:values].map{|u|u[1]}.include?("3") + end + end end From 9892ede7b70f39264ba44ae67742ecd06be92258 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:24 +0000 Subject: [PATCH 073/777] Merged r3917 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3967 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/issues_controller.rb | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index d73dfebf..4f6f975c 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -264,15 +264,9 @@ class IssuesController < ApplicationController moved_issues = [] @issues.each do |issue| issue.reload - changed_attributes = {} - [:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute| - unless params[valid_attribute].blank? - changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) - end - end issue.init_journal(User.current) call_hook(:controller_issues_move_before_save, { :params => params, :issue => issue, :target_project => @target_project, :copy => !!@copy }) - if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => changed_attributes}) + if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => extract_changed_attributes_for_move(params)}) moved_issues << r else unsaved_issue_ids << issue.id @@ -485,4 +479,14 @@ private return false end end + + def extract_changed_attributes_for_move(params) + changed_attributes = {} + [:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute| + unless params[valid_attribute].blank? + changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) + end + end + changed_attributes + end end From 2f529fd834029b5e98222ae40da5317cc4aea457 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:30 +0000 Subject: [PATCH 074/777] Merged r3918 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3968 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/issues_controller.rb | 7 +++++- app/views/issues/move.rhtml | 2 +- config/routes.rb | 2 +- lib/redmine.rb | 2 +- test/functional/issues_controller_test.rb | 26 +++++++++++------------ test/integration/routing_test.rb | 2 +- 6 files changed, 23 insertions(+), 18 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 4f6f975c..7fb4148e 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -20,7 +20,7 @@ class IssuesController < ApplicationController default_search_scope :issues before_filter :find_issue, :only => [:show, :edit, :update, :reply] - before_filter :find_issues, :only => [:bulk_edit, :move, :destroy] + before_filter :find_issues, :only => [:bulk_edit, :move, :perform_move, :destroy] before_filter :find_project, :only => [:new, :create, :update_form, :preview, :auto_complete] before_filter :authorize, :except => [:index, :changes, :preview, :context_menu] before_filter :find_optional_project, :only => [:index, :changes] @@ -287,6 +287,11 @@ class IssuesController < ApplicationController end render :layout => false if request.xhr? end + + # TODO: more descriptive name? move to separate controller like IssueMovesController? + def perform_move + move + end def destroy @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f diff --git a/app/views/issues/move.rhtml b/app/views/issues/move.rhtml index 47388c36..c216cba7 100644 --- a/app/views/issues/move.rhtml +++ b/app/views/issues/move.rhtml @@ -6,7 +6,7 @@ <% end -%> -<% form_tag({}, :id => 'move_form') do %> +<% form_tag({:action => 'perform_move'}, :id => 'move_form') do %> <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>
    diff --git a/config/routes.rb b/config/routes.rb index 58e620ea..2e8a145c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -124,7 +124,7 @@ ActionController::Routing::Routes.draw do |map| issues_actions.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show' issues_actions.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show' issues_actions.connect 'issues/:id/quoted', :action => 'reply', :id => /\d+/ - issues_actions.connect 'issues/:id/:action', :action => /edit|move|destroy/, :id => /\d+/ + issues_actions.connect 'issues/:id/:action', :action => /edit|perform_move|destroy/, :id => /\d+/ issues_actions.connect 'issues.:format', :action => 'create', :format => /xml/ end issues_routes.with_options :conditions => {:method => :put} do |issues_actions| diff --git a/lib/redmine.rb b/lib/redmine.rb index b95166e7..4196a5d7 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -69,7 +69,7 @@ Redmine::AccessControl.map do |map| map.permission :add_issue_notes, {:issues => [:edit, :update, :reply]} map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin - map.permission :move_issues, {:issues => :move}, :require => :loggedin + map.permission :move_issues, {:issues => [:move, :perform_move]}, :require => :loggedin map.permission :delete_issues, {:issues => :destroy}, :require => :member # Queries map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 670fb2d7..92e6fd30 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -1038,22 +1038,22 @@ class IssuesControllerTest < ActionController::TestCase assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier end - def test_move_one_issue_to_another_project + def test_perform_move_one_issue_to_another_project @request.session[:user_id] = 2 - post :move, :id => 1, :new_project_id => 2, :tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' + post :perform_move, :id => 1, :new_project_id => 2, :tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_equal 2, Issue.find(1).project_id end - def test_move_one_issue_to_another_project_should_follow_when_needed + def test_perform_move_one_issue_to_another_project_should_follow_when_needed @request.session[:user_id] = 2 - post :move, :id => 1, :new_project_id => 2, :follow => '1' + post :perform_move, :id => 1, :new_project_id => 2, :follow => '1' assert_redirected_to '/issues/1' end - def test_bulk_move_to_another_project + def test_bulk_perform_move_to_another_project @request.session[:user_id] = 2 - post :move, :ids => [1, 2], :new_project_id => 2 + post :perform_move, :ids => [1, 2], :new_project_id => 2 assert_redirected_to :action => 'index', :project_id => 'ecookbook' # Issues moved to project 2 assert_equal 2, Issue.find(1).project_id @@ -1063,9 +1063,9 @@ class IssuesControllerTest < ActionController::TestCase assert_equal 2, Issue.find(2).tracker_id end - def test_bulk_move_to_another_tracker + def test_bulk_perform_move_to_another_tracker @request.session[:user_id] = 2 - post :move, :ids => [1, 2], :new_tracker_id => 2 + post :perform_move, :ids => [1, 2], :new_tracker_id => 2 assert_redirected_to :action => 'index', :project_id => 'ecookbook' assert_equal 2, Issue.find(1).tracker_id assert_equal 2, Issue.find(2).tracker_id @@ -1075,19 +1075,19 @@ class IssuesControllerTest < ActionController::TestCase @request.session[:user_id] = 2 assert_difference 'Issue.count', 2 do assert_no_difference 'Project.find(1).issues.count' do - post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'} + post :perform_move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'} end end assert_redirected_to 'projects/ecookbook/issues' end - context "#move via bulk copy" do + context "#perform_move via bulk copy" do should "allow not changing the issue's attributes" do @request.session[:user_id] = 2 issue_before_move = Issue.find(1) assert_difference 'Issue.count', 1 do assert_no_difference 'Project.find(1).issues.count' do - post :move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' + post :perform_move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' end end issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2}) @@ -1104,7 +1104,7 @@ class IssuesControllerTest < ActionController::TestCase @request.session[:user_id] = 2 assert_difference 'Issue.count', 2 do assert_no_difference 'Project.find(1).issues.count' do - post :move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => 4, :status_id => 3, :start_date => '2009-12-01', :due_date => '2009-12-31' + post :perform_move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => 4, :status_id => 3, :start_date => '2009-12-01', :due_date => '2009-12-31' end end @@ -1122,7 +1122,7 @@ class IssuesControllerTest < ActionController::TestCase def test_copy_to_another_project_should_follow_when_needed @request.session[:user_id] = 2 - post :move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1' + post :perform_move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1' issue = Issue.first(:order => 'id DESC') assert_redirected_to :controller => 'issues', :action => 'show', :id => issue end diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb index f8476df5..51f8e71f 100644 --- a/test/integration/routing_test.rb +++ b/test/integration/routing_test.rb @@ -86,7 +86,7 @@ class RoutingTest < ActionController::IntegrationTest should_route :get, "/projects/23/issues/64/copy", :controller => 'issues', :action => 'new', :project_id => '23', :copy_from => '64' should_route :get, "/issues/1/move", :controller => 'issues', :action => 'move', :id => '1' - should_route :post, "/issues/1/move", :controller => 'issues', :action => 'move', :id => '1' + should_route :post, "/issues/1/perform_move", :controller => 'issues', :action => 'perform_move', :id => '1' should_route :post, "/issues/1/quoted", :controller => 'issues', :action => 'reply', :id => '1' From 7cae43314ae28d28955c782da444427a34f7df08 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:36 +0000 Subject: [PATCH 075/777] Merged r3919 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3969 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/tasks/ci.rake | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 lib/tasks/ci.rake diff --git a/lib/tasks/ci.rake b/lib/tasks/ci.rake new file mode 100644 index 00000000..09257531 --- /dev/null +++ b/lib/tasks/ci.rake @@ -0,0 +1,41 @@ +desc "Run the Continous Integration tests for Redmine" +task :ci do + # RAILS_ENV and ENV[] can diverge so force them both to test + ENV['RAILS_ENV'] = 'test' + RAILS_ENV = 'test' + Rake::Task["ci:setup"].invoke + Rake::Task["ci:build"].invoke + Rake::Task["ci:teardown"].invoke +end + +# Tasks can be hooked into by redefining them in a plugin +namespace :ci do + desc "Setup Redmine for a new build." + task :setup do + Rake::Task["ci:dump_environment"].invoke + Rake::Task["db:create"].invoke + Rake::Task["db:migrate"].invoke + Rake::Task["db:schema:dump"].invoke + end + + desc "Build Redmine" + task :build do + Rake::Task["test"].invoke + end + + # Use this to cleanup after building or run post-build analysis. + desc "Finish the build" + task :teardown do + end + + desc "Dump the environment information to a BUILD_ENVIRONMENT ENV variable for debugging" + task :dump_environment do + + ENV['BUILD_ENVIRONMENT'] = ['ruby -v', 'gem -v', 'gem list'].collect do |command| + result = `#{command}` + "$ #{command}\n#{result}" + end.join("\n") + + end +end + From dfe44017b609ca32fe9b8de16558ebeabedd0aff Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:42 +0000 Subject: [PATCH 076/777] Merged r3920 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3970 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/tasks/yardoc.rake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/tasks/yardoc.rake b/lib/tasks/yardoc.rake index c98f3bd4..761065df 100644 --- a/lib/tasks/yardoc.rake +++ b/lib/tasks/yardoc.rake @@ -2,7 +2,9 @@ begin require 'yard' YARD::Rake::YardocTask.new do |t| - t.files = ['lib/**/*.rb', 'app/**/*.rb', 'vendor/plugins/**/*.rb'] + files = ['lib/**/*.rb', 'app/**/*.rb'] + files << Dir['vendor/plugins/**/*.rb'].reject {|f| f.match(/test/) } # Exclude test files + t.files = files end rescue LoadError From 4ff607012623e9a8dbe4f9d586bd0d1b511468fd Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:48 +0000 Subject: [PATCH 077/777] Merged r3921 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3971 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/tasks/yardoc.rake | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/tasks/yardoc.rake b/lib/tasks/yardoc.rake index 761065df..88cf9b85 100644 --- a/lib/tasks/yardoc.rake +++ b/lib/tasks/yardoc.rake @@ -5,6 +5,7 @@ begin files = ['lib/**/*.rb', 'app/**/*.rb'] files << Dir['vendor/plugins/**/*.rb'].reject {|f| f.match(/test/) } # Exclude test files t.files = files + t.options += ['--output-dir', './doc/app'] end rescue LoadError From 31d233e56716acefee6f0499688499cb262f1754 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:53 +0000 Subject: [PATCH 078/777] Merged r3922 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3972 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/tasks/yardoc.rake | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/tasks/yardoc.rake b/lib/tasks/yardoc.rake index 88cf9b85..aa6c5eeb 100644 --- a/lib/tasks/yardoc.rake +++ b/lib/tasks/yardoc.rake @@ -5,7 +5,14 @@ begin files = ['lib/**/*.rb', 'app/**/*.rb'] files << Dir['vendor/plugins/**/*.rb'].reject {|f| f.match(/test/) } # Exclude test files t.files = files - t.options += ['--output-dir', './doc/app'] + + static_files = ['doc/CHANGELOG', + 'doc/COPYING', + 'doc/INSTALL', + 'doc/RUNNING_TESTS', + 'doc/UPGRADING'].join(',') + + t.options += ['--output-dir', './doc/app', '--files', static_files] end rescue LoadError From 18d841553e1f5cca0bfe9c57f757ff5824b0a940 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:31:59 +0000 Subject: [PATCH 079/777] Merged r3923 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3973 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- doc/CHANGELOG | 260 +++++++++++++++++++++++++------------------------- 1 file changed, 130 insertions(+), 130 deletions(-) diff --git a/doc/CHANGELOG b/doc/CHANGELOG index 4a100bfc..4e6be6a2 100644 --- a/doc/CHANGELOG +++ b/doc/CHANGELOG @@ -6,151 +6,151 @@ http://www.redmine.org/ == 2010-07-18 v1.0.0 (Release candidate) -#443: Adds context menu to the roadmap issue lists -#443: Subtasking -#741: Description preview while editing an issue -#1131: Add support for alternate (non-LDAP) authentication -#1214: REST API for Issues -#1223: File upload on wiki edit form -#1755: add "blocked by" as a related issues option -#2420: Fetching emails from an POP server -#2482: Named scopes in Issue and ActsAsWatchable plus some view refactoring (logic extraction). -#2924: Make the right click menu more discoverable using a cursor property -#2985: Make syntax highlighting pluggable -#3201: Workflow Check/Uncheck All Rows/Columns -#3359: Update CodeRay 0.9 -#3706: Allow assigned_to field configuration on Issue creation by email -#3936: configurable list of models to include in search -#4480: Create a link to the user profile from the administration interface -#4482: Cache textile rendering -#4572: Make it harder to ruin your database -#4573: Move github gems to Gemcutter -#4664: Add pagination to forum threads -#4732: Make login case-insensitive also for PostgreSQL -#4812: Create links to other projects -#4819: Replace images with smushed ones for speed -#4945: Allow custom fields attached to project to be searchable -#5121: Fix issues list layout overflow -#5169: Issue list view hook request -#5208: Aibility to edit wiki sidebar -#5281: Remove empty ul tags in the issue history -#5291: Updated basque translations -#5328: Automatically add "Repository" menu_item after repository creation -#5415: Fewer SQL statements generated for watcher_recipients -#5416: Exclude "fields_for" from overridden methods in TabularFormBuilder -#5573: Allow issue assignment in email -#5595: Allow start date and due dates to be set via incoming email -#5752: The projects view (/projects) renders ul's wrong -#5781: Allow to use more macros on the welcome page and project list -Fixed #1288: Unable to past escaped wiki syntax in an issue description -Fixed #1334: Wiki formatting character *_ and _* -Fixed #1416: Inline code with less-then/greater-than produces @lt; and @gt; respectively -Fixed #2473: Login and mail should not be case sensitive -Fixed #2990: Ruby 1.9 - wrong number of arguments (1 for 0) on rake db:migrate -Fixed #3089: Text formatting sometimes breaks when combined -Fixed #3690: Status change info duplicates on the issue screen -Fixed #3691: Redmine allows two files with the same file name to be uploaded to the same issue -Fixed #3764: ApplicationHelperTest fails with JRuby -Fixed #4265: Unclosed code tags in issue descriptions affects main UI -Fixed #4745: Bug in index.xml.builder (issues) -Fixed #4852: changing user/roles of project member not possible without javascript -Fixed #4857: Week number calculation in date picker is wrong if a week starts with Sunday -Fixed #4883: Bottom "contextual" placement in issue with associated changeset -Fixed #4918: Revisions r3453 and r3454 broke On-the-fly user creation with LDAP -Fixed #4935: Navigation to the Master Timesheet page (time_entries) -Fixed #5043: Flash messages are not displayed after the project settings[module/activity] saved -Fixed #5081: Broken links on public/help/wiki_syntax_detailed.html -Fixed #5104: Description of document not wikified on documents index -Fixed #5108: Issue linking fails inside of []s -Fixed #5199: diff code coloring using coderay -Fixed #5233: Add a hook to the issue report (Summary) view -Fixed #5265: timetracking: subtasks time is added to the main task -Fixed #5343: acts_as_event Doesn't Accept Outside URLs -Fixed #5440: UI Inconsistency : Administration > Enumerations table row headers should be enclosed in -Fixed #5463: 0.9.4 INSTALL and/or UPGRADE, missing session_store.rb -Fixed #5524: Update_parent_attributes doesn't work for the old parent issue when reparenting -Fixed #5548: SVN Repository: Can not list content of a folder which includes square brackets. -Fixed #5589: "with subproject" malfunction -Fixed #5676: Search for Numeric Value -Fixed #5696: Redmine + PostgreSQL 8.4.4 fails on _dir_list_content.rhtml -Fixed #5698: redmine:email:receive_imap fails silently for mails with subject longer than 255 characters -Fixed #5700: TimelogController#destroy assumes success -Fixed #5751: developer role is mispelled -Fixed #5769: Popup Calendar doesn't Advance in Chrome -Fixed #5771: Problem when importing git repository -Fixed #5823: Error in comments in plugin.rb +* #443: Adds context menu to the roadmap issue lists +* #443: Subtasking +* #741: Description preview while editing an issue +* #1131: Add support for alternate (non-LDAP) authentication +* #1214: REST API for Issues +* #1223: File upload on wiki edit form +* #1755: add "blocked by" as a related issues option +* #2420: Fetching emails from an POP server +* #2482: Named scopes in Issue and ActsAsWatchable plus some view refactoring (logic extraction). +* #2924: Make the right click menu more discoverable using a cursor property +* #2985: Make syntax highlighting pluggable +* #3201: Workflow Check/Uncheck All Rows/Columns +* #3359: Update CodeRay 0.9 +* #3706: Allow assigned_to field configuration on Issue creation by email +* #3936: configurable list of models to include in search +* #4480: Create a link to the user profile from the administration interface +* #4482: Cache textile rendering +* #4572: Make it harder to ruin your database +* #4573: Move github gems to Gemcutter +* #4664: Add pagination to forum threads +* #4732: Make login case-insensitive also for PostgreSQL +* #4812: Create links to other projects +* #4819: Replace images with smushed ones for speed +* #4945: Allow custom fields attached to project to be searchable +* #5121: Fix issues list layout overflow +* #5169: Issue list view hook request +* #5208: Aibility to edit wiki sidebar +* #5281: Remove empty ul tags in the issue history +* #5291: Updated basque translations +* #5328: Automatically add "Repository" menu_item after repository creation +* #5415: Fewer SQL statements generated for watcher_recipients +* #5416: Exclude "fields_for" from overridden methods in TabularFormBuilder +* #5573: Allow issue assignment in email +* #5595: Allow start date and due dates to be set via incoming email +* #5752: The projects view (/projects) renders ul's wrong +* #5781: Allow to use more macros on the welcome page and project list +* Fixed #1288: Unable to past escaped wiki syntax in an issue description +* Fixed #1334: Wiki formatting character *_ and _* +* Fixed #1416: Inline code with less-then/greater-than produces @lt; and @gt; respectively +* Fixed #2473: Login and mail should not be case sensitive +* Fixed #2990: Ruby 1.9 - wrong number of arguments (1 for 0) on rake db:migrate +* Fixed #3089: Text formatting sometimes breaks when combined +* Fixed #3690: Status change info duplicates on the issue screen +* Fixed #3691: Redmine allows two files with the same file name to be uploaded to the same issue +* Fixed #3764: ApplicationHelperTest fails with JRuby +* Fixed #4265: Unclosed code tags in issue descriptions affects main UI +* Fixed #4745: Bug in index.xml.builder (issues) +* Fixed #4852: changing user/roles of project member not possible without javascript +* Fixed #4857: Week number calculation in date picker is wrong if a week starts with Sunday +* Fixed #4883: Bottom "contextual" placement in issue with associated changeset +* Fixed #4918: Revisions r3453 and r3454 broke On-the-fly user creation with LDAP +* Fixed #4935: Navigation to the Master Timesheet page (time_entries) +* Fixed #5043: Flash messages are not displayed after the project settings[module/activity] saved +* Fixed #5081: Broken links on public/help/wiki_syntax_detailed.html +* Fixed #5104: Description of document not wikified on documents index +* Fixed #5108: Issue linking fails inside of []s +* Fixed #5199: diff code coloring using coderay +* Fixed #5233: Add a hook to the issue report (Summary) view +* Fixed #5265: timetracking: subtasks time is added to the main task +* Fixed #5343: acts_as_event Doesn't Accept Outside URLs +* Fixed #5440: UI Inconsistency : Administration > Enumerations table row headers should be enclosed in +* Fixed #5463: 0.9.4 INSTALL and/or UPGRADE, missing session_store.rb +* Fixed #5524: Update_parent_attributes doesn't work for the old parent issue when reparenting +* Fixed #5548: SVN Repository: Can not list content of a folder which includes square brackets. +* Fixed #5589: "with subproject" malfunction +* Fixed #5676: Search for Numeric Value +* Fixed #5696: Redmine + PostgreSQL 8.4.4 fails on _dir_list_content.rhtml +* Fixed #5698: redmine:email:receive_imap fails silently for mails with subject longer than 255 characters +* Fixed #5700: TimelogController#destroy assumes success +* Fixed #5751: developer role is mispelled +* Fixed #5769: Popup Calendar doesn't Advance in Chrome +* Fixed #5771: Problem when importing git repository +* Fixed #5823: Error in comments in plugin.rb == 2010-07-07 v0.9.6 -Fixed: Redmine.pm access by unauthorized users +* Fixed: Redmine.pm access by unauthorized users == 2010-06-24 v0.9.5 -Linkify folder names on revision view -"fiters" and "options" should be hidden in print view via css -Fixed: NoMethodError when no issue params are submitted -Fixed: projects.atom with required authentication -Fixed: External links not correctly displayed in Wiki TOC -Fixed: Member role forms in project settings are not hidden after member added -Fixed: pre can't be inside p -Fixed: session cookie path does not respect RAILS_RELATIVE_URL_ROOT -Fixed: mail handler fails when the from address is empty +* Linkify folder names on revision view +* "fiters" and "options" should be hidden in print view via css +* Fixed: NoMethodError when no issue params are submitted +* Fixed: projects.atom with required authentication +* Fixed: External links not correctly displayed in Wiki TOC +* Fixed: Member role forms in project settings are not hidden after member added +* Fixed: pre can't be inside p +* Fixed: session cookie path does not respect RAILS_RELATIVE_URL_ROOT +* Fixed: mail handler fails when the from address is empty == 2010-05-01 v0.9.4 -Filters collapsed by default on issues index page for a saved query -Fixed: When categories list is too big the popup menu doesn't adjust (ex. in the issue list) -Fixed: remove "main-menu" div when the menu is empty -Fixed: Code syntax highlighting not working in Document page -Fixed: Git blame/annotate fails on moved files -Fixed: Failing test in test_show_atom -Fixed: Migrate from trac - not displayed Wikis -Fixed: Email notifications on file upload sent to empty recipient list -Fixed: Migrating from trac is not possible, fails to allocate memory -Fixed: Lost password no longer flashes a confirmation message -Fixed: Crash while deleting in-use enumeration -Fixed: Hard coded English string at the selection of issue watchers -Fixed: Bazaar v2.1.0 changed behaviour -Fixed: Roadmap display can raise an exception if no trackers are selected -Fixed: Gravatar breaks layout of "logged in" page -Fixed: Reposman.rb on Windows -Fixed: Possible error 500 while moving an issue to another project with SQLite -Fixed: backslashes in issue description/note should be escaped when quoted -Fixed: Long text in
     disrupts Associated revisions
    -Fixed: Links to missing wiki pages not red on project overview page
    -Fixed: Cannot delete a project with subprojects that shares versions
    -Fixed: Update of Subversion changesets broken under Solaris
    -Fixed: "Move issues" permission not working for Non member
    -Fixed: Sidebar overlap on Users tab of Group editor
    -Fixed: Error on db:migrate with table prefix set (hardcoded name in principal.rb)
    -Fixed: Report shows sub-projects for non-members
    -Fixed: 500 internal error when browsing any Redmine page in epiphany
    -Fixed: Watchers selection lost when issue creation fails
    -Fixed: When copying projects, redmine should not generate an email to people who created issues
    -Fixed: Issue "#" table cells should have a class attribute to enable fine-grained CSS theme
    -Fixed: Plugin generators should display help if no parameter is given
    +* Filters collapsed by default on issues index page for a saved query
    +* Fixed: When categories list is too big the popup menu doesn't adjust (ex. in the issue list)
    +* Fixed: remove "main-menu" div when the menu is empty
    +* Fixed: Code syntax highlighting not working in Document page
    +* Fixed: Git blame/annotate fails on moved files
    +* Fixed: Failing test in test_show_atom
    +* Fixed: Migrate from trac - not displayed Wikis
    +* Fixed: Email notifications on file upload sent to empty recipient list
    +* Fixed: Migrating from trac is not possible, fails to allocate memory
    +* Fixed: Lost password no longer flashes a confirmation message
    +* Fixed: Crash while deleting in-use enumeration
    +* Fixed: Hard coded English string at the selection of issue watchers
    +* Fixed: Bazaar v2.1.0 changed behaviour
    +* Fixed: Roadmap display can raise an exception if no trackers are selected
    +* Fixed: Gravatar breaks layout of "logged in" page
    +* Fixed: Reposman.rb on Windows
    +* Fixed: Possible error 500 while moving an issue to another project with SQLite
    +* Fixed: backslashes in issue description/note should be escaped when quoted
    +* Fixed: Long text in 
     disrupts Associated revisions
    +* Fixed: Links to missing wiki pages not red on project overview page
    +* Fixed: Cannot delete a project with subprojects that shares versions
    +* Fixed: Update of Subversion changesets broken under Solaris
    +* Fixed: "Move issues" permission not working for Non member
    +* Fixed: Sidebar overlap on Users tab of Group editor
    +* Fixed: Error on db:migrate with table prefix set (hardcoded name in principal.rb)
    +* Fixed: Report shows sub-projects for non-members
    +* Fixed: 500 internal error when browsing any Redmine page in epiphany
    +* Fixed: Watchers selection lost when issue creation fails
    +* Fixed: When copying projects, redmine should not generate an email to people who created issues
    +* Fixed: Issue "#" table cells should have a class attribute to enable fine-grained CSS theme
    +* Fixed: Plugin generators should display help if no parameter is given
     
     
     == 2010-02-28 v0.9.3
     
    -Adds filter for system shared versions on the cross project issue list
    -Makes project identifiers searchable
    -Remove invalid utf8 sequences from commit comments and author name
    -Fixed: Wrong link when "http" not included in project "Homepage" link
    -Fixed: Escaping in html email templates
    -Fixed: Pound (#) followed by number with leading zero (0) removes leading zero when rendered in wiki
    -Fixed: Deselecting textile text formatting causes interning empty string errors
    -Fixed: error with postgres when entering a non-numeric id for an issue relation
    -Fixed: div.task incorrectly wrapping on Gantt Chart
    -Fixed: Project copy loses wiki pages hierarchy
    -Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project
    -Fixed: Repository.fetch_changesets tries to fetch changesets for archived projects
    -Fixed: Duplicated project name for subproject version on gantt chart
    -Fixed: roadmap shows subprojects issues even if subprojects is unchecked
    -Fixed: IndexError if all the :last menu items are deleted from a menu
    -Fixed: Very high CPU usage for a long time when fetching commits from a large Git repository
    +* Adds filter for system shared versions on the cross project issue list
    +* Makes project identifiers searchable
    +* Remove invalid utf8 sequences from commit comments and author name
    +* Fixed: Wrong link when "http" not included in project "Homepage" link
    +* Fixed: Escaping in html email templates
    +* Fixed: Pound (#) followed by number with leading zero (0) removes leading zero when rendered in wiki
    +* Fixed: Deselecting textile text formatting causes interning empty string errors
    +* Fixed: error with postgres when entering a non-numeric id for an issue relation
    +* Fixed: div.task incorrectly wrapping on Gantt Chart
    +* Fixed: Project copy loses wiki pages hierarchy
    +* Fixed: parent project field doesn't include blank value when a member with 'add subproject' permission edits a child project
    +* Fixed: Repository.fetch_changesets tries to fetch changesets for archived projects
    +* Fixed: Duplicated project name for subproject version on gantt chart
    +* Fixed: roadmap shows subprojects issues even if subprojects is unchecked
    +* Fixed: IndexError if all the :last menu items are deleted from a menu
    +* Fixed: Very high CPU usage for a long time when fetching commits from a large Git repository
     
     
     == 2010-02-07 v0.9.2
    
    From c7e719fc4b44e7b92442392a457b06ec3e467643 Mon Sep 17 00:00:00 2001
    From: Eric Davis 
    Date: Thu, 19 Aug 2010 04:32:06 +0000
    Subject: [PATCH 080/777] Merged r3924 from trunk.
    
    git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3974 e93f8b46-1217-0410-a6f0-8f06a7374b81
    ---
     app/helpers/application_helper.rb            | 27 +++++++++++++++-----
     app/helpers/projects_helper.rb               |  2 +-
     app/helpers/queries_helper.rb                |  2 +-
     app/views/admin/projects.rhtml               |  2 +-
     app/views/issues/_list_simple.rhtml          |  2 +-
     app/views/news/_news.rhtml                   |  2 +-
     app/views/news/index.rhtml                   |  2 +-
     app/views/users/_memberships.rhtml           |  2 +-
     app/views/users/show.rhtml                   |  2 +-
     app/views/welcome/index.rhtml                |  2 +-
     test/unit/helpers/application_helper_test.rb | 12 +++++++++
     11 files changed, 42 insertions(+), 15 deletions(-)
    
    diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
    index d6fd16a6..2c334b7f 100644
    --- a/app/helpers/application_helper.rb
    +++ b/app/helpers/application_helper.rb
    @@ -103,6 +103,23 @@ module ApplicationHelper
         link_to(text, {:controller => 'repositories', :action => 'revision', :id => project, :rev => revision}, :title => l(:label_revision_id, revision))
       end
     
    +  # Generates a link to a project if active
    +  # Examples:
    +  # 
    +  #   link_to_project(project)                          # => link to the specified project overview
    +  #   link_to_project(project, :action=>'settings')     # => link to project settings
    +  #   link_to_project(project, {:only_path => false}, :class => "project") # => 3rd arg adds html options
    +  #   link_to_project(project, {}, :class => "project") # => html options with default url (project overview)
    +  #
    +  def link_to_project(project, options={}, html_options = nil)
    +    if project.active?
    +      url = {:controller => 'projects', :action => 'show', :id => project}.merge(options)
    +      link_to(h(project), url, html_options)
    +    else
    +      h(project)
    +    end
    +  end
    +
       def toggle_link(name, id, options={})
         onclick = "Element.toggle('#{id}'); "
         onclick << (options[:focus] ? "Form.Element.focus('#{options[:focus]}'); " : "this.blur(); ")
    @@ -368,12 +385,12 @@ module ApplicationHelper
           ancestors = (@project.root? ? [] : @project.ancestors.visible)
           if ancestors.any?
             root = ancestors.shift
    -        b << link_to(h(root), {:controller => 'projects', :action => 'show', :id => root, :jump => current_menu_item}, :class => 'root')
    +        b << link_to_project(root, {:jump => current_menu_item}, :class => 'root')
             if ancestors.size > 2
               b << '…'
               ancestors = ancestors[-2, 2]
             end
    -        b += ancestors.collect {|p| link_to(h(p), {:controller => 'projects', :action => 'show', :id => p, :jump => current_menu_item}, :class => 'ancestor') }
    +        b += ancestors.collect {|p| link_to_project(p, {:jump => current_menu_item}, :class => 'ancestor') }
           end
           b << h(@project)
           b.join(' » ')
    @@ -605,8 +622,7 @@ module ApplicationHelper
                 end
               when 'project'
                 if p = Project.visible.find_by_id(oid)
    -              link = link_to h(p.name), {:only_path => only_path, :controller => 'projects', :action => 'show', :id => p},
    -                                              :class => 'project'
    +              link = link_to_project(p, {:only_path => only_path}, :class => 'project')
                 end
               end
             elsif sep == ':'
    @@ -648,8 +664,7 @@ module ApplicationHelper
                 end
               when 'project'
                 if p = Project.visible.find(:first, :conditions => ["identifier = :s OR LOWER(name) = :s", {:s => name.downcase}])
    -              link = link_to h(p.name), {:only_path => only_path, :controller => 'projects', :action => 'show', :id => p},
    -                                              :class => 'project'
    +              link = link_to_project(p, {:only_path => only_path}, :class => 'project')
                 end
               end
             end
    diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
    index 044ccfb7..3b089c11 100644
    --- a/app/helpers/projects_helper.rb
    +++ b/app/helpers/projects_helper.rb
    @@ -72,7 +72,7 @@ module ProjectsHelper
             end
             classes = (ancestors.empty? ? 'root' : 'child')
             s << "
  • " + - link_to(h(project), {:controller => 'projects', :action => 'show', :id => project}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") + link_to_project(project, {}, :class => "project #{User.current.member_of?(project) ? 'my-project' : nil}") s << "
    #{textilizable(project.short_description, :project => project)}
    " unless project.description.blank? s << "
    \n" ancestors << project diff --git a/app/helpers/queries_helper.rb b/app/helpers/queries_helper.rb index 594c8a79..26be6369 100644 --- a/app/helpers/queries_helper.rb +++ b/app/helpers/queries_helper.rb @@ -50,7 +50,7 @@ module QueriesHelper when 'User' link_to_user value when 'Project' - link_to(h(value), :controller => 'projects', :action => 'show', :id => value) + link_to_project value when 'Version' link_to(h(value), :controller => 'versions', :action => 'show', :id => value) when 'TrueClass' diff --git a/app/views/admin/projects.rhtml b/app/views/admin/projects.rhtml index dc7bb97e..46b68e4c 100644 --- a/app/views/admin/projects.rhtml +++ b/app/views/admin/projects.rhtml @@ -27,7 +27,7 @@ <% project_tree(@projects) do |project, level| %> <%= css_project_classes(project) %> <%= level > 0 ? "idnt idnt-#{level}" : nil %>"> - <%= project.active? ? link_to(h(project.name), :controller => 'projects', :action => 'settings', :id => project) : h(project.name) %> + <%= link_to_project(project, :action => 'settings') %> <%= textilizable project.short_description, :project => project %> <%= checked_image project.is_public? %> <%= format_date(project.created_on) %> diff --git a/app/views/issues/_list_simple.rhtml b/app/views/issues/_list_simple.rhtml index 38823765..dd7f4894 100644 --- a/app/views/issues/_list_simple.rhtml +++ b/app/views/issues/_list_simple.rhtml @@ -14,7 +14,7 @@ <%= check_box_tag("ids[]", issue.id, false, :style => 'display:none;') %> <%= link_to issue.id, :controller => 'issues', :action => 'show', :id => issue %> - <%= link_to(h(issue.project), :controller => 'projects', :action => 'show', :id => issue.project) %> + <%= link_to_project(issue.project) %> <%=h issue.tracker %> <%= link_to h(truncate(issue.subject, :length => 60)), :controller => 'issues', :action => 'show', :id => issue %> (<%=h issue.status %>) diff --git a/app/views/news/_news.rhtml b/app/views/news/_news.rhtml index e95e8a55..8f481f09 100644 --- a/app/views/news/_news.rhtml +++ b/app/views/news/_news.rhtml @@ -1,4 +1,4 @@ -

    <%= link_to(h(news.project.name), :controller => 'projects', :action => 'show', :id => news.project) + ': ' unless @project %> +

    <%= link_to_project(news.project) + ': ' unless @project %> <%= link_to h(news.title), :controller => 'news', :action => 'show', :id => news %> <%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>
    diff --git a/app/views/news/index.rhtml b/app/views/news/index.rhtml index 11a39232..8b7cc66e 100644 --- a/app/views/news/index.rhtml +++ b/app/views/news/index.rhtml @@ -28,7 +28,7 @@

    <%= l(:label_no_data) %>

    <% else %> <% @newss.each do |news| %> -

    <%= link_to(h(news.project.name), :controller => 'projects', :action => 'show', :id => news.project) + ': ' unless news.project == @project %> +

    <%= link_to_project(news.project) + ': ' unless news.project == @project %> <%= link_to h(news.title), :controller => 'news', :action => 'show', :id => news %> <%= "(#{l(:label_x_comments, :count => news.comments_count)})" if news.comments_count > 0 %>

    <%= authoring news.created_on, news.author %>

    diff --git a/app/views/users/_memberships.rhtml b/app/views/users/_memberships.rhtml index 4c71f81b..44129470 100644 --- a/app/views/users/_memberships.rhtml +++ b/app/views/users/_memberships.rhtml @@ -15,7 +15,7 @@ <% next if membership.new_record? %> - <%= link_to h(membership.project), {:controller => 'projects', :action => 'show', :id => membership.project} %> + <%= link_to_project membership.project %> <%=h membership.roles.sort.collect(&:to_s).join(', ') %> diff --git a/app/views/users/show.rhtml b/app/views/users/show.rhtml index 82634b01..df5aec82 100644 --- a/app/views/users/show.rhtml +++ b/app/views/users/show.rhtml @@ -24,7 +24,7 @@

    <%=l(:label_project_plural)%>

      <% for membership in @memberships %> -
    • <%= link_to(h(membership.project.name), :controller => 'projects', :action => 'show', :id => membership.project) %> +
    • <%= link_to_project(membership.project) %> (<%=h membership.roles.sort.collect(&:to_s).join(', ') %>, <%= format_date(membership.created_on) %>)
    • <% end %>
    diff --git a/app/views/welcome/index.rhtml b/app/views/welcome/index.rhtml index a0ada7cc..6ac09c15 100644 --- a/app/views/welcome/index.rhtml +++ b/app/views/welcome/index.rhtml @@ -20,7 +20,7 @@ <% for project in @projects %> <% @project = project %>
  • - <%= link_to h(project.name), :controller => 'projects', :action => 'show', :id => project %> (<%= format_time(project.created_on) %>) + <%= link_to_project project %> (<%= format_time(project.created_on) %>) <%= textilizable project.short_description, :project => project %>
  • <% end %> diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb index 90d34289..6fd21fe3 100644 --- a/test/unit/helpers/application_helper_test.rb +++ b/test/unit/helpers/application_helper_test.rb @@ -597,4 +597,16 @@ EXPECTED t = link_to_user(user) assert_equal ::I18n.t(:label_user_anonymous), t end + + def test_link_to_project + project = Project.find(1) + assert_equal %(eCookbook), + link_to_project(project) + assert_equal %(eCookbook), + link_to_project(project, :action => 'settings') + assert_equal %(eCookbook), + link_to_project(project, {:only_path => false, :jump => 'blah'}) + assert_equal %(eCookbook), + link_to_project(project, {:action => 'settings'}, :class => "project") + end end From a96eb375ec0ab051c196cbf9a1aaa8cc7e3c5116 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:13 +0000 Subject: [PATCH 081/777] Merged r3925 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3975 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/scm/adapters/git_adapter.rb | 10 +++++----- test/unit/lib/redmine/scm/adapters/git_adapter_test.rb | 4 ++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb index d15bce1a..0857d904 100644 --- a/lib/redmine/scm/adapters/git_adapter.rb +++ b/lib/redmine/scm/adapters/git_adapter.rb @@ -114,12 +114,12 @@ module Redmine def revisions(path, identifier_from, identifier_to, options={}) revisions = Revisions.new - cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller" - cmd << " --reverse" if options[:reverse] - cmd << " --all" if options[:all] + cmd = "#{GIT_BIN} --git-dir #{target('')} log --raw --date=iso --pretty=fuller " + cmd << " --reverse " if options[:reverse] + cmd << " --all " if options[:all] cmd << " -n #{options[:limit]} " if options[:limit] - cmd << " #{shell_quote(identifier_from + '..')} " if identifier_from - cmd << " #{shell_quote identifier_to} " if identifier_to + cmd << "#{shell_quote(identifier_from + '..')}" if identifier_from + cmd << "#{shell_quote identifier_to}" if identifier_to cmd << " --since=#{shell_quote(options[:since].strftime("%Y-%m-%d %H:%M:%S"))}" if options[:since] cmd << " -- #{path}" if path && !path.empty? diff --git a/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb index 2dc5d3e8..6b716b9c 100644 --- a/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb +++ b/test/unit/lib/redmine/scm/adapters/git_adapter_test.rb @@ -16,6 +16,10 @@ class GitAdapterTest < ActiveSupport::TestCase assert_equal 13, @adapter.revisions('',nil,nil,:all => true).length end + def test_getting_certain_revisions + assert_equal 1, @adapter.revisions('','899a15d^','899a15d').length + end + def test_annotate annotate = @adapter.annotate('sources/watchers_controller.rb') assert_kind_of Redmine::Scm::Adapters::Annotate, annotate From b6bc3a3665deded5046b96cb58349aa6d73ce539 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:19 +0000 Subject: [PATCH 082/777] Merged r3926 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3976 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/lib/redmine/menu_manager/menu_item_test.rb | 2 +- test/unit/lib/redmine/menu_manager_test.rb | 6 +----- test/unit/lib/redmine_test.rb | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/test/unit/lib/redmine/menu_manager/menu_item_test.rb b/test/unit/lib/redmine/menu_manager/menu_item_test.rb index 835e154d..ab17d4a4 100644 --- a/test/unit/lib/redmine/menu_manager/menu_item_test.rb +++ b/test/unit/lib/redmine/menu_manager/menu_item_test.rb @@ -24,7 +24,7 @@ module RedmineMenuTestHelper end end -class Redmine::MenuManager::MenuItemTest < Test::Unit::TestCase +class Redmine::MenuManager::MenuItemTest < ActiveSupport::TestCase include RedmineMenuTestHelper Redmine::MenuManager.map :test_menu do |menu| diff --git a/test/unit/lib/redmine/menu_manager_test.rb b/test/unit/lib/redmine/menu_manager_test.rb index 0c01ca32..200ed397 100644 --- a/test/unit/lib/redmine/menu_manager_test.rb +++ b/test/unit/lib/redmine/menu_manager_test.rb @@ -17,7 +17,7 @@ require File.dirname(__FILE__) + '/../../../test_helper' -class Redmine::MenuManagerTest < Test::Unit::TestCase +class Redmine::MenuManagerTest < ActiveSupport::TestCase context "MenuManager#map" do should "be tested" end @@ -25,8 +25,4 @@ class Redmine::MenuManagerTest < Test::Unit::TestCase context "MenuManager#items" do should "be tested" end - - should "be tested" do - assert true - end end diff --git a/test/unit/lib/redmine_test.rb b/test/unit/lib/redmine_test.rb index 5150da1f..2d32abdc 100644 --- a/test/unit/lib/redmine_test.rb +++ b/test/unit/lib/redmine_test.rb @@ -33,7 +33,7 @@ module RedmineMenuTestHelper end end -class RedmineTest < Test::Unit::TestCase +class RedmineTest < ActiveSupport::TestCase include RedmineMenuTestHelper def test_top_menu From c67272599cd1916674c0512b1a17a1f827f9ebce Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:25 +0000 Subject: [PATCH 083/777] Merged r3927 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3977 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/query.rb | 6 ++++++ test/unit/query_test.rb | 9 +++++++++ 2 files changed, 15 insertions(+) diff --git a/app/models/query.rb b/app/models/query.rb index fd7aa347..b1f78452 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -219,6 +219,12 @@ class Query < ActiveRecord::Base @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => system_shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } end add_custom_fields_filters(IssueCustomField.find(:all, :conditions => {:is_filter => true, :is_for_all => true})) + # project filter + project_values = Project.all(:conditions => Project.visible_by(User.current), :order => 'lft').map do |p| + pre = (p.level > 0 ? ('--' * p.level + ' ') : '') + ["#{pre}#{p.name}",p.id.to_s] + end + @available_filters["project_id"] = { :type => :list, :order => 1, :values => project_values} end @available_filters end diff --git a/test/unit/query_test.rb b/test/unit/query_test.rb index 4b11830e..12ab5d93 100644 --- a/test/unit/query_test.rb +++ b/test/unit/query_test.rb @@ -33,6 +33,15 @@ class QueryTest < ActiveSupport::TestCase assert query.available_filters['fixed_version_id'][:values].detect {|v| v.last == '2'} end + def test_project_filter_in_global_queries + query = Query.new(:project => nil, :name => '_') + project_filter = query.available_filters["project_id"] + assert_not_nil project_filter + project_ids = project_filter[:values].map{|p| p[1]} + assert project_ids.include?("1") #public project + assert !project_ids.include?("2") #private project user cannot see + end + def find_issues_with_query(query) Issue.find :all, :include => [ :assigned_to, :status, :tracker, :project, :priority ], From 36ad597b6916a8c88b626c27b9a50330c3a89ef9 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:31 +0000 Subject: [PATCH 084/777] Merged r3928 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3978 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/changeset.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/models/changeset.rb b/app/models/changeset.rb index 3bd26b11..063a4a48 100644 --- a/app/models/changeset.rb +++ b/app/models/changeset.rb @@ -76,7 +76,6 @@ class Changeset < ActiveRecord::Base def after_create scan_comment_for_issue_ids end - require 'pp' def scan_comment_for_issue_ids return if comments.blank? From 597266e5a2c1d51367ac07511f28faf804d51fd0 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:36 +0000 Subject: [PATCH 085/777] Merged r3929 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3979 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/member.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/member.rb b/app/models/member.rb index 94751efb..d840cfc3 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -82,7 +82,7 @@ class Member < ActiveRecord::Base protected def validate - errors.add_to_base "Role can't be blank" if member_roles.empty? && roles.empty? + errors.add_on_empty :role if member_roles.empty? && roles.empty? end private From b5b8d34d942f7fb486f344629a622f81a6ef008f Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:42 +0000 Subject: [PATCH 086/777] Merged r3930 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3980 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/issues_controller.rb | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 7fb4148e..a7e227c8 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -251,6 +251,18 @@ class IssuesController < ApplicationController end def move + @issues.sort! + @copy = params[:copy_options] && params[:copy_options][:copy] + @allowed_projects = Issue.allowed_target_projects_on_move + @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] + @target_project ||= @project + @trackers = @target_project.trackers + @available_statuses = Workflow.available_statuses(@project) + render :layout => false if request.xhr? + end + + # TODO: more descriptive name? move to separate controller like IssueMovesController? + def perform_move @issues.sort! @copy = params[:copy_options] && params[:copy_options][:copy] @allowed_projects = Issue.allowed_target_projects_on_move @@ -285,12 +297,6 @@ class IssuesController < ApplicationController end return end - render :layout => false if request.xhr? - end - - # TODO: more descriptive name? move to separate controller like IssueMovesController? - def perform_move - move end def destroy From 358ee2ef2ef87402174021871f6531dbc508b518 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:47 +0000 Subject: [PATCH 087/777] Merged r3931 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3981 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/timelog_controller.rb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/controllers/timelog_controller.rb b/app/controllers/timelog_controller.rb index 7addff78..e234848d 100644 --- a/app/controllers/timelog_controller.rb +++ b/app/controllers/timelog_controller.rb @@ -55,8 +55,7 @@ class TimelogController < ApplicationController sql = "SELECT #{sql_select}, tyear, tmonth, tweek, spent_on, SUM(hours) AS hours" sql << " FROM #{TimeEntry.table_name}" - sql << " LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id" - sql << " LEFT JOIN #{Project.table_name} ON #{TimeEntry.table_name}.project_id = #{Project.table_name}.id" + sql << time_report_joins sql << " WHERE" sql << " (%s) AND" % sql_condition sql << " (spent_on BETWEEN '%s' AND '%s')" % [ActiveRecord::Base.connection.quoted_date(@from), ActiveRecord::Base.connection.quoted_date(@to)] @@ -314,4 +313,12 @@ private call_hook(:controller_timelog_available_criterias, { :available_criterias => @available_criterias, :project => @project }) @available_criterias end + + def time_report_joins + sql = '' + sql << " LEFT JOIN #{Issue.table_name} ON #{TimeEntry.table_name}.issue_id = #{Issue.table_name}.id" + sql << " LEFT JOIN #{Project.table_name} ON #{TimeEntry.table_name}.project_id = #{Project.table_name}.id" + call_hook(:controller_timelog_time_report_joins, {:sql => sql} ) + sql + end end From 72ce3e18f8bfb2cb288d6401429d035ad6562ce4 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:53 +0000 Subject: [PATCH 088/777] Merged r3932 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3982 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/issues_controller.rb | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index a7e227c8..46c61ea0 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -251,25 +251,14 @@ class IssuesController < ApplicationController end def move - @issues.sort! - @copy = params[:copy_options] && params[:copy_options][:copy] - @allowed_projects = Issue.allowed_target_projects_on_move - @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] - @target_project ||= @project - @trackers = @target_project.trackers - @available_statuses = Workflow.available_statuses(@project) + prepare_for_issue_move render :layout => false if request.xhr? end # TODO: more descriptive name? move to separate controller like IssueMovesController? def perform_move - @issues.sort! - @copy = params[:copy_options] && params[:copy_options][:copy] - @allowed_projects = Issue.allowed_target_projects_on_move - @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] - @target_project ||= @project - @trackers = @target_project.trackers - @available_statuses = Workflow.available_statuses(@project) + prepare_for_issue_move + if request.post? new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) unsaved_issue_ids = [] @@ -473,6 +462,16 @@ private @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) end + def prepare_for_issue_move + @issues.sort! + @copy = params[:copy_options] && params[:copy_options][:copy] + @allowed_projects = Issue.allowed_target_projects_on_move + @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] + @target_project ||= @project + @trackers = @target_project.trackers + @available_statuses = Workflow.available_statuses(@project) + end + def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) if unsaved_issue_ids.empty? flash[:notice] = l(:notice_successful_update) unless issues.empty? From 7ca197b37f9c8aba08560f985ec063d1c6d70a8a Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:32:59 +0000 Subject: [PATCH 089/777] Merged r3933 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3983 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/functional/account_controller_test.rb | 7 +++++++ .../open_id_authentication/lib/open_id_authentication.rb | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/test/functional/account_controller_test.rb b/test/functional/account_controller_test.rb index 2a8c9c66..1d66d01d 100644 --- a/test/functional/account_controller_test.rb +++ b/test/functional/account_controller_test.rb @@ -67,6 +67,13 @@ class AccountControllerTest < ActionController::TestCase assert_redirected_to 'my/page' end + def test_login_with_invalid_openid_provider + Setting.self_registration = '0' + Setting.openid = '1' + post :login, :openid_url => 'http;//openid.example.com/good_user' + assert_redirected_to home_url + end + def test_login_with_openid_for_existing_non_active_user Setting.self_registration = '2' Setting.openid = '1' diff --git a/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb b/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb index 22481136..70418fde 100644 --- a/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb +++ b/vendor/plugins/open_id_authentication/lib/open_id_authentication.rb @@ -89,7 +89,7 @@ module OpenIdAuthentication begin uri = URI.parse(identifier) - uri.scheme = uri.scheme.downcase # URI should do this + uri.scheme = uri.scheme.downcase if uri.scheme # URI should do this identifier = uri.normalize.to_s rescue URI::InvalidURIError raise InvalidOpenId.new("#{identifier} is not an OpenID identifier") From 5345a2dd8979da186e83e7e3475422454a609bf2 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:05 +0000 Subject: [PATCH 090/777] Merged r3934 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3984 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/groups_controller.rb | 24 ++++++++++++++++-------- app/controllers/users_controller.rb | 24 ++++++++++++++++-------- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index 4bd732fc..29e4e4b0 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -141,14 +141,22 @@ class GroupsController < ApplicationController @membership = Member.edit_membership(params[:membership_id], params[:membership], @group) @membership.save if request.post? respond_to do |format| - format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' } - format.js { - render(:update) {|page| - page.replace_html "tab-content-memberships", :partial => 'groups/memberships' - page.visual_effect(:highlight, "member-#{@membership.id}") - } - } - end + if @membership.valid? + format.html { redirect_to :controller => 'groups', :action => 'edit', :id => @group, :tab => 'memberships' } + format.js { + render(:update) {|page| + page.replace_html "tab-content-memberships", :partial => 'groups/memberships' + page.visual_effect(:highlight, "member-#{@membership.id}") + } + } + else + format.js { + render(:update) {|page| + page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', '))) + } + } + end + end end def destroy_membership diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index f19cd783..023352d8 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -123,14 +123,22 @@ class UsersController < ApplicationController @membership = Member.edit_membership(params[:membership_id], params[:membership], @user) @membership.save if request.post? respond_to do |format| - format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' } - format.js { - render(:update) {|page| - page.replace_html "tab-content-memberships", :partial => 'users/memberships' - page.visual_effect(:highlight, "member-#{@membership.id}") - } - } - end + if @membership.valid? + format.html { redirect_to :controller => 'users', :action => 'edit', :id => @user, :tab => 'memberships' } + format.js { + render(:update) {|page| + page.replace_html "tab-content-memberships", :partial => 'users/memberships' + page.visual_effect(:highlight, "member-#{@membership.id}") + } + } + else + format.js { + render(:update) {|page| + page.alert(l(:notice_failed_to_save_members, :errors => @membership.errors.full_messages.join(', '))) + } + } + end + end end def destroy_membership From ab5ce45b4362af6452a4024ccefb0a9f2b700576 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:11 +0000 Subject: [PATCH 091/777] Merged r3935 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3985 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/users_controller.rb | 6 ++---- test/functional/users_controller_test.rb | 10 ++++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 023352d8..0354d165 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -53,10 +53,8 @@ class UsersController < ApplicationController @user = User.find(params[:id]) @custom_values = @user.custom_values - # show only public projects and private projects that the logged in user is also a member of - @memberships = @user.memberships.select do |membership| - membership.project.is_public? || (User.current.member_of?(membership.project)) - end + # show projects based on current user visibility + @memberships = @user.memberships.all(:conditions => Project.visible_by(User.current)) events = Redmine::Activity::Fetcher.new(User.current, :author => @user).events(nil, nil, :limit => 10) @events_by_day = events.group_by(&:event_date) diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index d178f8f8..640ce868 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -96,6 +96,16 @@ class UsersControllerTest < ActionController::TestCase assert_response 200 assert_not_nil assigns(:user) end + + def test_show_displays_memberships_based_on_project_visibility + @request.session[:user_id] = 1 + get :show, :id => 2 + assert_response :success + memberships = assigns(:memberships) + assert_not_nil memberships + project_ids = memberships.map(&:project_id) + assert project_ids.include?(2) #private project admin can see + end def test_edit ActionMailer::Base.deliveries.clear From fab5064643372d91da29bb7dacb6025e9d498f3b Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:18 +0000 Subject: [PATCH 092/777] Merged r3936 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3986 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/issue_moves_controller.rb | 94 ++++++++++++++++++ app/controllers/issues_controller.rb | 58 ----------- app/helpers/issue_moves_helper.rb | 2 + .../move.rhtml => issue_moves/new.rhtml} | 4 +- app/views/issues/_action_menu.rhtml | 4 +- app/views/issues/context_menu.rhtml | 4 +- config/routes.rb | 9 +- lib/redmine.rb | 2 +- .../functional/issue_moves_controller_test.rb | 99 +++++++++++++++++++ test/functional/issues_controller_test.rb | 97 +----------------- test/integration/routing_test.rb | 4 +- test/unit/helpers/issue_moves_helper_test.rb | 4 + 12 files changed, 217 insertions(+), 164 deletions(-) create mode 100644 app/controllers/issue_moves_controller.rb create mode 100644 app/helpers/issue_moves_helper.rb rename app/views/{issues/move.rhtml => issue_moves/new.rhtml} (96%) create mode 100644 test/functional/issue_moves_controller_test.rb create mode 100644 test/unit/helpers/issue_moves_helper_test.rb diff --git a/app/controllers/issue_moves_controller.rb b/app/controllers/issue_moves_controller.rb new file mode 100644 index 00000000..1999930d --- /dev/null +++ b/app/controllers/issue_moves_controller.rb @@ -0,0 +1,94 @@ +class IssueMovesController < ApplicationController + default_search_scope :issues + before_filter :find_issues + before_filter :authorize + + def new + prepare_for_issue_move + render :layout => false if request.xhr? + end + + def create + prepare_for_issue_move + + if request.post? + new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) + unsaved_issue_ids = [] + moved_issues = [] + @issues.each do |issue| + issue.reload + issue.init_journal(User.current) + call_hook(:controller_issues_move_before_save, { :params => params, :issue => issue, :target_project => @target_project, :copy => !!@copy }) + if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => extract_changed_attributes_for_move(params)}) + moved_issues << r + else + unsaved_issue_ids << issue.id + end + end + set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) + + if params[:follow] + if @issues.size == 1 && moved_issues.size == 1 + redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first + else + redirect_to :controller => 'issues', :action => 'index', :project_id => (@target_project || @project) + end + else + redirect_to :controller => 'issues', :action => 'index', :project_id => @project + end + return + end + end + + private + + def prepare_for_issue_move + @issues.sort! + @copy = params[:copy_options] && params[:copy_options][:copy] + @allowed_projects = Issue.allowed_target_projects_on_move + @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] + @target_project ||= @project + @trackers = @target_project.trackers + @available_statuses = Workflow.available_statuses(@project) + end + + # Filter for bulk operations + # TODO: duplicated in IssuesController + def find_issues + @issues = Issue.find_all_by_id(params[:id] || params[:ids]) + raise ActiveRecord::RecordNotFound if @issues.empty? + projects = @issues.collect(&:project).compact.uniq + if projects.size == 1 + @project = projects.first + else + # TODO: let users bulk edit/move/destroy issues from different projects + render_error 'Can not bulk edit/move/destroy issues from different projects' + return false + end + rescue ActiveRecord::RecordNotFound + render_404 + end + + # TODO: duplicated in IssuesController + def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) + if unsaved_issue_ids.empty? + flash[:notice] = l(:notice_successful_update) unless issues.empty? + else + flash[:error] = l(:notice_failed_to_save_issues, + :count => unsaved_issue_ids.size, + :total => issues.size, + :ids => '#' + unsaved_issue_ids.join(', #')) + end + end + + def extract_changed_attributes_for_move(params) + changed_attributes = {} + [:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute| + unless params[valid_attribute].blank? + changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) + end + end + changed_attributes + end + +end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 46c61ea0..50a6f08e 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -249,44 +249,6 @@ class IssuesController < ApplicationController @available_statuses = Workflow.available_statuses(@project) @custom_fields = @project.all_issue_custom_fields end - - def move - prepare_for_issue_move - render :layout => false if request.xhr? - end - - # TODO: more descriptive name? move to separate controller like IssueMovesController? - def perform_move - prepare_for_issue_move - - if request.post? - new_tracker = params[:new_tracker_id].blank? ? nil : @target_project.trackers.find_by_id(params[:new_tracker_id]) - unsaved_issue_ids = [] - moved_issues = [] - @issues.each do |issue| - issue.reload - issue.init_journal(User.current) - call_hook(:controller_issues_move_before_save, { :params => params, :issue => issue, :target_project => @target_project, :copy => !!@copy }) - if r = issue.move_to_project(@target_project, new_tracker, {:copy => @copy, :attributes => extract_changed_attributes_for_move(params)}) - moved_issues << r - else - unsaved_issue_ids << issue.id - end - end - set_flash_from_bulk_issue_save(@issues, unsaved_issue_ids) - - if params[:follow] - if @issues.size == 1 && moved_issues.size == 1 - redirect_to :controller => 'issues', :action => 'show', :id => moved_issues.first - else - redirect_to :controller => 'issues', :action => 'index', :project_id => (@target_project || @project) - end - else - redirect_to :controller => 'issues', :action => 'index', :project_id => @project - end - return - end - end def destroy @hours = TimeEntry.sum(:hours, :conditions => ['issue_id IN (?)', @issues]).to_f @@ -462,16 +424,6 @@ private @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) end - def prepare_for_issue_move - @issues.sort! - @copy = params[:copy_options] && params[:copy_options][:copy] - @allowed_projects = Issue.allowed_target_projects_on_move - @target_project = @allowed_projects.detect {|p| p.id.to_s == params[:new_project_id]} if params[:new_project_id] - @target_project ||= @project - @trackers = @target_project.trackers - @available_statuses = Workflow.available_statuses(@project) - end - def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) if unsaved_issue_ids.empty? flash[:notice] = l(:notice_successful_update) unless issues.empty? @@ -489,14 +441,4 @@ private return false end end - - def extract_changed_attributes_for_move(params) - changed_attributes = {} - [:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute| - unless params[valid_attribute].blank? - changed_attributes[valid_attribute] = (params[valid_attribute] == 'none' ? nil : params[valid_attribute]) - end - end - changed_attributes - end end diff --git a/app/helpers/issue_moves_helper.rb b/app/helpers/issue_moves_helper.rb new file mode 100644 index 00000000..b58b4ce5 --- /dev/null +++ b/app/helpers/issue_moves_helper.rb @@ -0,0 +1,2 @@ +module IssueMovesHelper +end diff --git a/app/views/issues/move.rhtml b/app/views/issue_moves/new.rhtml similarity index 96% rename from app/views/issues/move.rhtml rename to app/views/issue_moves/new.rhtml index c216cba7..2dc971df 100644 --- a/app/views/issues/move.rhtml +++ b/app/views/issue_moves/new.rhtml @@ -6,14 +6,14 @@ <% end -%> -<% form_tag({:action => 'perform_move'}, :id => 'move_form') do %> +<% form_tag({:action => 'create'}, :id => 'move_form') do %> <%= @issues.collect {|i| hidden_field_tag('ids[]', i.id)}.join %>

    <%= select_tag "new_project_id", project_tree_options_for_select(@allowed_projects, :selected => @target_project), - :onchange => remote_function(:url => { :action => 'move' }, + :onchange => remote_function(:url => { :action => 'new' }, :method => :get, :update => 'content', :with => "Form.serialize('move_form')") %>

    diff --git a/app/views/issues/_action_menu.rhtml b/app/views/issues/_action_menu.rhtml index 693b4923..c5d17511 100644 --- a/app/views/issues/_action_menu.rhtml +++ b/app/views/issues/_action_menu.rhtml @@ -4,7 +4,7 @@ <% replace_watcher ||= 'watcher' %> <%= watcher_tag(@issue, User.current, {:id => replace_watcher, :replace => ['watcher','watcher2']}) %> <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %> -<%= link_to_if_authorized l(:button_copy), {:controller => 'issues', :action => 'move', :id => @issue, :copy_options => {:copy => 't'} }, :class => 'icon icon-copy' %> -<%= link_to_if_authorized l(:button_move), {:controller => 'issues', :action => 'move', :id => @issue }, :class => 'icon icon-move' %> +<%= link_to_if_authorized l(:button_copy), new_issue_move_path(:id => @issue, :copy_options => {:copy => 't'}), :class => 'icon icon-copy' %> +<%= link_to_if_authorized l(:button_move), new_issue_move_path(:id => @issue), :class => 'icon icon-move' %> <%= link_to_if_authorized l(:button_delete), {:controller => 'issues', :action => 'destroy', :id => @issue}, :confirm => l(:text_are_you_sure), :method => :post, :class => 'icon icon-del' %>
    diff --git a/app/views/issues/context_menu.rhtml b/app/views/issues/context_menu.rhtml index d9e92a4f..dc11b5fd 100644 --- a/app/views/issues/context_menu.rhtml +++ b/app/views/issues/context_menu.rhtml @@ -102,9 +102,9 @@
  • <%= context_menu_link l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue}, :class => 'icon-duplicate', :disabled => !@can[:copy] %>
  • <% end %> -
  • <%= context_menu_link l(:button_copy), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id), :copy_options => {:copy => 't'}}, +
  • <%= context_menu_link l(:button_copy), new_issue_move_path(:ids => @issues.collect(&:id), :copy_options => {:copy => 't'}), :class => 'icon-copy', :disabled => !@can[:move] %>
  • -
  • <%= context_menu_link l(:button_move), {:controller => 'issues', :action => 'move', :ids => @issues.collect(&:id)}, +
  • <%= context_menu_link l(:button_move), new_issue_move_path(:ids => @issues.collect(&:id)), :class => 'icon-move', :disabled => !@can[:move] %>
  • <%= context_menu_link l(:button_delete), {:controller => 'issues', :action => 'destroy', :ids => @issues.collect(&:id)}, :method => :post, :confirm => l(:text_issues_destroy_confirmation), :class => 'icon-del', :disabled => !@can[:delete] %>
  • diff --git a/config/routes.rb b/config/routes.rb index 2e8a145c..6f71cb65 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -102,7 +102,9 @@ ActionController::Routing::Routes.draw do |map| document_actions.connect 'documents/:id/:action', :action => /destroy|edit/ end end - + + map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move' + map.with_options :controller => 'issues' do |issues_routes| issues_routes.with_options :conditions => {:method => :get} do |issues_views| issues_views.connect 'issues', :action => 'index' @@ -116,7 +118,6 @@ ActionController::Routing::Routes.draw do |map| issues_views.connect 'issues/:id', :action => 'show', :id => /\d+/ issues_views.connect 'issues/:id.:format', :action => 'show', :id => /\d+/ issues_views.connect 'issues/:id/edit', :action => 'edit', :id => /\d+/ - issues_views.connect 'issues/:id/move', :action => 'move', :id => /\d+/ end issues_routes.with_options :conditions => {:method => :post} do |issues_actions| issues_actions.connect 'issues', :action => 'index' @@ -124,7 +125,7 @@ ActionController::Routing::Routes.draw do |map| issues_actions.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show' issues_actions.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show' issues_actions.connect 'issues/:id/quoted', :action => 'reply', :id => /\d+/ - issues_actions.connect 'issues/:id/:action', :action => /edit|perform_move|destroy/, :id => /\d+/ + issues_actions.connect 'issues/:id/:action', :action => /edit|destroy/, :id => /\d+/ issues_actions.connect 'issues.:format', :action => 'create', :format => /xml/ end issues_routes.with_options :conditions => {:method => :put} do |issues_actions| @@ -138,7 +139,7 @@ ActionController::Routing::Routes.draw do |map| issues_routes.connect 'issues/calendar', :controller => 'calendars', :action => 'show' issues_routes.connect 'issues/:action' end - + map.with_options :controller => 'issue_relations', :conditions => {:method => :post} do |relations| relations.connect 'issues/:issue_id/relations/:id', :action => 'new' relations.connect 'issues/:issue_id/relations/:id/destroy', :action => 'destroy' diff --git a/lib/redmine.rb b/lib/redmine.rb index 4196a5d7..1d8dbea1 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -69,7 +69,7 @@ Redmine::AccessControl.map do |map| map.permission :add_issue_notes, {:issues => [:edit, :update, :reply]} map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin - map.permission :move_issues, {:issues => [:move, :perform_move]}, :require => :loggedin + map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin map.permission :delete_issues, {:issues => :destroy}, :require => :member # Queries map.permission :manage_public_queries, {:queries => [:new, :edit, :destroy]}, :require => :member diff --git a/test/functional/issue_moves_controller_test.rb b/test/functional/issue_moves_controller_test.rb new file mode 100644 index 00000000..083959c7 --- /dev/null +++ b/test/functional/issue_moves_controller_test.rb @@ -0,0 +1,99 @@ +require 'test_helper' + +class IssueMovesControllerTest < ActionController::TestCase + fixtures :all + + def setup + User.current = nil + end + + def test_create_one_issue_to_another_project + @request.session[:user_id] = 2 + post :create, :id => 1, :new_project_id => 2, :tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' + assert_equal 2, Issue.find(1).project_id + end + + def test_create_one_issue_to_another_project_should_follow_when_needed + @request.session[:user_id] = 2 + post :create, :id => 1, :new_project_id => 2, :follow => '1' + assert_redirected_to '/issues/1' + end + + def test_bulk_create_to_another_project + @request.session[:user_id] = 2 + post :create, :ids => [1, 2], :new_project_id => 2 + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' + # Issues moved to project 2 + assert_equal 2, Issue.find(1).project_id + assert_equal 2, Issue.find(2).project_id + # No tracker change + assert_equal 1, Issue.find(1).tracker_id + assert_equal 2, Issue.find(2).tracker_id + end + + def test_bulk_create_to_another_tracker + @request.session[:user_id] = 2 + post :create, :ids => [1, 2], :new_tracker_id => 2 + assert_redirected_to :controller => 'issues', :action => 'index', :project_id => 'ecookbook' + assert_equal 2, Issue.find(1).tracker_id + assert_equal 2, Issue.find(2).tracker_id + end + + def test_bulk_copy_to_another_project + @request.session[:user_id] = 2 + assert_difference 'Issue.count', 2 do + assert_no_difference 'Project.find(1).issues.count' do + post :create, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'} + end + end + assert_redirected_to 'projects/ecookbook/issues' + end + + context "#create via bulk copy" do + should "allow not changing the issue's attributes" do + @request.session[:user_id] = 2 + issue_before_move = Issue.find(1) + assert_difference 'Issue.count', 1 do + assert_no_difference 'Project.find(1).issues.count' do + post :create, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' + end + end + issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2}) + assert_equal issue_before_move.tracker_id, issue_after_move.tracker_id + assert_equal issue_before_move.status_id, issue_after_move.status_id + assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id + end + + should "allow changing the issue's attributes" do + # Fixes random test failure with Mysql + # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) doesn't return the expected results + Issue.delete_all("project_id=2") + + @request.session[:user_id] = 2 + assert_difference 'Issue.count', 2 do + assert_no_difference 'Project.find(1).issues.count' do + post :create, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => 4, :status_id => 3, :start_date => '2009-12-01', :due_date => '2009-12-31' + end + end + + copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) + assert_equal 2, copied_issues.size + copied_issues.each do |issue| + assert_equal 2, issue.project_id, "Project is incorrect" + assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect" + assert_equal 3, issue.status_id, "Status is incorrect" + assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect" + assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect" + end + end + end + + def test_copy_to_another_project_should_follow_when_needed + @request.session[:user_id] = 2 + post :create, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1' + issue = Issue.first(:order => 'id DESC') + assert_redirected_to :controller => 'issues', :action => 'show', :id => issue + end + +end diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 92e6fd30..6b23a651 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -1037,95 +1037,6 @@ class IssuesControllerTest < ActionController::TestCase assert_response :redirect assert_redirected_to :controller => 'issues', :action => 'index', :project_id => Project.find(1).identifier end - - def test_perform_move_one_issue_to_another_project - @request.session[:user_id] = 2 - post :perform_move, :id => 1, :new_project_id => 2, :tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' - assert_redirected_to :action => 'index', :project_id => 'ecookbook' - assert_equal 2, Issue.find(1).project_id - end - - def test_perform_move_one_issue_to_another_project_should_follow_when_needed - @request.session[:user_id] = 2 - post :perform_move, :id => 1, :new_project_id => 2, :follow => '1' - assert_redirected_to '/issues/1' - end - - def test_bulk_perform_move_to_another_project - @request.session[:user_id] = 2 - post :perform_move, :ids => [1, 2], :new_project_id => 2 - assert_redirected_to :action => 'index', :project_id => 'ecookbook' - # Issues moved to project 2 - assert_equal 2, Issue.find(1).project_id - assert_equal 2, Issue.find(2).project_id - # No tracker change - assert_equal 1, Issue.find(1).tracker_id - assert_equal 2, Issue.find(2).tracker_id - end - - def test_bulk_perform_move_to_another_tracker - @request.session[:user_id] = 2 - post :perform_move, :ids => [1, 2], :new_tracker_id => 2 - assert_redirected_to :action => 'index', :project_id => 'ecookbook' - assert_equal 2, Issue.find(1).tracker_id - assert_equal 2, Issue.find(2).tracker_id - end - - def test_bulk_copy_to_another_project - @request.session[:user_id] = 2 - assert_difference 'Issue.count', 2 do - assert_no_difference 'Project.find(1).issues.count' do - post :perform_move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'} - end - end - assert_redirected_to 'projects/ecookbook/issues' - end - - context "#perform_move via bulk copy" do - should "allow not changing the issue's attributes" do - @request.session[:user_id] = 2 - issue_before_move = Issue.find(1) - assert_difference 'Issue.count', 1 do - assert_no_difference 'Project.find(1).issues.count' do - post :perform_move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => '', :status_id => '', :start_date => '', :due_date => '' - end - end - issue_after_move = Issue.first(:order => 'id desc', :conditions => {:project_id => 2}) - assert_equal issue_before_move.tracker_id, issue_after_move.tracker_id - assert_equal issue_before_move.status_id, issue_after_move.status_id - assert_equal issue_before_move.assigned_to_id, issue_after_move.assigned_to_id - end - - should "allow changing the issue's attributes" do - # Fixes random test failure with Mysql - # where Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) doesn't return the expected results - Issue.delete_all("project_id=2") - - @request.session[:user_id] = 2 - assert_difference 'Issue.count', 2 do - assert_no_difference 'Project.find(1).issues.count' do - post :perform_move, :ids => [1, 2], :new_project_id => 2, :copy_options => {:copy => '1'}, :new_tracker_id => '', :assigned_to_id => 4, :status_id => 3, :start_date => '2009-12-01', :due_date => '2009-12-31' - end - end - - copied_issues = Issue.all(:limit => 2, :order => 'id desc', :conditions => {:project_id => 2}) - assert_equal 2, copied_issues.size - copied_issues.each do |issue| - assert_equal 2, issue.project_id, "Project is incorrect" - assert_equal 4, issue.assigned_to_id, "Assigned to is incorrect" - assert_equal 3, issue.status_id, "Status is incorrect" - assert_equal '2009-12-01', issue.start_date.to_s, "Start date is incorrect" - assert_equal '2009-12-31', issue.due_date.to_s, "Due date is incorrect" - end - end - end - - def test_copy_to_another_project_should_follow_when_needed - @request.session[:user_id] = 2 - post :perform_move, :ids => [1], :new_project_id => 2, :copy_options => {:copy => '1'}, :follow => '1' - issue = Issue.first(:order => 'id DESC') - assert_redirected_to :controller => 'issues', :action => 'show', :id => issue - end def test_context_menu_one_issue @request.session[:user_id] = 2 @@ -1156,10 +1067,10 @@ class IssuesControllerTest < ActionController::TestCase :attributes => { :href => '/projects/ecookbook/issues/1/copy', :class => 'icon-duplicate' } assert_tag :tag => 'a', :content => 'Copy', - :attributes => { :href => '/issues/move?copy_options%5Bcopy%5D=t&ids%5B%5D=1', + :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&ids%5B%5D=1', :class => 'icon-copy' } assert_tag :tag => 'a', :content => 'Move', - :attributes => { :href => '/issues/move?ids%5B%5D=1', + :attributes => { :href => '/issues/move/new?ids%5B%5D=1', :class => 'icon-move' } assert_tag :tag => 'a', :content => 'Delete', :attributes => { :href => '/issues/destroy?ids%5B%5D=1', @@ -1190,10 +1101,10 @@ class IssuesControllerTest < ActionController::TestCase :attributes => { :href => '/issues/bulk_edit?ids%5B%5D=1&ids%5B%5D=2&issue%5Bassigned_to_id%5D=3', :class => '' } assert_tag :tag => 'a', :content => 'Copy', - :attributes => { :href => '/issues/move?copy_options%5Bcopy%5D=t&ids%5B%5D=1&ids%5B%5D=2', + :attributes => { :href => '/issues/move/new?copy_options%5Bcopy%5D=t&ids%5B%5D=1&ids%5B%5D=2', :class => 'icon-copy' } assert_tag :tag => 'a', :content => 'Move', - :attributes => { :href => '/issues/move?ids%5B%5D=1&ids%5B%5D=2', + :attributes => { :href => '/issues/move/new?ids%5B%5D=1&ids%5B%5D=2', :class => 'icon-move' } assert_tag :tag => 'a', :content => 'Delete', :attributes => { :href => '/issues/destroy?ids%5B%5D=1&ids%5B%5D=2', diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb index 51f8e71f..af66f741 100644 --- a/test/integration/routing_test.rb +++ b/test/integration/routing_test.rb @@ -85,8 +85,8 @@ class RoutingTest < ActionController::IntegrationTest # Extra actions should_route :get, "/projects/23/issues/64/copy", :controller => 'issues', :action => 'new', :project_id => '23', :copy_from => '64' - should_route :get, "/issues/1/move", :controller => 'issues', :action => 'move', :id => '1' - should_route :post, "/issues/1/perform_move", :controller => 'issues', :action => 'perform_move', :id => '1' + should_route :get, "/issues/move/new", :controller => 'issue_moves', :action => 'new' + should_route :post, "/issues/move", :controller => 'issue_moves', :action => 'create' should_route :post, "/issues/1/quoted", :controller => 'issues', :action => 'reply', :id => '1' diff --git a/test/unit/helpers/issue_moves_helper_test.rb b/test/unit/helpers/issue_moves_helper_test.rb new file mode 100644 index 00000000..b2ffb604 --- /dev/null +++ b/test/unit/helpers/issue_moves_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class IssueMovesHelperTest < ActionView::TestCase +end From 7af610631f47c004a7242d20c34459d52f06fd01 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:23 +0000 Subject: [PATCH 093/777] Merged r3937 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3987 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/functional/issue_moves_controller_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/functional/issue_moves_controller_test.rb b/test/functional/issue_moves_controller_test.rb index 083959c7..7c400576 100644 --- a/test/functional/issue_moves_controller_test.rb +++ b/test/functional/issue_moves_controller_test.rb @@ -1,4 +1,4 @@ -require 'test_helper' +require File.dirname(__FILE__) + '/../test_helper' class IssueMovesControllerTest < ActionController::TestCase fixtures :all From 6e5f56734653b9e6e563b299ff1d20ce6ffcf036 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:29 +0000 Subject: [PATCH 094/777] Merged r3938 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3988 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/application_controller.rb | 18 +++++++++++++++++- app/controllers/issue_moves_controller.rb | 17 ----------------- app/controllers/issues_controller.rb | 16 ---------------- 3 files changed, 17 insertions(+), 34 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index c00b6ba4..3e482cf4 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -201,7 +201,23 @@ class ApplicationController < ActionController::Base def self.model_object(model) write_inheritable_attribute('model_object', model) end - + + # Filter for bulk issue operations + def find_issues + @issues = Issue.find_all_by_id(params[:id] || params[:ids]) + raise ActiveRecord::RecordNotFound if @issues.empty? + projects = @issues.collect(&:project).compact.uniq + if projects.size == 1 + @project = projects.first + else + # TODO: let users bulk edit/move/destroy issues from different projects + render_error 'Can not bulk edit/move/destroy issues from different projects' + return false + end + rescue ActiveRecord::RecordNotFound + render_404 + end + # make sure that the user is a member of the project (or admin) if project is private # used as a before_filter for actions that do not require any particular permission on the project def check_project_privacy diff --git a/app/controllers/issue_moves_controller.rb b/app/controllers/issue_moves_controller.rb index 1999930d..37068fad 100644 --- a/app/controllers/issue_moves_controller.rb +++ b/app/controllers/issue_moves_controller.rb @@ -52,23 +52,6 @@ class IssueMovesController < ApplicationController @available_statuses = Workflow.available_statuses(@project) end - # Filter for bulk operations - # TODO: duplicated in IssuesController - def find_issues - @issues = Issue.find_all_by_id(params[:id] || params[:ids]) - raise ActiveRecord::RecordNotFound if @issues.empty? - projects = @issues.collect(&:project).compact.uniq - if projects.size == 1 - @project = projects.first - else - # TODO: let users bulk edit/move/destroy issues from different projects - render_error 'Can not bulk edit/move/destroy issues from different projects' - return false - end - rescue ActiveRecord::RecordNotFound - render_404 - end - # TODO: duplicated in IssuesController def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) if unsaved_issue_ids.empty? diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 50a6f08e..e05d1939 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -359,22 +359,6 @@ private render_404 end - # Filter for bulk operations - def find_issues - @issues = Issue.find_all_by_id(params[:id] || params[:ids]) - raise ActiveRecord::RecordNotFound if @issues.empty? - projects = @issues.collect(&:project).compact.uniq - if projects.size == 1 - @project = projects.first - else - # TODO: let users bulk edit/move/destroy issues from different projects - render_error 'Can not bulk edit/move/destroy issues from different projects' - return false - end - rescue ActiveRecord::RecordNotFound - render_404 - end - def find_project project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] @project = Project.find(project_id) From 10a76f5e733acdc89fbe6a6994d3e1298f590375 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:34 +0000 Subject: [PATCH 095/777] Merged r3939 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3989 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/repositories/diff.rhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/repositories/diff.rhtml b/app/views/repositories/diff.rhtml index 73e13abf..36e86403 100644 --- a/app/views/repositories/diff.rhtml +++ b/app/views/repositories/diff.rhtml @@ -1,7 +1,7 @@

    <%= l(:label_revision) %> <%= format_revision(@rev_to) + ':' if @rev_to %><%= format_revision(@rev) %> <%=h @path %>

    -<% form_tag({}, :method => 'get') do %> +<% form_tag({:path => @path}, :method => 'get') do %> <%= hidden_field_tag('rev', params[:rev]) if params[:rev] %> <%= hidden_field_tag('rev_to', params[:rev_to]) if params[:rev_to] %>

    From 8ca6941a33276bd745f6786f9a27f92abad950b0 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:40 +0000 Subject: [PATCH 096/777] Merged r3940 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3990 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/application_controller.rb | 15 +++++++++++++++ app/controllers/issue_moves_controller.rb | 12 ------------ app/controllers/issues_controller.rb | 11 ----------- 3 files changed, 15 insertions(+), 23 deletions(-) diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 3e482cf4..e5909e69 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -365,6 +365,21 @@ class ApplicationController < ActionController::Base flash[:warning] = l(:warning_attachments_not_saved, obj.unsaved_attachments.size) if obj.unsaved_attachments.present? end + # Sets the `flash` notice or error based the number of issues that did not save + # + # @param [Array, Issue] issues all of the saved and unsaved Issues + # @param [Array, Integer] unsaved_issue_ids the issue ids that were not saved + def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) + if unsaved_issue_ids.empty? + flash[:notice] = l(:notice_successful_update) unless issues.empty? + else + flash[:error] = l(:notice_failed_to_save_issues, + :count => unsaved_issue_ids.size, + :total => issues.size, + :ids => '#' + unsaved_issue_ids.join(', #')) + end + end + # Rescues an invalid query statement. Just in case... def query_statement_invalid(exception) logger.error "Query::StatementInvalid: #{exception.message}" if logger diff --git a/app/controllers/issue_moves_controller.rb b/app/controllers/issue_moves_controller.rb index 37068fad..6ac46a1e 100644 --- a/app/controllers/issue_moves_controller.rb +++ b/app/controllers/issue_moves_controller.rb @@ -52,18 +52,6 @@ class IssueMovesController < ApplicationController @available_statuses = Workflow.available_statuses(@project) end - # TODO: duplicated in IssuesController - def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) - if unsaved_issue_ids.empty? - flash[:notice] = l(:notice_successful_update) unless issues.empty? - else - flash[:error] = l(:notice_failed_to_save_issues, - :count => unsaved_issue_ids.size, - :total => issues.size, - :ids => '#' + unsaved_issue_ids.join(', #')) - end - end - def extract_changed_attributes_for_move(params) changed_attributes = {} [:assigned_to_id, :status_id, :start_date, :due_date].each do |valid_attribute| diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index e05d1939..7518e375 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -408,17 +408,6 @@ private @allowed_statuses = @issue.new_statuses_allowed_to(User.current, true) end - def set_flash_from_bulk_issue_save(issues, unsaved_issue_ids) - if unsaved_issue_ids.empty? - flash[:notice] = l(:notice_successful_update) unless issues.empty? - else - flash[:error] = l(:notice_failed_to_save_issues, - :count => unsaved_issue_ids.size, - :total => issues.size, - :ids => '#' + unsaved_issue_ids.join(', #')) - end - end - def check_for_default_issue_status if IssueStatus.default.nil? render_error l(:error_no_default_issue_status) From 2012c60bfdf613ad69e5f8abdac5774754ae6a1b Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:46 +0000 Subject: [PATCH 097/777] Merged r3941 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3991 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/issues_controller.rb | 25 +-------------- app/controllers/journals_controller.rb | 34 ++++++++++++++++++++- app/helpers/journals_helper.rb | 2 +- config/routes.rb | 2 +- lib/redmine.rb | 4 +-- test/functional/issues_controller_test.rb | 14 --------- test/functional/journals_controller_test.rb | 14 +++++++++ test/integration/routing_test.rb | 2 +- 8 files changed, 53 insertions(+), 44 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 7518e375..eaa6dbc3 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -19,7 +19,7 @@ class IssuesController < ApplicationController menu_item :new_issue, :only => [:new, :create] default_search_scope :issues - before_filter :find_issue, :only => [:show, :edit, :update, :reply] + before_filter :find_issue, :only => [:show, :edit, :update] before_filter :find_issues, :only => [:bulk_edit, :move, :perform_move, :destroy] before_filter :find_project, :only => [:new, :create, :update_form, :preview, :auto_complete] before_filter :authorize, :except => [:index, :changes, :preview, :context_menu] @@ -200,29 +200,6 @@ class IssuesController < ApplicationController end end - def reply - journal = Journal.find(params[:journal_id]) if params[:journal_id] - if journal - user = journal.user - text = journal.notes - else - user = @issue.author - text = @issue.description - end - # Replaces pre blocks with [...] - text = text.to_s.strip.gsub(%r{

    ((.|\s)*?)
    }m, '[...]') - content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " - content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - - render(:update) { |page| - page.<< "$('notes').value = \"#{escape_javascript content}\";" - page.show 'update' - page << "Form.Element.focus('notes');" - page << "Element.scrollTo('update');" - page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" - } - end - # Bulk edit a set of issues def bulk_edit @issues.sort! diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index e9fe9099..10450970 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -16,7 +16,31 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class JournalsController < ApplicationController - before_filter :find_journal + before_filter :find_journal, :only => [:edit] + before_filter :find_issue, :only => [:new] + + def new + journal = Journal.find(params[:journal_id]) if params[:journal_id] + if journal + user = journal.user + text = journal.notes + else + user = @issue.author + text = @issue.description + end + # Replaces pre blocks with [...] + text = text.to_s.strip.gsub(%r{
    ((.|\s)*?)
    }m, '[...]') + content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " + content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + + render(:update) { |page| + page.<< "$('notes').value = \"#{escape_javascript content}\";" + page.show 'update' + page << "Form.Element.focus('notes');" + page << "Element.scrollTo('update');" + page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" + } + end def edit if request.post? @@ -38,4 +62,12 @@ private rescue ActiveRecord::RecordNotFound render_404 end + + # TODO: duplicated in IssuesController + def find_issue + @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) + @project = @issue.project + rescue ActiveRecord::RecordNotFound + render_404 + end end diff --git a/app/helpers/journals_helper.rb b/app/helpers/journals_helper.rb index cf877243..c8d53f25 100644 --- a/app/helpers/journals_helper.rb +++ b/app/helpers/journals_helper.rb @@ -22,7 +22,7 @@ module JournalsHelper links = [] if !journal.notes.blank? links << link_to_remote(image_tag('comment.png'), - { :url => {:controller => 'issues', :action => 'reply', :id => issue, :journal_id => journal} }, + { :url => {:controller => 'journals', :action => 'new', :id => issue, :journal_id => journal} }, :title => l(:button_quote)) if options[:reply_links] links << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", { :controller => 'journals', :action => 'edit', :id => journal }, diff --git a/config/routes.rb b/config/routes.rb index 6f71cb65..08cd1005 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -124,7 +124,7 @@ ActionController::Routing::Routes.draw do |map| issues_actions.connect 'projects/:project_id/issues', :action => 'create' issues_actions.connect 'projects/:project_id/issues/gantt', :controller => 'gantts', :action => 'show' issues_actions.connect 'projects/:project_id/issues/calendar', :controller => 'calendars', :action => 'show' - issues_actions.connect 'issues/:id/quoted', :action => 'reply', :id => /\d+/ + issues_actions.connect 'issues/:id/quoted', :controller => 'journals', :action => 'new', :id => /\d+/ issues_actions.connect 'issues/:id/:action', :action => /edit|destroy/, :id => /\d+/ issues_actions.connect 'issues.:format', :action => 'create', :format => /xml/ end diff --git a/lib/redmine.rb b/lib/redmine.rb index 1d8dbea1..e92f67b7 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -63,10 +63,10 @@ Redmine::AccessControl.map do |map| :queries => :index, :reports => [:issue_report, :issue_report_details]} map.permission :add_issues, {:issues => [:new, :create, :update_form]} - map.permission :edit_issues, {:issues => [:edit, :update, :reply, :bulk_edit, :update_form]} + map.permission :edit_issues, {:issues => [:edit, :update, :bulk_edit, :update_form], :journals => [:new]} map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]} map.permission :manage_subtasks, {} - map.permission :add_issue_notes, {:issues => [:edit, :update, :reply]} + map.permission :add_issue_notes, {:issues => [:edit, :update], :journals => [:new]} map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin map.permission :move_issues, {:issue_moves => [:new, :create]}, :require => :loggedin diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 6b23a651..0c1172f6 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -634,20 +634,6 @@ class IssuesControllerTest < ActionController::TestCase assert_equal 'This is the test_new issue', issue.subject end - def test_reply_to_issue - @request.session[:user_id] = 2 - get :reply, :id => 1 - assert_response :success - assert_select_rjs :show, "update" - end - - def test_reply_to_note - @request.session[:user_id] = 2 - get :reply, :id => 1, :journal_id => 2 - assert_response :success - assert_select_rjs :show, "update" - end - def test_update_using_invalid_http_verbs @request.session[:user_id] = 2 subject = 'Updated by an invalid http verb' diff --git a/test/functional/journals_controller_test.rb b/test/functional/journals_controller_test.rb index 0a11bab3..7d8345b2 100644 --- a/test/functional/journals_controller_test.rb +++ b/test/functional/journals_controller_test.rb @@ -31,6 +31,20 @@ class JournalsControllerTest < ActionController::TestCase User.current = nil end + def test_reply_to_issue + @request.session[:user_id] = 2 + get :new, :id => 1 + assert_response :success + assert_select_rjs :show, "update" + end + + def test_reply_to_note + @request.session[:user_id] = 2 + get :new, :id => 1, :journal_id => 2 + assert_response :success + assert_select_rjs :show, "update" + end + def test_get_edit @request.session[:user_id] = 1 xhr :get, :edit, :id => 2 diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb index af66f741..b9eac552 100644 --- a/test/integration/routing_test.rb +++ b/test/integration/routing_test.rb @@ -88,7 +88,7 @@ class RoutingTest < ActionController::IntegrationTest should_route :get, "/issues/move/new", :controller => 'issue_moves', :action => 'new' should_route :post, "/issues/move", :controller => 'issue_moves', :action => 'create' - should_route :post, "/issues/1/quoted", :controller => 'issues', :action => 'reply', :id => '1' + should_route :post, "/issues/1/quoted", :controller => 'journals', :action => 'new', :id => '1' should_route :get, "/issues/calendar", :controller => 'calendars', :action => 'show' should_route :post, "/issues/calendar", :controller => 'calendars', :action => 'show' From 758feaccab22f2e76b2c66279634f442d177d9f8 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:51 +0000 Subject: [PATCH 098/777] Merged r3942 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3992 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/boards_controller.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb index 541fefad..fa82218d 100644 --- a/app/controllers/boards_controller.rb +++ b/app/controllers/boards_controller.rb @@ -18,6 +18,7 @@ class BoardsController < ApplicationController default_search_scope :messages before_filter :find_project, :find_board_if_available, :authorize + accept_key_auth :index, :show helper :messages include MessagesHelper From 1c93f99a55299c2b0f6c61bd5a3c593328e33eb3 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:33:57 +0000 Subject: [PATCH 099/777] Merged r3943 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3993 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/gantts_controller.rb | 1 + lib/redmine.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/app/controllers/gantts_controller.rb b/app/controllers/gantts_controller.rb index e762c19c..cdfef523 100644 --- a/app/controllers/gantts_controller.rb +++ b/app/controllers/gantts_controller.rb @@ -1,4 +1,5 @@ class GanttsController < ApplicationController + menu_item :gantt before_filter :find_optional_project rescue_from Query::StatementInvalid, :with => :query_statement_invalid diff --git a/lib/redmine.rb b/lib/redmine.rb index e92f67b7..d390cda2 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -183,6 +183,7 @@ Redmine::MenuManager.map :project_menu do |menu| menu.push :issues, { :controller => 'issues', :action => 'index' }, :param => :project_id, :caption => :label_issue_plural menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new, :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } + menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil }, From bc57078b128cf994495dfa35a5df0cbcc875ff19 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:02 +0000 Subject: [PATCH 100/777] Merged r3944 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3994 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/calendars_controller.rb | 1 + lib/redmine.rb | 1 + 2 files changed, 2 insertions(+) diff --git a/app/controllers/calendars_controller.rb b/app/controllers/calendars_controller.rb index f2af5808..1115691a 100644 --- a/app/controllers/calendars_controller.rb +++ b/app/controllers/calendars_controller.rb @@ -1,4 +1,5 @@ class CalendarsController < ApplicationController + menu_item :calendar before_filter :find_optional_project rescue_from Query::StatementInvalid, :with => :query_statement_invalid diff --git a/lib/redmine.rb b/lib/redmine.rb index d390cda2..073e52d2 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -184,6 +184,7 @@ Redmine::MenuManager.map :project_menu do |menu| menu.push :new_issue, { :controller => 'issues', :action => 'new' }, :param => :project_id, :caption => :label_issue_new, :html => { :accesskey => Redmine::AccessKeys.key_for(:new_issue) } menu.push :gantt, { :controller => 'gantts', :action => 'show' }, :param => :project_id, :caption => :label_gantt + menu.push :calendar, { :controller => 'calendars', :action => 'show' }, :param => :project_id, :caption => :label_calendar menu.push :news, { :controller => 'news', :action => 'index' }, :param => :project_id, :caption => :label_news_plural menu.push :documents, { :controller => 'documents', :action => 'index' }, :param => :project_id, :caption => :label_document_plural menu.push :wiki, { :controller => 'wiki', :action => 'index', :page => nil }, From a12a073a6e3090a092f253c662cbea102f0ece43 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:08 +0000 Subject: [PATCH 101/777] Merged r3945 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3995 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/auto_completes_controller.rb | 25 +++++++++++++++++++ app/controllers/issues_controller.rb | 14 +---------- .../issues.html.erb} | 0 app/views/issues/_form.rhtml | 5 +--- config/routes.rb | 3 ++- lib/redmine.rb | 3 ++- .../auto_completes_controller_test.rb | 20 +++++++++++++++ test/functional/issues_controller_test.rb | 14 ----------- test/integration/routing_test.rb | 2 +- 9 files changed, 52 insertions(+), 34 deletions(-) create mode 100644 app/controllers/auto_completes_controller.rb rename app/views/{issues/auto_complete.html.erb => auto_completes/issues.html.erb} (100%) create mode 100644 test/functional/auto_completes_controller_test.rb diff --git a/app/controllers/auto_completes_controller.rb b/app/controllers/auto_completes_controller.rb new file mode 100644 index 00000000..1438106f --- /dev/null +++ b/app/controllers/auto_completes_controller.rb @@ -0,0 +1,25 @@ +class AutoCompletesController < ApplicationController + before_filter :find_project + + def issues + @issues = [] + q = params[:q].to_s + if q.match(/^\d+$/) + @issues << @project.issues.visible.find_by_id(q.to_i) + end + unless q.blank? + @issues += @project.issues.visible.find(:all, :conditions => ["LOWER(#{Issue.table_name}.subject) LIKE ?", "%#{q.downcase}%"], :limit => 10) + end + render :layout => false + end + + private + + def find_project + project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] + @project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + render_404 + end + +end diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index eaa6dbc3..4981f43e 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -21,7 +21,7 @@ class IssuesController < ApplicationController before_filter :find_issue, :only => [:show, :edit, :update] before_filter :find_issues, :only => [:bulk_edit, :move, :perform_move, :destroy] - before_filter :find_project, :only => [:new, :create, :update_form, :preview, :auto_complete] + before_filter :find_project, :only => [:new, :create, :update_form, :preview] before_filter :authorize, :except => [:index, :changes, :preview, :context_menu] before_filter :find_optional_project, :only => [:index, :changes] before_filter :check_for_default_issue_status, :only => [:new, :create] @@ -316,18 +316,6 @@ class IssuesController < ApplicationController render :layout => false end - def auto_complete - @issues = [] - q = params[:q].to_s - if q.match(/^\d+$/) - @issues << @project.issues.visible.find_by_id(q.to_i) - end - unless q.blank? - @issues += @project.issues.visible.find(:all, :conditions => ["LOWER(#{Issue.table_name}.subject) LIKE ?", "%#{q.downcase}%"], :limit => 10) - end - render :layout => false - end - private def find_issue @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) diff --git a/app/views/issues/auto_complete.html.erb b/app/views/auto_completes/issues.html.erb similarity index 100% rename from app/views/issues/auto_complete.html.erb rename to app/views/auto_completes/issues.html.erb diff --git a/app/views/issues/_form.rhtml b/app/views/issues/_form.rhtml index 1e3beaf8..ccb7a55a 100644 --- a/app/views/issues/_form.rhtml +++ b/app/views/issues/_form.rhtml @@ -9,10 +9,7 @@ <% unless (@issue.new_record? && @issue.parent_issue_id.nil?) || !User.current.allowed_to?(:manage_subtasks, @project) %>

    <%= f.text_field :parent_issue_id, :size => 10 %>

    -<%= javascript_tag "observeParentIssueField('#{url_for(:controller => :issues, - :action => :auto_complete, - :id => @issue, - :project_id => @project) }')" %> +<%= javascript_tag "observeParentIssueField('#{auto_complete_issues_path(:id => @issue, :project_id => @project) }')" %> <% end %>

    <%= f.text_area :description, diff --git a/config/routes.rb b/config/routes.rb index 08cd1005..910087ab 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -104,7 +104,8 @@ ActionController::Routing::Routes.draw do |map| end map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move' - + map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues' + map.with_options :controller => 'issues' do |issues_routes| issues_routes.with_options :conditions => {:method => :get} do |issues_views| issues_views.connect 'issues', :action => 'index' diff --git a/lib/redmine.rb b/lib/redmine.rb index 073e52d2..aa9fe75d 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -58,7 +58,8 @@ Redmine::AccessControl.map do |map| map.permission :manage_categories, {:projects => :settings, :issue_categories => [:new, :edit, :destroy]}, :require => :member # Issues map.permission :view_issues, {:projects => :roadmap, - :issues => [:index, :changes, :show, :context_menu, :auto_complete], + :issues => [:index, :changes, :show, :context_menu], + :auto_complete => [:issues], :versions => [:show, :status_by], :queries => :index, :reports => [:issue_report, :issue_report_details]} diff --git a/test/functional/auto_completes_controller_test.rb b/test/functional/auto_completes_controller_test.rb new file mode 100644 index 00000000..25e75fc4 --- /dev/null +++ b/test/functional/auto_completes_controller_test.rb @@ -0,0 +1,20 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class AutoCompletesControllerTest < ActionController::TestCase + fixtures :all + + def test_issues_should_not_be_case_sensitive + get :issues, :project_id => 'ecookbook', :q => 'ReCiPe' + assert_response :success + assert_not_nil assigns(:issues) + assert assigns(:issues).detect {|issue| issue.subject.match /recipe/} + end + + def test_issues_should_return_issue_with_given_id + get :issues, :project_id => 'subproject1', :q => '13' + assert_response :success + assert_not_nil assigns(:issues) + assert assigns(:issues).include?(Issue.find(13)) + end + +end diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 0c1172f6..948cf859 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -1123,20 +1123,6 @@ class IssuesControllerTest < ActionController::TestCase assert_not_nil assigns(:notes) end - def test_auto_complete_should_not_be_case_sensitive - get :auto_complete, :project_id => 'ecookbook', :q => 'ReCiPe' - assert_response :success - assert_not_nil assigns(:issues) - assert assigns(:issues).detect {|issue| issue.subject.match /recipe/} - end - - def test_auto_complete_should_return_issue_with_given_id - get :auto_complete, :project_id => 'subproject1', :q => '13' - assert_response :success - assert_not_nil assigns(:issues) - assert assigns(:issues).include?(Issue.find(13)) - end - def test_destroy_issue_with_no_time_entries assert_nil TimeEntry.find_by_issue_id(2) @request.session[:user_id] = 2 diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb index b9eac552..607df5b0 100644 --- a/test/integration/routing_test.rb +++ b/test/integration/routing_test.rb @@ -100,7 +100,7 @@ class RoutingTest < ActionController::IntegrationTest should_route :get, "/projects/project-name/issues/gantt", :controller => 'gantts', :action => 'show', :project_id => 'project-name' should_route :post, "/projects/project-name/issues/gantt", :controller => 'gantts', :action => 'show', :project_id => 'project-name' - should_route :get, "/issues/auto_complete", :controller => 'issues', :action => 'auto_complete' + should_route :get, "/issues/auto_complete", :controller => 'auto_completes', :action => 'issues' end context "issue categories" do From 80e833cd88b06f3ee2f05ec9bd376bd9712e5dae Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:14 +0000 Subject: [PATCH 102/777] Merged r3946 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3996 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/issues_controller.rb | 15 ---------- app/controllers/previews_controller.rb | 28 +++++++++++++++++++ app/views/issues/_edit.rhtml | 2 +- app/views/issues/new.rhtml | 2 +- .../issue.html.erb} | 0 config/routes.rb | 2 ++ test/functional/issues_controller_test.rb | 16 ----------- test/functional/previews_controller_test.rb | 22 +++++++++++++++ test/integration/routing_test.rb | 3 ++ 9 files changed, 57 insertions(+), 33 deletions(-) create mode 100644 app/controllers/previews_controller.rb rename app/views/{issues/preview.html.erb => previews/issue.html.erb} (100%) create mode 100644 test/functional/previews_controller_test.rb diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 4981f43e..239c23e7 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -301,21 +301,6 @@ class IssuesController < ApplicationController render :partial => 'attributes' end - def preview - @issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank? - if @issue - @attachements = @issue.attachments - @description = params[:issue] && params[:issue][:description] - if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n") - @description = nil - end - @notes = params[:notes] - else - @description = (params[:issue] ? params[:issue][:description] : nil) - end - render :layout => false - end - private def find_issue @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) diff --git a/app/controllers/previews_controller.rb b/app/controllers/previews_controller.rb new file mode 100644 index 00000000..e1c64465 --- /dev/null +++ b/app/controllers/previews_controller.rb @@ -0,0 +1,28 @@ +class PreviewsController < ApplicationController + before_filter :find_project + + def issue + @issue = @project.issues.find_by_id(params[:id]) unless params[:id].blank? + if @issue + @attachements = @issue.attachments + @description = params[:issue] && params[:issue][:description] + if @description && @description.gsub(/(\r?\n|\n\r?)/, "\n") == @issue.description.to_s.gsub(/(\r?\n|\n\r?)/, "\n") + @description = nil + end + @notes = params[:notes] + else + @description = (params[:issue] ? params[:issue][:description] : nil) + end + render :layout => false + end + + private + + def find_project + project_id = (params[:issue] && params[:issue][:project_id]) || params[:project_id] + @project = Project.find(project_id) + rescue ActiveRecord::RecordNotFound + render_404 + end + +end diff --git a/app/views/issues/_edit.rhtml b/app/views/issues/_edit.rhtml index 0c01f80b..ec36b145 100644 --- a/app/views/issues/_edit.rhtml +++ b/app/views/issues/_edit.rhtml @@ -44,7 +44,7 @@ <%= f.hidden_field :lock_version %> <%= submit_tag l(:button_submit) %> <%= link_to_remote l(:label_preview), - { :url => { :controller => 'issues', :action => 'preview', :project_id => @project, :id => @issue }, + { :url => preview_issue_path(:project_id => @project, :id => @issue), :method => 'post', :update => 'preview', :with => 'Form.serialize("issue-form")', diff --git a/app/views/issues/new.rhtml b/app/views/issues/new.rhtml index 839286bd..310085d7 100644 --- a/app/views/issues/new.rhtml +++ b/app/views/issues/new.rhtml @@ -9,7 +9,7 @@ <%= submit_tag l(:button_create) %> <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> <%= link_to_remote l(:label_preview), - { :url => { :controller => 'issues', :action => 'preview', :project_id => @project }, + { :url => preview_issue_path(:project_id => @project), :method => 'post', :update => 'preview', :with => "Form.serialize('issue-form')", diff --git a/app/views/issues/preview.html.erb b/app/views/previews/issue.html.erb similarity index 100% rename from app/views/issues/preview.html.erb rename to app/views/previews/issue.html.erb diff --git a/config/routes.rb b/config/routes.rb index 910087ab..956ce054 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -105,6 +105,8 @@ ActionController::Routing::Routes.draw do |map| map.resources :issue_moves, :only => [:new, :create], :path_prefix => '/issues', :as => 'move' map.auto_complete_issues '/issues/auto_complete', :controller => 'auto_completes', :action => 'issues' + # TODO: would look nicer as /issues/:id/preview + map.preview_issue '/issues/preview/:id', :controller => 'previews', :action => 'issue' map.with_options :controller => 'issues' do |issues_routes| issues_routes.with_options :conditions => {:method => :get} do |issues_views| diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 948cf859..22f528b7 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -1107,22 +1107,6 @@ class IssuesControllerTest < ActionController::TestCase :class => 'icon-del disabled' } end - def test_preview_new_issue - @request.session[:user_id] = 2 - post :preview, :project_id => '1', :issue => {:description => 'Foo'} - assert_response :success - assert_template 'preview' - assert_not_nil assigns(:description) - end - - def test_preview_notes - @request.session[:user_id] = 2 - post :preview, :project_id => '1', :id => 1, :issue => {:description => Issue.find(1).description}, :notes => 'Foo' - assert_response :success - assert_template 'preview' - assert_not_nil assigns(:notes) - end - def test_destroy_issue_with_no_time_entries assert_nil TimeEntry.find_by_issue_id(2) @request.session[:user_id] = 2 diff --git a/test/functional/previews_controller_test.rb b/test/functional/previews_controller_test.rb new file mode 100644 index 00000000..63456d1d --- /dev/null +++ b/test/functional/previews_controller_test.rb @@ -0,0 +1,22 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class PreviewsControllerTest < ActionController::TestCase + fixtures :all + + def test_preview_new_issue + @request.session[:user_id] = 2 + post :issue, :project_id => '1', :issue => {:description => 'Foo'} + assert_response :success + assert_template 'preview' + assert_not_nil assigns(:description) + end + + def test_preview_issue_notes + @request.session[:user_id] = 2 + post :issue, :project_id => '1', :id => 1, :issue => {:description => Issue.find(1).description}, :notes => 'Foo' + assert_response :success + assert_template 'preview' + assert_not_nil assigns(:notes) + end + +end diff --git a/test/integration/routing_test.rb b/test/integration/routing_test.rb index 607df5b0..01a96b7a 100644 --- a/test/integration/routing_test.rb +++ b/test/integration/routing_test.rb @@ -101,6 +101,9 @@ class RoutingTest < ActionController::IntegrationTest should_route :post, "/projects/project-name/issues/gantt", :controller => 'gantts', :action => 'show', :project_id => 'project-name' should_route :get, "/issues/auto_complete", :controller => 'auto_completes', :action => 'issues' + + should_route :get, "/issues/preview/123", :controller => 'previews', :action => 'issue', :id => '123' + should_route :post, "/issues/preview/123", :controller => 'previews', :action => 'issue', :id => '123' end context "issue categories" do From d1a9f81fc6d129700e58c3038f717afe73cafc01 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:20 +0000 Subject: [PATCH 103/777] Merged r3947 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3997 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/issues_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index 239c23e7..a0264bc5 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -21,8 +21,8 @@ class IssuesController < ApplicationController before_filter :find_issue, :only => [:show, :edit, :update] before_filter :find_issues, :only => [:bulk_edit, :move, :perform_move, :destroy] - before_filter :find_project, :only => [:new, :create, :update_form, :preview] - before_filter :authorize, :except => [:index, :changes, :preview, :context_menu] + before_filter :find_project, :only => [:new, :create, :update_form] + before_filter :authorize, :except => [:index, :changes, :context_menu] before_filter :find_optional_project, :only => [:index, :changes] before_filter :check_for_default_issue_status, :only => [:new, :create] before_filter :build_new_issue_from_params, :only => [:new, :create] From b9f23bedb74876552737a2385e450aca11eeff34 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:26 +0000 Subject: [PATCH 104/777] Merged r3948 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3998 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/tasks/permissions.rake | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 lib/tasks/permissions.rake diff --git a/lib/tasks/permissions.rake b/lib/tasks/permissions.rake new file mode 100644 index 00000000..02ce1b2a --- /dev/null +++ b/lib/tasks/permissions.rake @@ -0,0 +1,9 @@ +namespace :redmine do + desc "List all permissions and the actions registered with them" + task :permissions => :environment do + puts "Permission Name - controller/action pairs" + Redmine::AccessControl.permissions.sort {|a,b| a.name.to_s <=> b.name.to_s }.each do |permission| + puts ":#{permission.name} - #{permission.actions.join(', ')}" + end + end +end From d457f90fcd75ad2518601ff09fbf067648b367f5 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:31 +0000 Subject: [PATCH 105/777] Merged r3949 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@3999 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/application_controller.rb | 13 +++++++++--- test/integration/layout_test.rb | 26 +++++++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 test/integration/layout_test.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e5909e69..725bde78 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -258,7 +258,7 @@ class ApplicationController < ActionController::Base def render_403 @project = nil respond_to do |format| - format.html { render :template => "common/403", :layout => (request.xhr? ? false : 'base'), :status => 403 } + format.html { render :template => "common/403", :layout => use_layout, :status => 403 } format.atom { head 403 } format.xml { head 403 } format.js { head 403 } @@ -269,7 +269,7 @@ class ApplicationController < ActionController::Base def render_404 respond_to do |format| - format.html { render :template => "common/404", :layout => !request.xhr?, :status => 404 } + format.html { render :template => "common/404", :layout => use_layout, :status => 404 } format.atom { head 404 } format.xml { head 404 } format.js { head 404 } @@ -282,7 +282,7 @@ class ApplicationController < ActionController::Base respond_to do |format| format.html { flash.now[:error] = msg - render :text => '', :layout => !request.xhr?, :status => 500 + render :text => '', :layout => use_layout, :status => 500 } format.atom { head 500 } format.xml { head 500 } @@ -290,6 +290,13 @@ class ApplicationController < ActionController::Base format.json { head 500 } end end + + # Picks which layout to use based on the request + # + # @return [boolean, string] name of the layout to use or false for no layout + def use_layout + request.xhr? ? false : 'base' + end def invalid_authenticity_token if api_request? diff --git a/test/integration/layout_test.rb b/test/integration/layout_test.rb new file mode 100644 index 00000000..03d407d2 --- /dev/null +++ b/test/integration/layout_test.rb @@ -0,0 +1,26 @@ +require "#{File.dirname(__FILE__)}/../test_helper" + +class LayoutTest < ActionController::IntegrationTest + fixtures :all + + test "browsing to a missing page should render the base layout" do + get "/users/100000000" + + assert_response :not_found + + # UsersController uses the admin layout by default + assert_select "#admin-menu", :count => 0 + end + + test "browsing to an unauthorized page should render the base layout" do + user = User.find(9) + user.password, user.password_confirmation = 'test', 'test' + user.save! + + log_user('miscuser9','test') + + get "/admin" + assert_response :forbidden + assert_select "#admin-menu", :count => 0 + end +end From 3e692a908b99e2e1963e8db53f891c9406e2a358 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:37 +0000 Subject: [PATCH 106/777] Merged r3950 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@4000 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- public/stylesheets/calendar.css | 84 ++++++++++++++++----------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/public/stylesheets/calendar.css b/public/stylesheets/calendar.css index c8d2dd61..288ed724 100644 --- a/public/stylesheets/calendar.css +++ b/public/stylesheets/calendar.css @@ -8,7 +8,7 @@ img.calendar-trigger { div.calendar { position: relative; z-index: 30;} -.calendar, .calendar table { +div.calendar, div.calendar table { border: 1px solid #556; font-size: 11px; color: #000; @@ -19,16 +19,16 @@ div.calendar { position: relative; z-index: 30;} /* Header part -- contains navigation buttons and day names. */ -.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ +div.calendar .button { /* "<<", "<", ">", ">>" buttons have this class */ text-align: center; /* They are the navigation buttons */ padding: 2px; /* Make the buttons seem like they're pressing */ } -.calendar .nav { +div.calendar .nav { background: #467aa7; } -.calendar thead .title { /* This holds the current "month, year" */ +div.calendar thead .title { /* This holds the current "month, year" */ font-weight: bold; /* Pressing it will take you to the current date */ text-align: center; background: #fff; @@ -36,79 +36,79 @@ div.calendar { position: relative; z-index: 30;} padding: 2px; } -.calendar thead .headrow { /* Row containing navigation buttons */ +div.calendar thead .headrow { /* Row containing navigation buttons */ background: #467aa7; color: #fff; } -.calendar thead .daynames { /* Row containing the day names */ +div.calendar thead .daynames { /* Row containing the day names */ background: #bdf; } -.calendar thead .name { /* Cells containing the day names */ +div.calendar thead .name { /* Cells containing the day names */ border-bottom: 1px solid #556; padding: 2px; text-align: center; color: #000; } -.calendar thead .weekend { /* How a weekend day name shows in header */ +div.calendar thead .weekend { /* How a weekend day name shows in header */ color: #a66; } -.calendar thead .hilite { /* How do the buttons in header appear when hover */ +div.calendar thead .hilite { /* How do the buttons in header appear when hover */ background-color: #80b0da; color: #000; padding: 1px; } -.calendar thead .active { /* Active (pressed) buttons in header */ +div.calendar thead .active { /* Active (pressed) buttons in header */ background-color: #77c; padding: 2px 0px 0px 2px; } /* The body part -- contains all the days in month. */ -.calendar tbody .day { /* Cells containing month days dates */ +div.calendar tbody .day { /* Cells containing month days dates */ width: 2em; color: #456; text-align: right; padding: 2px 4px 2px 2px; } -.calendar tbody .day.othermonth { +div.calendar tbody .day.othermonth { font-size: 80%; color: #bbb; } -.calendar tbody .day.othermonth.oweekend { +div.calendar tbody .day.othermonth.oweekend { color: #fbb; } -.calendar table .wn { +div.calendar table .wn { padding: 2px 3px 2px 2px; border-right: 1px solid #000; background: #bdf; } -.calendar tbody .rowhilite td { +div.calendar tbody .rowhilite td { background: #def; } -.calendar tbody .rowhilite td.wn { +div.calendar tbody .rowhilite td.wn { background: #80b0da; } -.calendar tbody td.hilite { /* Hovered cells */ +div.calendar tbody td.hilite { /* Hovered cells */ background: #80b0da; padding: 1px 3px 1px 1px; border: 1px solid #bbb; } -.calendar tbody td.active { /* Active (pressed) cells */ +div.calendar tbody td.active { /* Active (pressed) cells */ background: #cde; padding: 2px 2px 0px 2px; } -.calendar tbody td.selected { /* Cell showing today date */ +div.calendar tbody td.selected { /* Cell showing today date */ font-weight: bold; border: 1px solid #000; padding: 1px 3px 1px 1px; @@ -116,55 +116,55 @@ div.calendar { position: relative; z-index: 30;} color: #000; } -.calendar tbody td.weekend { /* Cells showing weekend days */ +div.calendar tbody td.weekend { /* Cells showing weekend days */ color: #a66; } -.calendar tbody td.today { /* Cell showing selected date */ +div.calendar tbody td.today { /* Cell showing selected date */ font-weight: bold; color: #f00; } -.calendar tbody .disabled { color: #999; } +div.calendar tbody .disabled { color: #999; } -.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ +div.calendar tbody .emptycell { /* Empty cells (the best is to hide them) */ visibility: hidden; } -.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ +div.calendar tbody .emptyrow { /* Empty row (some months need less than 6 rows) */ display: none; } /* The footer part -- status bar and "Close" button */ -.calendar tfoot .footrow { /* The in footer (only one right now) */ +div.calendar tfoot .footrow { /* The in footer (only one right now) */ text-align: center; background: #556; color: #fff; } -.calendar tfoot .ttip { /* Tooltip (status bar) cell */ +div.calendar tfoot .ttip { /* Tooltip (status bar) cell */ background: #fff; color: #445; border-top: 1px solid #556; padding: 1px; } -.calendar tfoot .hilite { /* Hover style for buttons in footer */ +div.calendar tfoot .hilite { /* Hover style for buttons in footer */ background: #aaf; border: 1px solid #04f; color: #000; padding: 1px; } -.calendar tfoot .active { /* Active (pressed) style for buttons in footer */ +div.calendar tfoot .active { /* Active (pressed) style for buttons in footer */ background: #77c; padding: 2px 0px 0px 2px; } /* Combo boxes (menus that display months/years for direct selection) */ -.calendar .combo { +div.calendar .combo { position: absolute; display: none; top: 0px; @@ -178,59 +178,59 @@ div.calendar { position: relative; z-index: 30;} z-index: 100; } -.calendar .combo .label, -.calendar .combo .label-IEfix { +div.calendar .combo .label, +div.calendar .combo .label-IEfix { text-align: center; padding: 1px; } -.calendar .combo .label-IEfix { +div.calendar .combo .label-IEfix { width: 4em; } -.calendar .combo .hilite { +div.calendar .combo .hilite { background: #acf; } -.calendar .combo .active { +div.calendar .combo .active { border-top: 1px solid #46a; border-bottom: 1px solid #46a; background: #eef; font-weight: bold; } -.calendar td.time { +div.calendar td.time { border-top: 1px solid #000; padding: 1px 0px; text-align: center; background-color: #f4f0e8; } -.calendar td.time .hour, -.calendar td.time .minute, -.calendar td.time .ampm { +div.calendar td.time .hour, +div.calendar td.time .minute, +div.calendar td.time .ampm { padding: 0px 3px 0px 4px; border: 1px solid #889; font-weight: bold; background-color: #fff; } -.calendar td.time .ampm { +div.calendar td.time .ampm { text-align: center; } -.calendar td.time .colon { +div.calendar td.time .colon { padding: 0px 2px 0px 3px; font-weight: bold; } -.calendar td.time span.hilite { +div.calendar td.time span.hilite { border-color: #000; background-color: #667; color: #fff; } -.calendar td.time span.active { +div.calendar td.time span.active { border-color: #f00; background-color: #000; color: #0f0; From 047bf692b36943d61fa1cfd84b95f634ea5b3953 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:42 +0000 Subject: [PATCH 107/777] Merged r3951 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@4001 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/integration/layout_test.rb | 4 +--- test/test_helper.rb | 6 ++++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/integration/layout_test.rb b/test/integration/layout_test.rb index 03d407d2..001bf50d 100644 --- a/test/integration/layout_test.rb +++ b/test/integration/layout_test.rb @@ -13,9 +13,7 @@ class LayoutTest < ActionController::IntegrationTest end test "browsing to an unauthorized page should render the base layout" do - user = User.find(9) - user.password, user.password_confirmation = 'test', 'test' - user.save! + change_user_password('miscuser9', 'test') log_user('miscuser9','test') diff --git a/test/test_helper.rb b/test/test_helper.rb index 15a1f157..dc04fa82 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -86,6 +86,12 @@ class ActiveSupport::TestCase saved_settings.each {|k, v| Setting[k] = v} end + def change_user_password(login, new_password) + user = User.first(:conditions => {:login => login}) + user.password, user.password_confirmation = new_password, new_password + user.save! + end + def self.ldap_configured? @test_ldap = Net::LDAP.new(:host => '127.0.0.1', :port => 389) return @test_ldap.bind From ccbc9f8ff963e51f81016e92e1277c224e85dd9d Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Thu, 19 Aug 2010 04:34:48 +0000 Subject: [PATCH 108/777] Merged r3952 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@4002 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/issues_helper.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index 60798fed..61782298 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -30,12 +30,14 @@ module IssuesHelper end def render_issue_tooltip(issue) + @cached_label_status ||= l(:field_status) @cached_label_start_date ||= l(:field_start_date) @cached_label_due_date ||= l(:field_due_date) @cached_label_assigned_to ||= l(:field_assigned_to) @cached_label_priority ||= l(:field_priority) link_to_issue(issue) + "

    " + + "#{@cached_label_status}: #{issue.status.name}
    " + "#{@cached_label_start_date}: #{format_date(issue.start_date)}
    " + "#{@cached_label_due_date}: #{format_date(issue.due_date)}
    " + "#{@cached_label_assigned_to}: #{issue.assigned_to}
    " + From 9e5d2100b612cc51576c689100a63187a6ae01e2 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 22 Aug 2010 19:48:26 +0000 Subject: [PATCH 109/777] Merged r4003 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@4015 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- config/locales/de.yml | 2 +- config/locales/es.yml | 44 +- config/locales/it.yml | 343 ++-- config/locales/ja.yml | 2 +- config/locales/nl.yml | 152 +- config/locales/ru.yml | 2 +- config/locales/sr-CY.yml | 907 --------- config/locales/sr-YU.yml | 907 +++++++++ config/locales/sr.yml | 1618 ++++++++--------- config/locales/sv.yml | 6 +- .../javascripts/calendar/lang/calendar-it.js | 25 +- .../calendar/lang/calendar-sr-CY.js | 127 -- .../calendar/lang/calendar-sr-yu.js | 127 ++ .../javascripts/calendar/lang/calendar-sr.js | 254 +-- .../jstoolbar/lang/jstoolbar-it.js | 5 +- .../jstoolbar/lang/jstoolbar-sr-yu.js | 16 + .../jstoolbar/lang/jstoolbar-sr.js | 32 +- 17 files changed, 2296 insertions(+), 2273 deletions(-) delete mode 100644 config/locales/sr-CY.yml create mode 100644 config/locales/sr-YU.yml delete mode 100644 public/javascripts/calendar/lang/calendar-sr-CY.js create mode 100644 public/javascripts/calendar/lang/calendar-sr-yu.js create mode 100644 public/javascripts/jstoolbar/lang/jstoolbar-sr-yu.js diff --git a/config/locales/de.yml b/config/locales/de.yml index f7f9043c..411e9e9f 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -839,7 +839,7 @@ de: version_status_locked: gesperrt version_status_closed: abgeschlossen - field_active: Activ + field_active: Aktiv text_select_mail_notifications: Bitte wählen Sie die Aktionen aus, für die eine Mailbenachrichtigung gesendet werden soll. text_regexp_info: z. B. ^[A-Z0-9]+$ diff --git a/config/locales/es.yml b/config/locales/es.yml index bc345dcb..e7abd434 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -1,7 +1,7 @@ # Spanish translations for Rails # by Francisco Fernando García Nieto (ffgarcianieto@gmail.com) # Redmine spanish translation: -# by J. Cayetano Delgado (jcdelgado _at_ ingenia.es) +# by J. Cayetano Delgado (Cayetano _dot_ Delgado _at_ ioko _dot_ com) es: number: @@ -926,25 +926,25 @@ es: Está a punto de eliminar algún o todos sus permisos y podría perder la posibilidad de modificar este proyecto tras hacerlo. ¿Está seguro de querer continuar? label_close_versions: Cerrar versiones completadas - label_board_sticky: Sticky - label_board_locked: Locked - permission_export_wiki_pages: Export wiki pages - setting_cache_formatted_text: Cache formatted text - permission_manage_project_activities: Manage project activities - error_unable_delete_issue_status: Unable to delete issue status - label_profile: Profile - permission_manage_subtasks: Manage subtasks - field_parent_issue: Parent task - label_subtask_plural: Subtasks - label_project_copy_notifications: Send email notifications during the project copy - error_can_not_delete_custom_field: Unable to delete custom field - error_unable_to_connect: Unable to connect ({{value}}) - error_can_not_remove_role: This role is in use and can not be deleted. - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + label_board_sticky: Pegajoso + label_board_locked: Bloqueado + permission_export_wiki_pages: Exportar páginas wiki + setting_cache_formatted_text: Cachear texto formateado + permission_manage_project_activities: Gestionar actividades del proyecto + error_unable_delete_issue_status: Fue imposible eliminar el estado de la petición + label_profile: Perfil + permission_manage_subtasks: Gestionar subtareas + field_parent_issue: Tarea padre + label_subtask_plural: Subtareas + label_project_copy_notifications: Enviar notificaciones por correo electrónico durante la copia del proyecto + error_can_not_delete_custom_field: Fue imposible eliminar el campo personalizado + error_unable_to_connect: Fue imposible conectar con ({{value}}) + error_can_not_remove_role: Este rol está en uso y no puede ser eliminado. + error_can_not_delete_tracker: Este tipo contiene peticiones y no puede ser eliminado. field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + label_my_page_block: Bloque Mi página + notice_failed_to_save_members: "Fallo al guardar miembro(s): {{errors}}." + text_zoom_out: Alejar + text_zoom_in: Acercar + notice_unable_delete_time_entry: Fue imposible eliminar la entrada de tiempo dedicado. + label_overall_spent_time: Tiempo total dedicado diff --git a/config/locales/it.yml b/config/locales/it.yml index bab1c6a9..aec2c8ea 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -1,5 +1,6 @@ # Italian translations for Ruby on Rails # by Claudio Poli (masterkain@gmail.com) +# by Diego Pierotto (ita.translations@tiscali.it) it: date: @@ -64,8 +65,8 @@ it: one: "oltre un anno" other: "oltre {{count}} anni" almost_x_years: - one: "almost 1 year" - other: "almost {{count}} years" + one: "quasi 1 anno" + other: "quasi {{count}} anni" number: format: @@ -91,7 +92,7 @@ it: support: array: - sentence_connector: "and" + sentence_connector: "e" skip_last_comma: false activerecord: @@ -128,9 +129,9 @@ it: actionview_instancetag_blank_option: Scegli general_text_No: 'No' - general_text_Yes: 'Si' + general_text_Yes: 'Sì' general_text_no: 'no' - general_text_yes: 'si' + general_text_yes: 'sì' general_lang_name: 'Italiano' general_csv_separator: ',' general_csv_decimal_separator: '.' @@ -138,13 +139,13 @@ it: general_pdf_encoding: ISO-8859-1 general_first_day_of_week: '1' - notice_account_updated: L'utenza è stata aggiornata. + notice_account_updated: L'utente è stata aggiornato. notice_account_invalid_creditentials: Nome utente o password non validi. notice_account_password_updated: La password è stata aggiornata. notice_account_wrong_password: Password errata - notice_account_register_done: L'utenza è stata creata. + notice_account_register_done: L'utente è stata creato. notice_account_unknown_email: Utente sconosciuto. - notice_can_t_change_password: Questa utenza utilizza un metodo di autenticazione esterno. Impossibile cambiare la password. + notice_can_t_change_password: Questo utente utilizza un metodo di autenticazione esterno. Impossibile cambiare la password. notice_account_lost_email_sent: Ti è stata spedita una email con le istruzioni per cambiare la password. notice_account_activated: Il tuo account è stato attivato. Ora puoi effettuare l'accesso. notice_successful_create: Creazione effettuata. @@ -154,17 +155,17 @@ it: notice_file_not_found: La pagina desiderata non esiste o è stata rimossa. notice_locking_conflict: Le informazioni sono state modificate da un altro utente. notice_not_authorized: Non sei autorizzato ad accedere a questa pagina. - notice_email_sent: "Una e-mail è stata spedita a {{value}}" - notice_email_error: "Si è verificato un errore durante l'invio di una e-mail ({{value}})" + notice_email_sent: "Una email è stata spedita a {{value}}" + notice_email_error: "Si è verificato un errore durante l'invio di una email ({{value}})" notice_feeds_access_key_reseted: La tua chiave di accesso RSS è stata reimpostata. error_scm_not_found: "La risorsa e/o la versione non esistono nel repository." error_scm_command_failed: "Si è verificato un errore durante l'accesso al repository: {{value}}" mail_subject_lost_password: "Password {{value}}" - mail_body_lost_password: 'Per cambiare la password, usate il seguente collegamento:' - mail_subject_register: "Attivazione utenza {{value}}" - mail_body_register: 'Per attivare la vostra utenza, usate il seguente collegamento:' + mail_body_lost_password: 'Per cambiare la password, usa il seguente collegamento:' + mail_subject_register: "Attivazione utente {{value}}" + mail_body_register: "Per attivare l'utente, usa il seguente collegamento:" gui_validation_error: 1 errore gui_validation_error_plural: "{{count}} errori" @@ -195,22 +196,22 @@ it: field_issue: Segnalazione field_status: Stato field_notes: Note - field_is_closed: Chiude la segnalazione + field_is_closed: Chiudi la segnalazione field_is_default: Stato predefinito field_tracker: Tracker field_subject: Oggetto field_due_date: Data ultima field_assigned_to: Assegnato a - field_priority: Priorita' + field_priority: Priorità field_fixed_version: Versione prevista field_user: Utente field_role: Ruolo field_homepage: Homepage field_is_public: Pubblico field_parent: Sottoprogetto di - field_is_in_roadmap: Segnalazioni mostrate nel roadmap - field_login: Login - field_mail_notification: Notifiche via e-mail + field_is_in_roadmap: Segnalazioni mostrate nella roadmap + field_login: Utente + field_mail_notification: Notifiche via email field_admin: Amministratore field_last_login_on: Ultima connessione field_language: Lingua @@ -222,17 +223,17 @@ it: field_type: Tipo field_host: Host field_port: Porta - field_account: Utenza + field_account: Utente field_base_dn: DN base - field_attr_login: Attributo login + field_attr_login: Attributo connessione field_attr_firstname: Attributo nome field_attr_lastname: Attributo cognome - field_attr_mail: Attributo e-mail - field_onthefly: Creazione utenza "al volo" + field_attr_mail: Attributo email + field_onthefly: Creazione utente "al volo" field_start_date: Inizio field_done_ratio: % completato field_auth_source: Modalità di autenticazione - field_hide_mail: Nascondi il mio indirizzo di e-mail + field_hide_mail: Nascondi il mio indirizzo email field_comments: Commento field_url: URL field_start_page: Pagina principale @@ -255,9 +256,9 @@ it: setting_default_language: Lingua predefinita setting_login_required: Autenticazione richiesta setting_self_registration: Auto-registrazione abilitata - setting_attachment_max_size: Massima dimensione allegati + setting_attachment_max_size: Dimensione massima allegati setting_issues_export_limit: Limite esportazione segnalazioni - setting_mail_from: Indirizzo sorgente e-mail + setting_mail_from: Indirizzo sorgente email setting_host_name: Nome host setting_text_formatting: Formattazione testo setting_wiki_compression: Comprimi cronologia wiki @@ -266,7 +267,7 @@ it: setting_sys_api_enabled: Abilita WS per la gestione del repository setting_commit_ref_keywords: Parole chiave riferimento setting_commit_fix_keywords: Parole chiave chiusura - setting_autologin: Login automatico + setting_autologin: Connessione automatica setting_date_format: Formato data setting_cross_project_issue_relations: Consenti la creazione di relazioni tra segnalazioni in progetti differenti @@ -277,9 +278,9 @@ it: label_project_new: Nuovo progetto label_project_plural: Progetti label_x_projects: - zero: no projects - one: 1 project - other: "{{count}} projects" + zero: nessun progetto + one: 1 progetto + other: "{{count}} progetti" label_project_all: Tutti i progetti label_project_latest: Ultimi progetti registrati label_issue: Segnalazione @@ -300,10 +301,10 @@ it: label_tracker_plural: Tracker label_tracker_new: Nuovo tracker label_workflow: Workflow - label_issue_status: Stato segnalazioni - label_issue_status_plural: Stati segnalazione + label_issue_status: Stato segnalazione + label_issue_status_plural: Stati segnalazioni label_issue_status_new: Nuovo stato - label_issue_category: Categorie segnalazioni + label_issue_category: Categoria segnalazione label_issue_category_plural: Categorie segnalazioni label_issue_category_new: Nuova categoria label_custom_field: Campo personalizzato @@ -313,16 +314,16 @@ it: label_enumeration_new: Nuovo valore label_information: Informazione label_information_plural: Informazioni - label_please_login: Autenticarsi + label_please_login: Entra label_register: Registrati label_password_lost: Password dimenticata label_home: Home label_my_page: Pagina personale - label_my_account: La mia utenza + label_my_account: Il mio utente label_my_projects: I miei progetti label_administration: Amministrazione - label_login: Login - label_logout: Logout + label_login: Entra + label_logout: Esci label_help: Aiuto label_reported_issues: Segnalazioni label_assigned_to_me_issues: Le mie segnalazioni @@ -330,7 +331,7 @@ it: label_registered_on: Registrato il label_activity: Attività label_new: Nuovo - label_logged_as: Autenticato come + label_logged_as: Collegato come label_environment: Ambiente label_authentication: Autenticazione label_auth_source: Modalità di autenticazione @@ -376,17 +377,17 @@ it: label_closed_issues: chiusa label_closed_issues_plural: chiuse label_x_open_issues_abbr_on_total: - zero: 0 open / {{total}} - one: 1 open / {{total}} - other: "{{count}} open / {{total}}" + zero: 0 aperte / {{total}} + one: 1 aperta / {{total}} + other: "{{count}} aperte / {{total}}" label_x_open_issues_abbr: - zero: 0 open - one: 1 open - other: "{{count}} open" + zero: 0 aperte + one: 1 aperta + other: "{{count}} aperte" label_x_closed_issues_abbr: - zero: 0 closed - one: 1 closed - other: "{{count}} closed" + zero: 0 chiuse + one: 1 chiusa + other: "{{count}} chiuse" label_total: Totale label_permissions: Permessi label_current_status: Stato attuale @@ -409,9 +410,9 @@ it: label_comment: Commento label_comment_plural: Commenti label_x_comments: - zero: no comments - one: 1 comment - other: "{{count}} comments" + zero: nessun commento + one: 1 commento + other: "{{count}} commenti" label_comment_add: Aggiungi un commento label_comment_added: Commento aggiunto label_comment_delete: Elimina commenti @@ -458,10 +459,10 @@ it: label_result_plural: Risultati label_all_words: Tutte le parole label_wiki: Wiki - label_wiki_edit: Modifica Wiki + label_wiki_edit: Modifica wiki label_wiki_edit_plural: Modfiche wiki label_wiki_page: Pagina Wiki - label_wiki_page_plural: Pagine Wiki + label_wiki_page_plural: Pagine wiki label_index_by_title: Ordina per titolo label_index_by_date: Ordina per data label_current_version: Versione corrente @@ -495,14 +496,14 @@ it: label_blocked_by: bloccato da label_precedes: precede label_follows: segue - label_end_to_start: end to start - label_end_to_end: end to end - label_start_to_start: start to start - label_start_to_end: start to end + label_end_to_start: fine a inizio + label_end_to_end: fine a fine + label_start_to_start: inizio a inizio + label_start_to_end: inizio a fine label_stay_logged_in: Rimani collegato label_disabled: disabilitato label_show_completed_versions: Mostra versioni completate - label_me: io + label_me: me label_board: Forum label_board_new: Nuovo forum label_board_plural: Forum @@ -519,24 +520,24 @@ it: label_date_to: A label_language_based: Basato sul linguaggio label_sort_by: "Ordina per {{value}}" - label_send_test_email: Invia una e-mail di test + label_send_test_email: Invia una email di prova label_feeds_access_key_created_on: "chiave di accesso RSS creata {{value}} fa" label_module_plural: Moduli label_added_time_by: "Aggiunto da {{author}} {{age}} fa" label_updated_time: "Aggiornato {{value}} fa" label_jump_to_a_project: Vai al progetto... - button_login: Login + button_login: Entra button_submit: Invia button_save: Salva button_check_all: Seleziona tutti button_uncheck_all: Deseleziona tutti button_delete: Elimina button_create: Crea - button_test: Test + button_test: Prova button_edit: Modifica button_add: Aggiungi - button_change: Modifica + button_change: Cambia button_apply: Applica button_clear: Pulisci button_lock: Blocca @@ -556,7 +557,7 @@ it: button_reply: Rispondi button_archive: Archivia button_unarchive: Ripristina - button_reset: Reset + button_reset: Reimposta button_rename: Rinomina status_active: attivo @@ -564,9 +565,9 @@ it: status_locked: bloccato text_select_mail_notifications: Seleziona le azioni per cui deve essere inviata una notifica. - text_regexp_info: eg. ^[A-Z0-9]+$ + text_regexp_info: es. ^[A-Z0-9]+$ text_min_max_length_info: 0 significa nessuna restrizione - text_project_destroy_confirmation: Sei sicuro di voler cancellare il progetti e tutti i dati ad esso collegati? + text_project_destroy_confirmation: Sei sicuro di voler eliminare il progetto e tutti i dati ad esso collegati? text_workflow_edit: Seleziona un ruolo ed un tracker per modificare il workflow text_are_you_sure: Sei sicuro ? text_tip_task_begin_day: attività che iniziano in questa giornata @@ -577,25 +578,25 @@ it: text_length_between: "Lunghezza compresa tra {{min}} e {{max}} caratteri." text_tracker_no_workflow: Nessun workflow definito per questo tracker text_unallowed_characters: Caratteri non permessi - text_comma_separated: Valori multipli permessi (separati da virgola). + text_comma_separated: Valori multipli permessi (separati da virgole). text_issues_ref_in_commit_messages: Segnalazioni di riferimento e chiusura nei messaggi di commit text_issue_added: "E' stata segnalata l'anomalia {{id}} da {{author}}." - text_issue_updated: "L'anomalia {{id}} e' stata aggiornata da {{author}}." - text_wiki_destroy_confirmation: Sicuro di voler cancellare questo wiki e tutti i suoi contenuti? + text_issue_updated: "L'anomalia {{id}} è stata aggiornata da {{author}}." + text_wiki_destroy_confirmation: Sicuro di voler eliminare questo wiki e tutti i suoi contenuti? text_issue_category_destroy_question: "Alcune segnalazioni ({{count}}) risultano assegnate a questa categoria. Cosa vuoi fare ?" - text_issue_category_destroy_assignments: Rimuovi gli assegnamenti a questa categoria + text_issue_category_destroy_assignments: Rimuovi le assegnazioni a questa categoria text_issue_category_reassign_to: Riassegna segnalazioni a questa categoria - default_role_manager: Manager + default_role_manager: Gestore default_role_developer: Sviluppatore - default_role_reporter: Reporter + default_role_reporter: Segnalatore default_tracker_bug: Segnalazione default_tracker_feature: Funzione default_tracker_support: Supporto default_issue_status_new: Nuovo - default_issue_status_in_progress: In Progress + default_issue_status_in_progress: In elaborazione default_issue_status_resolved: Risolto - default_issue_status_feedback: Feedback + default_issue_status_feedback: Commenti default_issue_status_closed: Chiuso default_issue_status_rejected: Rifiutato default_doc_category_user: Documentazione utente @@ -630,7 +631,7 @@ it: label_user_mail_option_selected: "Solo per gli eventi relativi ai progetti selezionati..." label_user_mail_option_all: "Per ogni evento relativo ad uno dei miei progetti" label_user_mail_option_none: "Solo per argomenti che osservo o che mi riguardano" - setting_emails_footer: Piè di pagina e-mail + setting_emails_footer: Piè di pagina email label_float: Decimale button_copy: Copia mail_body_account_information_external: "Puoi utilizzare il tuo account {{value}} per accedere al sistema." @@ -638,7 +639,7 @@ it: setting_protocol: Protocollo label_user_mail_no_self_notified: "Non voglio notifiche riguardanti modifiche da me apportate" setting_time_format: Formato ora - label_registration_activation_by_email: attivazione account via e-mail + label_registration_activation_by_email: attivazione account via email mail_subject_account_activation_request: "{{value}} richiesta attivazione account" mail_body_account_activation_request: "Un nuovo utente ({{value}}) ha effettuato la registrazione. Il suo account è in attesa di abilitazione da parte tua:" label_registration_automatic_activation: attivazione account automatica @@ -655,7 +656,7 @@ it: label_age: Età notice_default_data_loaded: Configurazione predefinita caricata con successo. text_load_default_configuration: Carica la configurazione predefinita - text_no_configuration_data: "Ruoli, tracker, stati delle segnalazioni e workflow non sono stati ancora configurati.\nIt is highly recommended to load the default configuration. You will be able to modify it once loaded." + text_no_configuration_data: "Ruoli, tracker, stati delle segnalazioni e workflow non sono stati ancora configurati.\nE' vivamente consigliato caricare la configurazione predefinita. Potrai modificarla una volta caricata." error_can_t_load_default_data: "Non è stato possibile caricare la configurazione predefinita : {{value}}" button_update: Aggiorna label_change_properties: Modifica le proprietà @@ -699,7 +700,7 @@ it: label_last_month: ultimo mese label_add_another_file: Aggiungi un altro file label_optional_description: Descrizione opzionale - text_destroy_time_entries_question: "{{hours}} ore risultano spese sulle segnalazioni che stai per cancellare. Cosa vuoi fare ?" + text_destroy_time_entries_question: "{{hours}} ore risultano spese sulle segnalazioni che stai per eliminare. Cosa vuoi fare ?" error_issue_not_found_in_project: 'La segnalazione non è stata trovata o non appartiene al progetto' text_assign_time_entries_to_project: Assegna le ore segnalate al progetto text_destroy_time_entries: Elimina le ore segnalate @@ -709,9 +710,9 @@ it: field_comments_sorting: Mostra commenti label_reverse_chronological_order: In ordine cronologico inverso label_preferences: Preferenze - setting_display_subprojects_issues: Mostra le segnalazioni dei sottoprogetti nel progetto principale per default + setting_display_subprojects_issues: Mostra le segnalazioni dei sottoprogetti nel progetto principale in modo predefinito label_overall_activity: Attività generale - setting_default_projects_public: I nuovi progetti sono pubblici per default + setting_default_projects_public: I nuovi progetti sono pubblici in modo predefinito error_scm_annotate: "L'oggetto non esiste o non può essere annotato." label_planning: Pianificazione text_subprojects_destroy_warning: "Anche i suoi sottoprogetti: {{value}} verranno eliminati." @@ -723,17 +724,17 @@ it: setting_enabled_scm: SCM abilitato text_enumeration_category_reassign_to: 'Riassegnale a questo valore:' text_enumeration_destroy_question: "{{count}} oggetti hanno un assegnamento su questo valore." - label_incoming_emails: E-mail in arrivo + label_incoming_emails: Email in arrivo label_generate_key: Genera una chiave - setting_mail_handler_api_enabled: Abilita WS per le e-mail in arrivo + setting_mail_handler_api_enabled: Abilita WS per le email in arrivo setting_mail_handler_api_key: Chiave API - text_email_delivery_not_configured: "La consegna via e-mail non è configurata e le notifiche sono disabilitate.\nConfigura il tuo server SMTP in config/email.yml e riavvia l'applicazione per abilitarle." - field_parent_title: Parent page + text_email_delivery_not_configured: "La consegna via email non è configurata e le notifiche sono disabilitate.\nConfigura il tuo server SMTP in config/email.yml e riavvia l'applicazione per abilitarle." + field_parent_title: Pagina principale label_issue_watchers: Osservatori setting_commit_logs_encoding: Codifica dei messaggi di commit button_quote: Quota setting_sequential_project_identifiers: Genera progetti con identificativi in sequenza - notice_unable_delete_version: Impossibile cancellare la versione + notice_unable_delete_version: Impossibile eliminare la versione label_renamed: rinominato label_copied: copiato setting_plain_text_mail: Solo testo (non HTML) @@ -747,7 +748,7 @@ it: permission_view_time_entries: Vedi tempi impiegati permission_manage_versions: Gestisci versioni permission_manage_wiki: Gestisci wiki - permission_manage_categories: Gestisci categorie segnalazione + permission_manage_categories: Gestisci categorie segnalazioni permission_protect_wiki_pages: Proteggi pagine wiki permission_comment_news: Commenta notizie permission_delete_messages: Elimina messaggi @@ -785,23 +786,23 @@ it: permission_edit_own_issue_notes: Modifica proprie note setting_gravatar_enabled: Usa icone utente Gravatar label_example: Esempio - text_repository_usernames_mapping: "Seleziona per aggiornare la corrispondenza tra gli utenti Redmine e quelli presenti nel log del repository.\nGli utenti Redmine e repository con lo stesso username o email sono mappati automaticamente." + text_repository_usernames_mapping: "Seleziona per aggiornare la corrispondenza tra gli utenti Redmine e quelli presenti nel log del repository.\nGli utenti Redmine e repository con lo stesso note utente o email sono mappati automaticamente." permission_edit_own_messages: Modifica propri messaggi permission_delete_own_messages: Elimina propri messaggi label_user_activity: "attività di {{value}}" label_updated_time_by: "Aggiornato da {{author}} {{age}} fa" text_diff_truncated: '... Le differenze sono state troncate perchè superano il limite massimo visualizzabile.' setting_diff_max_lines_displayed: Limite massimo di differenze (linee) mostrate - text_plugin_assets_writable: Assets directory dei plugins scrivibile + text_plugin_assets_writable: Directory attività dei plugins scrivibile warning_attachments_not_saved: "{{count}} file non possono essere salvati." button_create_and_continue: Crea e continua - text_custom_field_possible_values_info: 'Un valore per ogni linea' + text_custom_field_possible_values_info: 'Un valore per ogni riga' label_display: Mostra field_editable: Modificabile setting_repository_log_display_limit: Numero massimo di revisioni elencate nella cronologia file setting_file_max_size_displayed: Dimensione massima dei contenuti testuali visualizzati field_watcher: Osservatore - setting_openid: Accetta login e registrazione con OpenID + setting_openid: Accetta connessione e registrazione con OpenID field_identity_url: URL OpenID label_login_with_open_id_option: oppure autenticati usando OpenID field_content: Contenuto @@ -815,7 +816,7 @@ it: text_wiki_page_reassign_children: Riassegna le pagine figlie al padre di questa pagina text_wiki_page_nullify_children: Mantieni le pagine figlie come pagine radice text_wiki_page_destroy_children: Elimina le pagine figlie e tutta la discendenza - setting_password_min_length: Minima lunghezza password + setting_password_min_length: Lunghezza minima password field_group_by: Raggruppa risultati per mail_subject_wiki_content_updated: "La pagina wiki '{{page}}' è stata aggiornata" label_wiki_content_added: Aggiunta pagina al wiki @@ -825,89 +826,89 @@ it: mail_body_wiki_content_updated: La pagina '{{page}}' wiki è stata aggiornata da{{author}}. permission_add_project: Crea progetto setting_new_project_user_role_id: Ruolo assegnato agli utenti non amministratori che creano un progetto - label_view_all_revisions: View all revisions + label_view_all_revisions: Mostra tutte le revisioni label_tag: Tag label_branch: Branch - error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. - error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). - text_journal_changed: "{{label}} changed from {{old}} to {{new}}" - text_journal_set_to: "{{label}} set to {{value}}" - text_journal_deleted: "{{label}} deleted ({{old}})" - label_group_plural: Groups - label_group: Group - label_group_new: New group - label_time_entry_plural: Spent time - text_journal_added: "{{label}} {{value}} added" - field_active: Active - enumeration_system_activity: System Activity - permission_delete_issue_watchers: Delete watchers - version_status_closed: closed - version_status_locked: locked - version_status_open: open - error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened - label_user_anonymous: Anonymous - button_move_and_follow: Move and follow - setting_default_projects_modules: Default enabled modules for new projects - setting_gravatar_default: Default Gravatar image - field_sharing: Sharing - label_version_sharing_hierarchy: With project hierarchy - label_version_sharing_system: With all projects - label_version_sharing_descendants: With subprojects - label_version_sharing_tree: With project tree - label_version_sharing_none: Not shared - error_can_not_archive_project: This project can not be archived - button_duplicate: Duplicate - button_copy_and_follow: Copy and follow - label_copy_source: Source - setting_issue_done_ratio: Calculate the issue done ratio with - setting_issue_done_ratio_issue_status: Use the issue status - error_issue_done_ratios_not_updated: Issue done ratios not updated. - error_workflow_copy_target: Please select target tracker(s) and role(s) - setting_issue_done_ratio_issue_field: Use the issue field - label_copy_same_as_target: Same as target - label_copy_target: Target - notice_issue_done_ratios_updated: Issue done ratios updated. - error_workflow_copy_source: Please select a source tracker or role - label_update_issue_done_ratios: Update issue done ratios - setting_start_of_week: Start calendars on - permission_view_issues: View Issues - label_display_used_statuses_only: Only display statuses that are used by this tracker - label_revision_id: Revision {{value}} - label_api_access_key: API access key - label_api_access_key_created_on: API access key created {{value}} ago - label_feeds_access_key: RSS access key - notice_api_access_key_reseted: Your API access key was reset. - setting_rest_api_enabled: Enable REST web service - label_missing_api_access_key: Missing an API access key - label_missing_feeds_access_key: Missing a RSS access key - button_show: Show - text_line_separated: Multiple values allowed (one line for each value). - setting_mail_handler_body_delimiters: Truncate emails after one of these lines - permission_add_subprojects: Create subprojects - label_subproject_new: New subproject + error_no_tracker_in_project: Nessun tracker è associato a questo progetto. Per favore verifica le impostazioni del Progetto. + error_no_default_issue_status: Nessuno stato predefinito delle segnalazioni è configurato. Per favore verifica le impostazioni (Vai in "Amministrazione -> Stati segnalazioni"). + text_journal_changed: "{{label}} modificata da {{old}} a {{new}}" + text_journal_set_to: "{{label}} impostata a {{value}}" + text_journal_deleted: "{{label}} eliminata ({{old}})" + label_group_plural: Gruppi + label_group: Gruppo + label_group_new: Nuovo gruppo + label_time_entry_plural: Tempo impiegato + text_journal_added: "{{value}} {{label}} aggiunto" + field_active: Attivo + enumeration_system_activity: Attività di sistema + permission_delete_issue_watchers: Elimina osservatori + version_status_closed: chiusa + version_status_locked: bloccata + version_status_open: aperta + error_can_not_reopen_issue_on_closed_version: Una segnalazione assegnata ad una versione chiusa non può essere riaperta + label_user_anonymous: Anonimo + button_move_and_follow: Sposta e segui + setting_default_projects_modules: Moduli predefiniti abilitati per i nuovi progetti + setting_gravatar_default: Immagine Gravatar predefinita + field_sharing: Condivisione + label_version_sharing_hierarchy: Con gerarchia progetto + label_version_sharing_system: Con tutti i progetti + label_version_sharing_descendants: Con sottoprogetti + label_version_sharing_tree: Con progetto padre + label_version_sharing_none: Nessuna condivisione + error_can_not_archive_project: Questo progetto non può essere archiviato + button_duplicate: Duplica + button_copy_and_follow: Copia e segui + label_copy_source: Sorgente + setting_issue_done_ratio: Calcola la percentuale di segnalazioni completate con + setting_issue_done_ratio_issue_status: Usa lo stato segnalazioni + error_issue_done_ratios_not_updated: La percentuale delle segnalazioni completate non è aggiornata. + error_workflow_copy_target: Per favore seleziona trackers finali e ruolo(i) + setting_issue_done_ratio_issue_field: Usa il campo segnalazioni + label_copy_same_as_target: Uguale a destinazione + label_copy_target: Destinazione + notice_issue_done_ratios_updated: La percentuale delle segnalazioni completate è aggiornata. + error_workflow_copy_source: Per favore seleziona un tracker sorgente o ruolo + label_update_issue_done_ratios: Aggiorna la percentuale delle segnalazioni completate + setting_start_of_week: Avvia calendari il + permission_view_issues: Mostra segnalazioni + label_display_used_statuses_only: Mostra solo stati che vengono usati per questo tracker + label_revision_id: Revisione {{value}} + label_api_access_key: Chiave di accesso API + label_api_access_key_created_on: Chiave di accesso API creata {{value}} fa + label_feeds_access_key: Chiave di accesso RSS + notice_api_access_key_reseted: La chiave di accesso API è stata reimpostata. + setting_rest_api_enabled: Abilita il servizio web REST + label_missing_api_access_key: Chiave di accesso API mancante + label_missing_feeds_access_key: Chiave di accesso RSS mancante + button_show: Mostra + text_line_separated: Valori multipli permessi (un valore per ogni riga). + setting_mail_handler_body_delimiters: Tronca email dopo una di queste righe + permission_add_subprojects: Crea sottoprogetti + label_subproject_new: Nuovo sottoprogetto text_own_membership_delete_confirmation: |- - You are about to remove some or all of your permissions and may no longer be able to edit this project after that. - Are you sure you want to continue? - label_close_versions: Close completed versions - label_board_sticky: Sticky - label_board_locked: Locked - permission_export_wiki_pages: Export wiki pages - setting_cache_formatted_text: Cache formatted text - permission_manage_project_activities: Manage project activities - error_unable_delete_issue_status: Unable to delete issue status - label_profile: Profile - permission_manage_subtasks: Manage subtasks - field_parent_issue: Parent task - label_subtask_plural: Subtasks - label_project_copy_notifications: Send email notifications during the project copy - error_can_not_delete_custom_field: Unable to delete custom field - error_unable_to_connect: Unable to connect ({{value}}) - error_can_not_remove_role: This role is in use and can not be deleted. - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. - field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + Stai per eliminare alcuni o tutti i permessi e non sarai più in grado di modificare questo progetto dopo tale azione. + Sei sicuro di voler continuare? + label_close_versions: Versioni completate chiuse + label_board_sticky: Annunci + label_board_locked: Bloccato + permission_export_wiki_pages: Esporta pagine wiki + setting_cache_formatted_text: Cache testo formattato + permission_manage_project_activities: Gestisci attività progetti + error_unable_delete_issue_status: Impossibile eliminare lo stato segnalazioni + label_profile: Profilo + permission_manage_subtasks: Gestisci sottoattività + field_parent_issue: Attività principale + label_subtask_plural: Sottoattività + label_project_copy_notifications: Invia notifiche email durante la copia del progetto + error_can_not_delete_custom_field: Impossibile eliminare il campo personalizzato + error_unable_to_connect: Impossibile connettersi ({{value}}) + error_can_not_remove_role: Questo ruolo è in uso e non può essere eliminato. + error_can_not_delete_tracker: Questo tracker contiene segnalazioni e non può essere eliminato. + field_principal: Principale + label_my_page_block: La mia pagina di blocco + notice_failed_to_save_members: "Impossibile salvare il membro(i): {{errors}}." + text_zoom_out: Riduci ingrandimento + text_zoom_in: Aumenta ingrandimento + notice_unable_delete_time_entry: Impossibile eliminare il valore time log. + label_overall_spent_time: Totale tempo impiegato diff --git a/config/locales/ja.yml b/config/locales/ja.yml index c82155b8..4c513fef 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -214,7 +214,7 @@ ja: mail_body_account_information: アカウント情報 mail_subject_account_activation_request: "{{value}} アカウントの承認要求" mail_body_account_activation_request: "新しいユーザ {{value}} が登録されました。このアカウントはあなたの承認待ちです:" - mail_subject_reminder: "{{count}}件のチケットが{{days}}期日間近です" + mail_subject_reminder: "{{count}}件のチケットの期日が{{days}}日以内に到来します" mail_body_reminder: "{{count}}件の担当チケットの期日が{{days}}日以内に到来します:" mail_subject_wiki_content_added: "Wikiページ {{page}} が追加されました" mail_body_wiki_content_added: "{{author}} によってWikiページ {{page}} が追加されました。" diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 4472a19d..f2e0529e 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -571,7 +571,7 @@ nl: label_used_by: Gebruikt door label_user: Gebruiker label_user_activity: "{{value}}'s activiteit" - label_user_mail_no_self_notified: "Ik wil niet verwittigd worden van wijzigingen die ik zelf maak." + label_user_mail_no_self_notified: "Ik wil niet op de hoogte gehouden worden van wijzigingen die ik zelf maak." label_user_mail_option_all: "Bij elk gebeurtenis in al mijn projecten..." label_user_mail_option_none: "Alleen in de dingen die ik monitor of in betrokken ben" label_user_mail_option_selected: "Enkel bij elke gebeurtenis op het geselecteerde project..." @@ -791,98 +791,98 @@ nl: text_wiki_page_nullify_children: Behoud subpagina's als hoofdpagina's text_wiki_page_destroy_children: Verwijder alle subpagina's en onderliggende pagina's setting_password_min_length: Minimum wachtwoord lengte - field_group_by: Group results by - mail_subject_wiki_content_updated: "'{{page}}' wiki page has been updated" - label_wiki_content_added: Wiki page added - mail_subject_wiki_content_added: "'{{page}}' wiki page has been added" - mail_body_wiki_content_added: The '{{page}}' wiki page has been added by {{author}}. - label_wiki_content_updated: Wiki page updated - mail_body_wiki_content_updated: The '{{page}}' wiki page has been updated by {{author}}. - permission_add_project: Create project - setting_new_project_user_role_id: Role given to a non-admin user who creates a project - label_view_all_revisions: View all revisions + field_group_by: Groepeer resultaten per + mail_subject_wiki_content_updated: "'{{page}}' wiki pagina is bijgewerkt" + label_wiki_content_added: Wiki pagina toegevoegd + mail_subject_wiki_content_added: "'{{page}}' wiki pagina is toegevoegd" + mail_body_wiki_content_added: The '{{page}}' wiki pagina is toegevoegd door {{author}}. + label_wiki_content_updated: Wiki pagina bijgewerkt + mail_body_wiki_content_updated: The '{{page}}' wiki pagina is bijgewerkt door {{author}}. + permission_add_project: Maak project + setting_new_project_user_role_id: Rol van gebruiker die een project maakt + label_view_all_revisions: Bekijk alle revisies label_tag: Tag label_branch: Branch - error_no_tracker_in_project: No tracker is associated to this project. Please check the Project settings. - error_no_default_issue_status: No default issue status is defined. Please check your configuration (Go to "Administration -> Issue statuses"). - text_journal_changed: "{{label}} changed from {{old}} to {{new}}" - text_journal_set_to: "{{label}} set to {{value}}" - text_journal_deleted: "{{label}} deleted ({{old}})" - label_group_plural: Groups - label_group: Group - label_group_new: New group - label_time_entry_plural: Spent time - text_journal_added: "{{label}} {{value}} added" - field_active: Active - enumeration_system_activity: System Activity - permission_delete_issue_watchers: Delete watchers - version_status_closed: closed - version_status_locked: locked + error_no_tracker_in_project: Geen tracker is geassocieerd met dit project. Check de project instellingen. + error_no_default_issue_status: Geen standaard issue status ingesteld. Check de configuratie (Ga naar "Administratie -> Issue statussen"). + text_journal_changed: "{{label}} gewijzigd van {{old}} naar {{new}}" + text_journal_set_to: "{{label}} gewijzigd naar {{value}}" + text_journal_deleted: "{{label}} verwijderd ({{old}})" + label_group_plural: Groepen + label_group: Groep + label_group_new: Nieuwe groep + label_time_entry_plural: Bestede tijd + text_journal_added: "{{label}} {{value}} toegevoegd" + field_active: Actief + enumeration_system_activity: Systeem Activiteit + permission_delete_issue_watchers: Verwijder volgers + version_status_closed: gesloten + version_status_locked: vergrendeld version_status_open: open error_can_not_reopen_issue_on_closed_version: An issue assigned to a closed version can not be reopened - label_user_anonymous: Anonymous - button_move_and_follow: Move and follow - setting_default_projects_modules: Default enabled modules for new projects - setting_gravatar_default: Default Gravatar image - field_sharing: Sharing - label_version_sharing_hierarchy: With project hierarchy - label_version_sharing_system: With all projects - label_version_sharing_descendants: With subprojects + label_user_anonymous: Anoniem + button_move_and_follow: Verplaats en volg + setting_default_projects_modules: Standaard geactiveerde modules voor nieuwe projecten + setting_gravatar_default: Standaard Gravatar plaatje + field_sharing: Delen + label_version_sharing_hierarchy: Met project hiërarchie + label_version_sharing_system: Met alle projecten + label_version_sharing_descendants: Met subprojecten label_version_sharing_tree: With project tree - label_version_sharing_none: Not shared - error_can_not_archive_project: This project can not be archived - button_duplicate: Duplicate - button_copy_and_follow: Copy and follow - label_copy_source: Source - setting_issue_done_ratio: Calculate the issue done ratio with - setting_issue_done_ratio_issue_status: Use the issue status - error_issue_done_ratios_not_updated: Issue done ratios not updated. - error_workflow_copy_target: Please select target tracker(s) and role(s) - setting_issue_done_ratio_issue_field: Use the issue field - label_copy_same_as_target: Same as target - label_copy_target: Target + label_version_sharing_none: Niet gedeeld + error_can_not_archive_project: Dit project kan niet worden gearchiveerd + button_duplicate: Dupliceer + button_copy_and_follow: Kopiëer en volg + label_copy_source: Bron + setting_issue_done_ratio: Bereken issue done ratio met + setting_issue_done_ratio_issue_status: Gebruik de issue status + error_issue_done_ratios_not_updated: Issue done ratios niet geupdate. + error_workflow_copy_target: Selecteer tracker(s) en rol(len) + setting_issue_done_ratio_issue_field: Gebruik het issue veld + label_copy_same_as_target: Zelfde als doel + label_copy_target: Doel notice_issue_done_ratios_updated: Issue done ratios updated. - error_workflow_copy_source: Please select a source tracker or role + error_workflow_copy_source: Selecteer een bron tracker of rol label_update_issue_done_ratios: Update issue done ratios - setting_start_of_week: Start calendars on - permission_view_issues: View Issues - label_display_used_statuses_only: Only display statuses that are used by this tracker + setting_start_of_week: Week begint op + permission_view_issues: Bekijk Issues + label_display_used_statuses_only: Laat alleen statussen zien die gebruikt worden door deze tracker label_revision_id: Revision {{value}} label_api_access_key: API access key - label_api_access_key_created_on: API access key created {{value}} ago + label_api_access_key_created_on: API access key gemaakt {{value}} geleden label_feeds_access_key: RSS access key - notice_api_access_key_reseted: Your API access key was reset. + notice_api_access_key_reseted: Uw API access key was gereset. setting_rest_api_enabled: Enable REST web service - label_missing_api_access_key: Missing an API access key - label_missing_feeds_access_key: Missing a RSS access key - button_show: Show - text_line_separated: Multiple values allowed (one line for each value). + label_missing_api_access_key: Geen API access key + label_missing_feeds_access_key: Geen RSS access key + button_show: Laat zien + text_line_separated: Meerdere waarden toegestaan (elke regel is een waarde). setting_mail_handler_body_delimiters: Truncate emails after one of these lines - permission_add_subprojects: Create subprojects - label_subproject_new: New subproject + permission_add_subprojects: Maak subprojecten + label_subproject_new: Nieuw subproject text_own_membership_delete_confirmation: |- - You are about to remove some or all of your permissions and may no longer be able to edit this project after that. - Are you sure you want to continue? - label_close_versions: Close completed versions + U staat op punt om sommige of alle van uw permissies te verwijderen en bent mogelijk niet meer toegestaan om dit project hierna te wijzigen. + Wilt u doorgaan? + label_close_versions: Sluit complete versies label_board_sticky: Sticky - label_board_locked: Locked - permission_export_wiki_pages: Export wiki pages - setting_cache_formatted_text: Cache formatted text + label_board_locked: Vergrendeld + permission_export_wiki_pages: Exporteer wiki pagina's + setting_cache_formatted_text: Cache opgemaakte tekst permission_manage_project_activities: Manage project activities - error_unable_delete_issue_status: Unable to delete issue status - label_profile: Profile + error_unable_delete_issue_status: Verwijderen van issue status niet gelukt + label_profile: Profiel permission_manage_subtasks: Manage subtasks field_parent_issue: Parent task label_subtask_plural: Subtasks - label_project_copy_notifications: Send email notifications during the project copy - error_can_not_delete_custom_field: Unable to delete custom field - error_unable_to_connect: Unable to connect ({{value}}) - error_can_not_remove_role: This role is in use and can not be deleted. - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. + label_project_copy_notifications: Stuur email notificaties voor de project kopie + error_can_not_delete_custom_field: Verwijderen niet mogelijk van custom field + error_unable_to_connect: Geen connectie ({{value}}) + error_can_not_remove_role: Deze rol is in gebruik en kan niet worden verwijderd. + error_can_not_delete_tracker: Deze tracker bevat nog issues en kan niet worden verwijderd. field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out + label_my_page_block: Mijn pagina block + notice_failed_to_save_members: "Niet gelukt om lid/leden op te slaan: {{errors}}." + text_zoom_out: Zoom uit text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + notice_unable_delete_time_entry: Verwijderen niet mogelijk van tijd log invoer. + label_overall_spent_time: Totaal bestede tijd diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 064cbc28..4812e2ad 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -755,7 +755,7 @@ ru: mail_subject_account_activation_request: "Запрос на активацию пользователя в системе {{value}}" mail_subject_lost_password: "Ваш {{value}} пароль" mail_subject_register: "Активация учетной записи {{value}}" - mail_subject_reminder: "{{count}} назначенных на Вас задач в ближайшие {{days}} дни" + mail_subject_reminder: "{{count}} назначенных на Вас задач в ближайшие {{days}} дней" notice_account_activated: Ваша учетная запись активирована. Вы можете войти. notice_account_invalid_creditentials: Неправильное имя пользователя или пароль diff --git a/config/locales/sr-CY.yml b/config/locales/sr-CY.yml deleted file mode 100644 index 39cc5dcb..00000000 --- a/config/locales/sr-CY.yml +++ /dev/null @@ -1,907 +0,0 @@ -# Serbian translations for Redmine -# by Vladimir Medarović (vlada@medarovic.com) -sr-CY: - date: - formats: - # Use the strftime parameters for formats. - # When no format has been given, it uses default. - # You can provide other formats here if you like! - default: "%d.%m.%Y." - short: "%e %b" - long: "%B %e, %Y" - - day_names: [Недеља, Понедељак, Уторак, Среда, Четвртак, Петак, Субота] - abbr_day_names: [Нед, Пон, Уто, Сре, Чет, Пет, Суб] - - # Don't forget the nil at the beginning; there's no such thing as a 0th month - month_names: [~, Јануар, Фебруар, Март, Април, Мај, Јун, Јул, Август, Септембар, Октобар, Новембар, Децембар] - abbr_month_names: [~, Јан, Феб, Мар, Апр, Мај, Јун, Јул, Авг, Сеп, Окт, Нов, Дец] - # Used in date_select and datime_select. - order: [ :day, :month, :year ] - - time: - formats: - default: "%d.%m.%Y. у %H:%M" - time: "%H:%M" - short: "%d. %b у %H:%M" - long: "%d. %B %Y у %H:%M" - am: "am" - pm: "pm" - - datetime: - distance_in_words: - half_a_minute: "пола минута" - less_than_x_seconds: - one: "мање од једне секунде" - other: "мање од {{count}} сек." - x_seconds: - one: "једна секунда" - other: "{{count}} сек." - less_than_x_minutes: - one: "мање од минута" - other: "мање од {{count}} мин." - x_minutes: - one: "један минут" - other: "{{count}} мин." - about_x_hours: - one: "приближно један сат" - other: "приближно {{count}} сати" - x_days: - one: "један дан" - other: "{{count}} дана" - about_x_months: - one: "приближно један месец" - other: "приближно {{count}} месеци" - x_months: - one: "један месец" - other: "{{count}} месеци" - about_x_years: - one: "приближно годину дана" - other: "приближно {{count}} год." - over_x_years: - one: "преко годину дана" - other: "преко {{count}} год." - almost_x_years: - one: "скоро годину дана" - other: "скоро {{count}} год." - - number: - human: - format: - delimiter: "" - precision: 1 - storage_units: - format: "%n %u" - units: - byte: - one: "Byte" - other: "Bytes" - kb: "KB" - mb: "MB" - gb: "GB" - tb: "TB" - - -# Used in array.to_sentence. - support: - array: - sentence_connector: "и" - skip_last_comma: false - - activerecord: - errors: - messages: - inclusion: "није укључен у списак" - exclusion: "је резервисан" - invalid: "је неисправан" - confirmation: "потврда не одговара" - accepted: "мора бити прихваћен" - empty: "не може бити празно" - blank: "не може бити празно" - too_long: "је предугачка (максимум знакова је {{count}})" - too_short: "је прекратка (минимум знакова је {{count}})" - wrong_length: "је погрешне дужине (број знакова мора бити {{count}})" - taken: "је већ у употреби" - not_a_number: "није број" - not_a_date: "није исправан датум" - greater_than: "мора бити већи од {{count}}" - greater_than_or_equal_to: "мора бити већи или једнак {{count}}" - equal_to: "мора бити једнак {{count}}" - less_than: "мора бити мањи од {{count}}" - less_than_or_equal_to: "мора бити мањи или једнак {{count}}" - odd: "мора бити паран" - even: "мора бити непаран" - greater_than_start_date: "мора бити већи од почетног датума" - not_same_project: "не припада истом пројекту" - circular_dependency: "Ова веза ће створити кружну референцу" - - actionview_instancetag_blank_option: Молим одаберите - - general_text_No: 'Не' - general_text_Yes: 'Да' - general_text_no: 'не' - general_text_yes: 'да' - general_lang_name: 'Српски' - general_csv_separator: ',' - general_csv_decimal_separator: '.' - general_csv_encoding: UTF-8 - general_pdf_encoding: UTF-8 - general_first_day_of_week: '1' - - notice_account_updated: Налог је успешно ажуриран. - notice_account_invalid_creditentials: Неисправно корисничко име или лозинка. - notice_account_password_updated: Лозинка је успешно ажурирана. - notice_account_wrong_password: Погрешна лозинка - notice_account_register_done: Кориснички налог је успешно креиран. Кликните на линк који сте добили у емаил поруци за активацију. - notice_account_unknown_email: Непознат корисник. - notice_can_t_change_password: Овај кориснички налог за проверу идентитета користи спољни извор. Немогуће је променити лозинку. - notice_account_lost_email_sent: Послата вам је емаил порука са упутством за избор нове лозинке - notice_account_activated: Ваш кориснички налог је активиран. Сада се можете пријавити. - notice_successful_create: Успешно креирање. - notice_successful_update: Успешно ажурирање. - notice_successful_delete: Успешно брисање. - notice_successful_connection: Успешно повезивање. - notice_file_not_found: Страна којој желите приступити не постоји или је уклоњена. - notice_locking_conflict: Податак је ажуриран од стране другог корисника. - notice_not_authorized: Нисте овлашћени за приступ овој страни. - notice_email_sent: "Порука је послата на адресу {{value}}" - notice_email_error: "Догодила се грешка приликом слања поруке ({{value}})" - notice_feeds_access_key_reseted: Ваш RSS приступни кључ је поништен. - notice_api_access_key_reseted: Ваш API приступни кључ је поништен. - notice_failed_to_save_issues: "Неуспешно снимање {{count}} проблема од {{total}} одабраних: {{ids}}." - notice_no_issue_selected: "Ни један проблем није одабран! Молим, одаберите проблем који желите да мењате." - notice_account_pending: "Ваш налог је креиран и чека на одобрење администратора." - notice_default_data_loaded: Подразумевано конфигурисање је успешно учитано. - notice_unable_delete_version: Немогуће је обрисати верзију. - notice_issue_done_ratios_updated: Однос решених проблема је ажуриран. - - error_can_t_load_default_data: "Подразумевано конфигурисање је немогуће учитати: {{value}}" - error_scm_not_found: "Ставка или исправка нису пронађене у спремишту." - error_scm_command_failed: "Грешка се јавила приликом покушаја приступа спремишту: {{value}}" - error_scm_annotate: "Ставка не постоји или не може бити означена." - error_issue_not_found_in_project: 'Проблем није пронађен или не припада овом пројекту.' - error_no_tracker_in_project: 'Ни један трагач није повезан са овим пројектом. Молимо проверите подешавања пројекта.' - error_no_default_issue_status: 'Подразумевани статус проблема није дефинисан. Молимо проверите ваше конфигурисање (Идите на "Администрација -> Статуси проблема").' - error_can_not_reopen_issue_on_closed_version: 'Проблем додељен затвореној верзији не може бити поново отворен' - error_can_not_archive_project: Овај пројекат се не може архивирати - error_issue_done_ratios_not_updated: "Однос решених проблема није ажуриран." - error_workflow_copy_source: 'Молимо одаберите изворног трагача или улогу' - error_workflow_copy_target: 'Молимо одаберите крајњег трагача и улогу' - - warning_attachments_not_saved: "{{count}} датотека не може бити снимљено." - - mail_subject_lost_password: "Ваша {{value}} лозинка" - mail_body_lost_password: 'За промену ваше лозинке, кликните на следећи линк:' - mail_subject_register: "Активација вашег {{value}} налога" - mail_body_register: 'За активацију вашег налога, кликните на следећи линк:' - mail_body_account_information_external: "Можете користити ваш налог {{value}} за пријаву." - mail_body_account_information: Информације о вашем налогу - mail_subject_account_activation_request: "Захтев за активацију налога {{value}}" - mail_body_account_activation_request: "Нови корисник ({{value}}) је регистрован. Налог чека на ваше одобрење:" - mail_subject_reminder: "{{count}} проблема доспева наредних {{days}} дана" - mail_body_reminder: "{{count}} проблема додељених вама доспева у наредних {{days}} дана:" - mail_subject_wiki_content_added: "'{{page}}' wiki страна је додато" - mail_body_wiki_content_added: "{{author}} је додао '{{page}}' wiki страна." - mail_subject_wiki_content_updated: "'{{page}}' wiki страна је ажурирано" - mail_body_wiki_content_updated: "{{author}} је ажурирао '{{page}}' wiki страна." - - gui_validation_error: једна грешка - gui_validation_error_plural: "{{count}} грешака" - - field_name: Назив - field_description: Опис - field_summary: Резиме - field_is_required: Обавезно - field_firstname: Име - field_lastname: Презиме - field_mail: Емаил адреса - field_filename: Датотека - field_filesize: Величина - field_downloads: Преузимања - field_author: Аутор - field_created_on: Креирано - field_updated_on: Ажурирано - field_field_format: Формат - field_is_for_all: За све пројекте - field_possible_values: Могуће вредности - field_regexp: Регуларан израз - field_min_length: Минимална дужина - field_max_length: Максимална дужина - field_value: Вредност - field_category: Категорија - field_title: Наслов - field_project: Пројекат - field_issue: Проблем - field_status: Статус - field_notes: Белешке - field_is_closed: Затворен проблем - field_is_default: Подразумевана вредност - field_tracker: Трагач - field_subject: Предмет - field_due_date: Крајњи рок - field_assigned_to: Додељено - field_priority: Приоритет - field_fixed_version: Одредишна верзија - field_user: Корисник - field_role: Улога - field_homepage: Почетна страна - field_is_public: Јавно - field_parent: Потпројекат од - field_is_in_roadmap: Проблеми приказани у плану рада - field_login: Корисничко име - field_mail_notification: Емаил обавештења - field_admin: Администратор - field_last_login_on: Последње повезивање - field_language: Језик - field_effective_date: Датум - field_password: Лозинка - field_new_password: Нова лозинка - field_password_confirmation: Потврда лозинке - field_version: Верзија - field_type: Тип - field_host: Главни рачунар - field_port: Прикључак - field_account: Кориснички налог - field_base_dn: Базни DN - field_attr_login: Атрибут пријављивања - field_attr_firstname: Атрибут имена - field_attr_lastname: Атрибут презимена - field_attr_mail: Атрибут емаил адресе - field_onthefly: Креирање корисника у току рада - field_start_date: Почетак - field_done_ratio: % урађено - field_auth_source: Режим провере идентитета - field_hide_mail: Сакриј моју емаил адресу - field_comments: Коментар - field_url: URL - field_start_page: Почетна страна - field_subproject: Потпројекат - field_hours: сати - field_activity: Активност - field_spent_on: Датум - field_identifier: Идентификатор - field_is_filter: Употреби као филтер - field_issue_to: Повезани проблеми - field_delay: Кашњење - field_assignable: Проблем може бити додељен овој улози - field_redirect_existing_links: Преусмери постојеће везе - field_estimated_hours: Протекло време - field_column_names: Колоне - field_time_zone: Временска зона - field_searchable: Претражива - field_default_value: Подразумевана вредност - field_comments_sorting: Прикажи коментаре - field_parent_title: Матична страна - field_editable: Измељиво - field_watcher: Посматрач - field_identity_url: OpenID URL - field_content: Садржај - field_group_by: Групиши резултате по - field_sharing: Дељење - - setting_app_title: Наслов апликације - setting_app_subtitle: Поднаслов апликације - setting_welcome_text: Текст добродошлице - setting_default_language: Подразумевани језик - setting_login_required: Обавезна провера идентитета - setting_self_registration: Саморегистрација - setting_attachment_max_size: Макс. величина приложене датотеке - setting_issues_export_limit: Ограничење извоза проблема - setting_mail_from: Емаил адреса емисије - setting_bcc_recipients: Примаоци невидљиве копије поруке (bcc) - setting_plain_text_mail: Порука са чистим текстом (без HTML-а) - setting_host_name: Путања и назив главног рачунара - setting_text_formatting: Обликовање текста - setting_wiki_compression: Компресија Wiki историје - setting_feeds_limit: Ограничење садржаја извора вести - setting_default_projects_public: Нови пројекти су јавни ако се другачије не наведе - setting_autofetch_changesets: Извршавање аутоматског преузимања - setting_sys_api_enabled: Омогући WS за управљање спремиштем - setting_commit_ref_keywords: Референцирање кључних речи - setting_commit_fix_keywords: Поправљање кључних речи - setting_autologin: Аутоматска пријава - setting_date_format: Формат датума - setting_time_format: Формат времена - setting_cross_project_issue_relations: Дозволи релације проблема из унакрсних пројеката - setting_issue_list_default_columns: Подразумеване колоне приказане на списку проблема - setting_repositories_encodings: Кодирање спремишта - setting_commit_logs_encoding: Кодирање извршних порука - setting_emails_footer: Подножје емаил поруке - setting_protocol: Протокол - setting_per_page_options: Опције приказа објеката по страни - setting_user_format: Формат приказа корисника - setting_activity_days_default: Број дана приказаних на пројектној активности - setting_display_subprojects_issues: Приказуј проблеме из потпројеката на главном пројекту уколико није другачије наведено - setting_enabled_scm: Омогући SCM - setting_mail_handler_body_delimiters: "Скрати поруку након једне од ових линија" - setting_mail_handler_api_enabled: Омогући WS долазне поруке - setting_mail_handler_api_key: API кључ - setting_sequential_project_identifiers: Генерисање секвенцијалног имена пројекта - setting_gravatar_enabled: Користи Gravatar корисничке иконе - setting_gravatar_default: Подразумевана Gravatar слика - setting_diff_max_lines_displayed: Макс. број приказаних различитих линија - setting_file_max_size_displayed: Макс. величина текстуалних датотека приказаних унутра - setting_repository_log_display_limit: Макс. број ревизија приказан у датотеци за евиденцију - setting_openid: Дозволи OpenID пријаву и регистрацију - setting_password_min_length: Минимална дужина лозинке - setting_new_project_user_role_id: Улога додељена кориснику (који није администратор), креатору пројекта - setting_default_projects_modules: Подразумевано омогућени модули за нове пројекте - setting_issue_done_ratio: Израчунај однос решених проблема - setting_issue_done_ratio_issue_field: користећи поље проблема - setting_issue_done_ratio_issue_status: користећи статус проблема - setting_start_of_week: Први дан у седмици - setting_rest_api_enabled: Омогући REST web услуге - setting_cache_formatted_text: Кеширај обрађен текст - - permission_add_project: Креирање пројекта - permission_add_subprojects: Креирање потпојекта - permission_edit_project: Измена пројеката - permission_select_project_modules: Одабирање модула пројекта - permission_manage_members: Управљање члановима - permission_manage_project_activities: Управљање пројектним активностима - permission_manage_versions: Управљање верзијама - permission_manage_categories: Управљање категоријама проблема - permission_view_issues: Преглед проблема - permission_add_issues: Додавање проблема - permission_edit_issues: Измена проблема - permission_manage_issue_relations: Управљање релацијама између проблема - permission_add_issue_notes: Додавање белешки - permission_edit_issue_notes: Измена белешки - permission_edit_own_issue_notes: Измена сопствених белешки - permission_move_issues: Померање проблема - permission_delete_issues: Брисање проблема - permission_manage_public_queries: Управљање јавним упитима - permission_save_queries: Снимање упита - permission_view_gantt: Прегледање Гантовог дијаграма - permission_view_calendar: Прегледање календара - permission_view_issue_watchers: Прегледање списка посматрача - permission_add_issue_watchers: Додавање посматрача - permission_delete_issue_watchers: Брисање посматрача - permission_log_time: Бележење утрошеног времена - permission_view_time_entries: Прегледање утрошеног времена - permission_edit_time_entries: Измена утрошеног времена - permission_edit_own_time_entries: Измена сопственог утрошеног времена - permission_manage_news: Управљање вестима - permission_comment_news: Коментарисање вести - permission_manage_documents: Управљање документима - permission_view_documents: Прегледање докумената - permission_manage_files: Управљање датотекама - permission_view_files: Прегледање датотека - permission_manage_wiki: Управљање wiki странама - permission_rename_wiki_pages: Промена имена wiki странама - permission_delete_wiki_pages: Брисање wiki страна - permission_view_wiki_pages: Прегледање wiki страна - permission_view_wiki_edits: Прегледање wiki историје - permission_edit_wiki_pages: Измена wiki страна - permission_delete_wiki_pages_attachments: Брисање приложених датотека - permission_protect_wiki_pages: Заштита wiki страна - permission_manage_repository: Управљање спремиштем - permission_browse_repository: Прегледање спремишта - permission_view_changesets: Прегледање скупа промена - permission_commit_access: Потврда приступа - permission_manage_boards: Управљање форумима - permission_view_messages: Прегледање порука - permission_add_messages: Слање порука - permission_edit_messages: Измена порука - permission_edit_own_messages: Измена сопствених порука - permission_delete_messages: Брисање порука - permission_delete_own_messages: Брисање сопствених порука - permission_export_wiki_pages: Извоз wiki страна - - project_module_issue_tracking: Трагање за проблемом - project_module_time_tracking: Време трагања - project_module_news: Вести - project_module_documents: Документа - project_module_files: Датотеке - project_module_wiki: Wiki - project_module_repository: Спремиште - project_module_boards: Форуми - - label_user: Корисник - label_user_plural: Корисници - label_user_new: Нови корисник - label_user_anonymous: Анониман - label_project: Пројекат - label_project_new: Нови пројекат - label_project_plural: Пројекти - label_x_projects: - zero: нема пројеката - one: један пројекат - other: "{{count}} пројеката" - label_project_all: Сви пројекти - label_project_latest: Последњи пројекти - label_issue: Проблем - label_issue_new: Нови проблем - label_issue_plural: Проблеми - label_issue_view_all: Приказ свих проблема - label_issues_by: "Проблеми - {{value}}" - label_issue_added: Проблем је додат - label_issue_updated: Проблем је ажуриран - label_document: Документ - label_document_new: Нови документ - label_document_plural: Документи - label_document_added: Документ је додат - label_role: Улога - label_role_plural: Улоге - label_role_new: Нова улога - label_role_and_permissions: Улоге и дозволе - label_member: Члан - label_member_new: Нови члан - label_member_plural: Чланови - label_tracker: Трагач - label_tracker_plural: Трагачи - label_tracker_new: Нови трагач - label_workflow: Ток рада - label_issue_status: Статус проблема - label_issue_status_plural: Статуси проблема - label_issue_status_new: Нови статус - label_issue_category: Категорија проблема - label_issue_category_plural: Категорије проблема - label_issue_category_new: Нова категорија - label_custom_field: Прилагођено поље - label_custom_field_plural: Прилагођена поља - label_custom_field_new: Ново прилагођено поље - label_enumerations: Набројива листа - label_enumeration_new: Нова вредност - label_information: Информација - label_information_plural: Информацијe - label_please_login: Молимо, пријавите се - label_register: Регистрација - label_login_with_open_id_option: или пријава са OpenID - label_password_lost: Изгубљена лозинка - label_home: Почетак - label_my_page: Моја страна - label_my_account: Мој налог - label_my_projects: Моји пројекти - label_administration: Администрација - label_login: Пријава - label_logout: Одјава - label_help: Помоћ - label_reported_issues: Пријављени проблеми - label_assigned_to_me_issues: Проблеми додољени мени - label_last_login: Последње повезивање - label_registered_on: Регистрован - label_activity: Активност - label_overall_activity: Обухватна активност - label_user_activity: "Активност корисника {{value}}" - label_new: Ново - label_logged_as: Пријављени сте као - label_environment: Окружење - label_authentication: Провера идентитета - label_auth_source: Режим провере идентитета - label_auth_source_new: Нови режим провере идентитета - label_auth_source_plural: Режими провере идентитета - label_subproject_plural: Потпројекти - label_subproject_new: Нови потпројекат - label_and_its_subprojects: "{{value}} и његови потпројекти" - label_min_max_length: Мин. - Макс. дужина - label_list: Списак - label_date: Датум - label_integer: Цео број - label_float: Са покретним зарезом - label_boolean: Логички оператор - label_string: Текст - label_text: Дуги текст - label_attribute: Особина - label_attribute_plural: Особине - label_download: "{{count}} преузимање" - label_download_plural: "{{count}} преузимања" - label_no_data: Нема података за приказивање - label_change_status: Промена статуса - label_history: Историја - label_attachment: Датотека - label_attachment_new: Нова датотека - label_attachment_delete: Брисање датотеке - label_attachment_plural: Датотеке - label_file_added: Датотека додата - label_report: Извештај - label_report_plural: Извештаји - label_news: Вести - label_news_new: Додавање вести - label_news_plural: Вести - label_news_latest: Последње вести - label_news_view_all: Приказ свих вести - label_news_added: Вести додато - label_settings: Подешавања - label_overview: Преглед - label_version: Верзија - label_version_new: Нова верзија - label_version_plural: Верзије - label_close_versions: Затвори завршене верзије - label_confirmation: Потврда - label_export_to: 'Такође доступно и у варијанти:' - label_read: Читање... - label_public_projects: Јавни пројекти - label_open_issues: отворен - label_open_issues_plural: отворених - label_closed_issues: затворен - label_closed_issues_plural: затворених - label_x_open_issues_abbr_on_total: - zero: 0 отворених / {{total}} - one: 1 отворен / {{total}} - other: "{{count}} отворених / {{total}}" - label_x_open_issues_abbr: - zero: 0 отворених - one: 1 отворен - other: "{{count}} отворених" - label_x_closed_issues_abbr: - zero: 0 затворених - one: 1 затворен - other: "{{count}} затворених" - label_total: Укупно - label_permissions: Овлашћења - label_current_status: Тренутни статус - label_new_statuses_allowed: Нови статуси дозвољени - label_all: сви - label_none: ниједан - label_nobody: никоме - label_next: Следеће - label_previous: Претходно - label_used_by: Користио - label_details: Детаљи - label_add_note: Додај белешку - label_per_page: По страни - label_calendar: Календар - label_months_from: месеци од - label_gantt: Гантов дијаграм - label_internal: Унутрашљи - label_last_changes: "последњих {{count}} промена" - label_change_view_all: Прикажи све промене - label_personalize_page: Персонализујте ову страну - label_comment: Коментар - label_comment_plural: Коментари - label_x_comments: - zero: без коментара - one: један коментар - other: "{{count}} коментара" - label_comment_add: Додај коментар - label_comment_added: Коментар додат - label_comment_delete: Обриши коментаре - label_query: Прилагођен упит - label_query_plural: Прилагођени упити - label_query_new: Нови упит - label_filter_add: Додај филтер - label_filter_plural: Филтери - label_equals: је - label_not_equals: није - label_in_less_than: мање од - label_in_more_than: више од - label_greater_or_equal: '>=' - label_less_or_equal: '<=' - label_in: у - label_today: данас - label_all_time: све време - label_yesterday: јуче - label_this_week: ове седмице - label_last_week: последње седмице - label_last_n_days: "последњих {{count}} дана" - label_this_month: овог месеца - label_last_month: последњег месеца - label_this_year: ове године - label_date_range: Временски период - label_less_than_ago: пре мање од неколико дана - label_more_than_ago: пре више од неколико дана - label_ago: пре неколико дана - label_contains: садржи - label_not_contains: не садржи - label_day_plural: дана - label_repository: Спремиште - label_repository_plural: Спремишта - label_browse: Прегледање - label_modification: "{{count}} промена" - label_modification_plural: "{{count}} промена" - label_branch: Грана - label_tag: Ознака - label_revision: Ревизија - label_revision_plural: Ревизије - label_revision_id: "Ревизија {{value}}" - label_associated_revisions: Придружене ревизије - label_added: додато - label_modified: промењено - label_copied: копирано - label_renamed: преименовано - label_deleted: обрисано - label_latest_revision: Последња ревизија - label_latest_revision_plural: Последње ревизије - label_view_revisions: Преглед ревизија - label_view_all_revisions: Преглед свих ревизија - label_max_size: Максимална величина - label_sort_highest: Премести на врх - label_sort_higher: Премести на горе - label_sort_lower: Премести на доле - label_sort_lowest: Премести на дно - label_roadmap: План рада - label_roadmap_due_in: "Доспева {{value}}" - label_roadmap_overdue: "{{value}} најкасније" - label_roadmap_no_issues: Нема проблема за ову верзију - label_search: Претрага - label_result_plural: Резултати - label_all_words: Све речи - label_wiki: Wiki - label_wiki_edit: Wiki измена - label_wiki_edit_plural: Wiki измене - label_wiki_page: Wiki страна - label_wiki_page_plural: Wiki стране - label_index_by_title: Индексирање по наслову - label_index_by_date: Индексирање по датуму - label_current_version: Тренутна верзија - label_preview: Преглед - label_feed_plural: Извори вести - label_changes_details: Детаљи свих промена - label_issue_tracking: Праћење проблема - label_spent_time: Утрошено време - label_f_hour: "{{value}} сат" - label_f_hour_plural: "{{value}} сати" - label_time_tracking: Време праћења - label_change_plural: Промене - label_statistics: Статистика - label_commits_per_month: Потврда месечно - label_commits_per_author: Потврда по аутору - label_view_diff: Погледај разлике - label_diff_inline: унутра - label_diff_side_by_side: упоредо - label_options: Опције - label_copy_workflow_from: Копирај ток рада од - label_permissions_report: Извештај о овлашћењима - label_watched_issues: Посматрани проблеми - label_related_issues: Повезани проблеми - label_applied_status: Примењени статуси - label_loading: Учитавање... - label_relation_new: Нова релација - label_relation_delete: Обриши релацију - label_relates_to: повезаних са - label_duplicates: дуплираних - label_duplicated_by: дуплираних од - label_blocks: одбијених - label_blocked_by: одбијених од - label_precedes: претходи - label_follows: праћених - label_end_to_start: од краја до почетка - label_end_to_end: од краја до краја - label_start_to_start: од почетка до почетка - label_start_to_end: од почетка до краја - label_stay_logged_in: Остани пријављен - label_disabled: онемогућено - label_show_completed_versions: Прикажи завршене верзије - label_me: мени - label_board: Форум - label_board_new: Нови форум - label_board_plural: Форуми - label_board_locked: Закључана - label_board_sticky: Лепљива - label_topic_plural: Теме - label_message_plural: Поруке - label_message_last: Последња порука - label_message_new: Нова порука - label_message_posted: Порука је додата - label_reply_plural: Одговори - label_send_information: Пошаљи детаље налога кориснику - label_year: Година - label_month: Месец - label_week: Седмица - label_date_from: Шаље - label_date_to: Прима - label_language_based: Базирано на језику корисника - label_sort_by: "Поређано по {{value}}" - label_send_test_email: Пошаљи пробну поруку - label_feeds_access_key: RSS приступни кључ - label_missing_feeds_access_key: RSS приступни кључ недостаје - label_feeds_access_key_created_on: "RSS приступни кључ је направљен пре {{value}}" - label_module_plural: Модули - label_added_time_by: "Додао {{author}} пре {{age}}" - label_updated_time_by: "Ажурирао {{author}} пре {{age}}" - label_updated_time: "Ажурирано пре {{value}}" - label_jump_to_a_project: Скок на пројекат... - label_file_plural: Датотеке - label_changeset_plural: Скупови промена - label_default_columns: Подразумеване колоне - label_no_change_option: (Без промена) - label_bulk_edit_selected_issues: Групна измена одабраних проблема - label_theme: Тема - label_default: Подразумевано - label_search_titles_only: Претражуј само наслове - label_user_mail_option_all: "За било који догађај на свим мојим пројектима" - label_user_mail_option_selected: "За било који догађај на само одабраним пројектима..." - label_user_mail_option_none: "Само за ствари које пратим или сам укључен" - label_user_mail_no_self_notified: "Не желим бити обавештаван за промене које сам правим" - label_registration_activation_by_email: активација налога путем емаил-а - label_registration_manual_activation: ручна активација налога - label_registration_automatic_activation: аутоматска активација налога - label_display_per_page: "Број ставки по страни: {{value}}" - label_age: Старост - label_change_properties: Промени својства - label_general: Општи - label_more: Више - label_scm: SCM - label_plugins: Додаци - label_ldap_authentication: LDAP провера идентитета - label_downloads_abbr: D/L - label_optional_description: Опционо опис - label_add_another_file: Додај још једну датотеку - label_preferences: Подешавања - label_chronological_order: по хронолошком редоследу - label_reverse_chronological_order: по обрнутом хронолошком редоследу - label_planning: Планирање - label_incoming_emails: Долазне поруке - label_generate_key: Генериши кључ - label_issue_watchers: Посматрачи - label_example: Пример - label_display: Приказ - label_sort: Редослед - label_ascending: Растући низ - label_descending: Опадајући низ - label_date_from_to: Од {{start}} до {{end}} - label_wiki_content_added: Wiki страна је додата - label_wiki_content_updated: Wiki страна је ажурирана - label_group: Група - label_group_plural: Групе - label_group_new: Нова група - label_time_entry_plural: Проведено време - label_version_sharing_none: Није дељено - label_version_sharing_descendants: Са потпројектима - label_version_sharing_hierarchy: Са хијерархијом пројекта - label_version_sharing_tree: Са стаблом пројекта - label_version_sharing_system: Са свим пројектима - label_update_issue_done_ratios: Ажурирај однос решених проблема - label_copy_source: Извор - label_copy_target: Одредиште - label_copy_same_as_target: Исто као одредиште - label_display_used_statuses_only: Приказуј статусе коришћене само од стране овог трагача - label_api_access_key: API приступни кључ - label_missing_api_access_key: API приступни кључ недостаје - label_api_access_key_created_on: "API приступни кључ је креиран пре {{value}}" - label_project_copy_notifications: Пошаљи емаил поруку са обавештењем приликом копирања пројекта - - button_login: Пријава - button_submit: Пошаљи - button_save: Сними - button_check_all: Укључи све - button_uncheck_all: Искључи све - button_delete: Обриши - button_create: Направи - button_create_and_continue: Направи и настави - button_test: Тест - button_edit: Измени - button_add: Додај - button_change: Промени - button_apply: Примени - button_clear: Обриши - button_lock: Закључај - button_unlock: Откључај - button_download: Преузми - button_list: Списак - button_view: Приказ - button_move: Помери - button_move_and_follow: Помери и прати - button_back: Назад - button_cancel: Поништи - button_activate: Активирај - button_sort: Поређај - button_log_time: Евидентирање времена - button_rollback: Повратак на ову верзију - button_watch: Прати - button_unwatch: Не прати више - button_reply: Одговори - button_archive: Архивирај - button_unarchive: Врати из архиве - button_reset: Поништи - button_rename: Реименуј - button_change_password: Променa лозинкe - button_copy: Копирај - button_copy_and_follow: Копирај и прати - button_annotate: Прибележи - button_update: Ажурирај - button_configure: Подеси - button_quote: Под наводницима - button_duplicate: Дуплирај - button_show: Прикажи - - status_active: активни - status_registered: регистровани - status_locked: закључани - - version_status_open: отворен - version_status_locked: закључан - version_status_closed: затворен - - field_active: Активан - - text_select_mail_notifications: Одабери акције за које ће емаил обавештење бити послато. - text_regexp_info: нпр. ^[A-Z0-9]+$ - text_min_max_length_info: 0 значи без ограничења - text_project_destroy_confirmation: Јесте ли сигурни да желите да обришете овај пројекат и све припадајуће податке? - text_subprojects_destroy_warning: "Потпојекат: {{value}} ће такође бити обрисан." - text_workflow_edit: Одаберите улогу и трагача за измену тока рада - text_are_you_sure: Јесте ли сигурни? - text_journal_changed: "{{label}} промењен од {{old}} у {{new}}" - text_journal_set_to: "{{label}} постављен у {{value}}" - text_journal_deleted: "{{label}} обрисано ({{old}})" - text_journal_added: "{{label}} {{value}} додато" - text_tip_task_begin_day: задатак почиње овог дана - text_tip_task_end_day: задатак се завршава овог дана - text_tip_task_begin_end_day: задатак почиње и завршава истог дана - text_project_identifier_info: 'Дозвољена су само мала слова (a-ш), бројеви и цртице.
    Једном снимљен, идентификатор се не може променити.' - text_caracters_maximum: "{{count}} знак(ова) највише." - text_caracters_minimum: "Број знакова мора бити најмање {{count}}." - text_length_between: "Број знакова мора бити између {{min}} и {{max}}." - text_tracker_no_workflow: Ток рада није дефинисан за овог трагача - text_unallowed_characters: Недозвољени знакови - text_comma_separated: Вишеструке вредности су дозвољене (одвојене зарезом). - text_line_separated: Вишеструке вредности су дозвољене (један ред за сваку вредност). - text_issues_ref_in_commit_messages: Референцирање и поправљање проблема у извршним порукама - text_issue_added: "Проблем {{id}} је пријавио {{author}}." - text_issue_updated: "Проблем {{id}} је ажурирао {{author}}." - text_wiki_destroy_confirmation: Јесте ли сигурни да желите да обришете wiki и сав садржај? - text_issue_category_destroy_question: "Неколико проблема ({{count}}) је додељено овој категорији. Шта желите да урадите?" - text_issue_category_destroy_assignments: Уклони додољене категорије - text_issue_category_reassign_to: Додели поново проблеме овој категорији - text_user_mail_option: "За неизабране пројекте, добићете само обавештење о стварима које пратите или сте укључени (нпр. проблеми чији сте ви аутор или заступник)." - text_no_configuration_data: "Улоге, трагачи, статуси проблема и процеса рада још увек нису подешени.\nПрепоручљиво је да учитате подразумевано конфигурисање. Измена је могућа након првог учитавања." - text_load_default_configuration: Учитај подразумевано конфигурисање - text_status_changed_by_changeset: "Примењено у скупу са променама {{value}}." - text_issues_destroy_confirmation: 'Јесте ли сигурни да желите да обришете одабране проблеме?' - text_select_project_modules: 'Одаберите модуле које желите омогућити за овај пројекат:' - text_default_administrator_account_changed: Подразумевани администраторски налог је промењен - text_file_repository_writable: Фасцикла приложених датотека је уписива - text_plugin_assets_writable: Фасцикла елемената додатка је уписива - text_rmagick_available: RMagick је доступан (опционо) - text_destroy_time_entries_question: "{{hours}} сати је пријављено за овај проблем који желите обрисати. Шта желите да урадите?" - text_destroy_time_entries: Обриши пријављене сате - text_assign_time_entries_to_project: Додели пријављене сате пројекту - text_reassign_time_entries: 'Додели поново пријављене сате овом проблему:' - text_user_wrote: "{{value}} је написао:" - text_enumeration_destroy_question: "{{count}} објекат(а) је додељено овој вредности." - text_enumeration_category_reassign_to: 'Додели их поново овој вредности:' - text_email_delivery_not_configured: "Испорука емаил порука није конфигурисана и обавештавања су онемогућена.\nПодесите ваш SMTP сервер у config/email.yml и покрените поново апликацију за њихово омогућавање." - text_repository_usernames_mapping: "Одаберите или ажурирајте Redmine кориснике мапирањем на свако корисничко име пронађено у евиденцији спремишта.\nКорисници са истим Redmine именом и именом спремишта или емаил адресом су аутоматски мапирани." - text_diff_truncated: '... Ова разлика је исечена зато што је достигнута максимална величина која може бити приказана.' - text_custom_field_possible_values_info: 'Један ред за сваку вредност' - text_wiki_page_destroy_question: "Ова страна има {{descendants}} страна наследника и потомака. Шта желите да урадите?" - text_wiki_page_nullify_children: "Задржи стране наследника као корене стране" - text_wiki_page_destroy_children: "Обриши стране наследника и свих њихових потомака" - text_wiki_page_reassign_children: "Додели поново стране наследника њиховој родитељској страни" - text_own_membership_delete_confirmation: "Уклањањем појединих или свих ваших дозвола нећете више моћи за уређујете овај пројекат након тога.\nЖелите ли да наставите?" - - default_role_manager: Менаџер - default_role_developer: Програмер - default_role_reporter: Извештач - default_tracker_bug: Грешка - default_tracker_feature: Функционалност - default_tracker_support: Подршка - default_issue_status_new: Ново - default_issue_status_in_progress: У току - default_issue_status_resolved: Решено - default_issue_status_feedback: Повратна информација - default_issue_status_closed: Затворено - default_issue_status_rejected: Одбијено - default_doc_category_user: Корисничка документација - default_doc_category_tech: Техничка документација - default_priority_low: Низак - default_priority_normal: Нормалан - default_priority_high: Висок - default_priority_urgent: Хитно - default_priority_immediate: Непосредно - default_activity_design: Дизајн - default_activity_development: Развој - - enumeration_issue_priorities: Приоритети проблема - enumeration_doc_categories: Категорије документа - enumeration_activities: Активности (временски праћене) - enumeration_system_activity: Системска активност - - error_can_not_delete_custom_field: Unable to delete custom field - permission_manage_subtasks: Manage subtasks - label_profile: Profile - error_unable_to_connect: Unable to connect ({{value}}) - error_can_not_remove_role: This role is in use and can not be deleted. - field_parent_issue: Parent task - error_unable_delete_issue_status: Unable to delete issue status - label_subtask_plural: Subtasks - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. - field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time diff --git a/config/locales/sr-YU.yml b/config/locales/sr-YU.yml new file mode 100644 index 00000000..2cc0c098 --- /dev/null +++ b/config/locales/sr-YU.yml @@ -0,0 +1,907 @@ +# Serbian translations for Redmine +# by Vladimir Medarović (vlada@medarovic.com) +sr-YU: + date: + formats: + # Use the strftime parameters for formats. + # When no format has been given, it uses default. + # You can provide other formats here if you like! + default: "%d.%m.%Y." + short: "%e %b" + long: "%B %e, %Y" + + day_names: [nedelja, ponedeljak, utorak, sreda, četvrtak, petak, subota] + abbr_day_names: [ned, pon, uto, sre, čet, pet, sub] + + # Don't forget the nil at the beginning; there's no such thing as a 0th month + month_names: [~, januar, februar, mart, april, maj, jun, jul, avgust, septembar, oktobar, novembar, decembar] + abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, avg, sep, okt, nov, dec] + # Used in date_select and datime_select. + order: [ :day, :month, :year ] + + time: + formats: + default: "%d.%m.%Y. u %H:%M" + time: "%H:%M" + short: "%d. %b u %H:%M" + long: "%d. %B %Y u %H:%M" + am: "am" + pm: "pm" + + datetime: + distance_in_words: + half_a_minute: "pola minuta" + less_than_x_seconds: + one: "manje od jedne sekunde" + other: "manje od {{count}} sek." + x_seconds: + one: "jedna sekunda" + other: "{{count}} sek." + less_than_x_minutes: + one: "manje od minuta" + other: "manje od {{count}} min." + x_minutes: + one: "jedan minut" + other: "{{count}} min." + about_x_hours: + one: "približno jedan sat" + other: "približno {{count}} sati" + x_days: + one: "jedan dan" + other: "{{count}} dana" + about_x_months: + one: "približno jedan mesec" + other: "približno {{count}} meseci" + x_months: + one: "jedan mesec" + other: "{{count}} meseci" + about_x_years: + one: "približno godinu dana" + other: "približno {{count}} god." + over_x_years: + one: "preko godinu dana" + other: "preko {{count}} god." + almost_x_years: + one: "skoro godinu dana" + other: "skoro {{count}} god." + + number: + human: + format: + delimiter: "" + precision: 1 + storage_units: + format: "%n %u" + units: + byte: + one: "Byte" + other: "Bytes" + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" + + +# Used in array.to_sentence. + support: + array: + sentence_connector: "i" + skip_last_comma: false + + activerecord: + errors: + messages: + inclusion: "nije uključen u spisak" + exclusion: "je rezervisan" + invalid: "je neispravan" + confirmation: "potvrda ne odgovara" + accepted: "mora biti prihvaćen" + empty: "ne može biti prazno" + blank: "ne može biti prazno" + too_long: "je predugačka (maksimum znakova je {{count}})" + too_short: "je prekratka (minimum znakova je {{count}})" + wrong_length: "je pogrešne dužine (broj znakova mora biti {{count}})" + taken: "je već u upotrebi" + not_a_number: "nije broj" + not_a_date: "nije ispravan datum" + greater_than: "mora biti veći od {{count}}" + greater_than_or_equal_to: "mora biti veći ili jednak {{count}}" + equal_to: "mora biti jednak {{count}}" + less_than: "mora biti manji od {{count}}" + less_than_or_equal_to: "mora biti manji ili jednak {{count}}" + odd: "mora biti paran" + even: "mora biti neparan" + greater_than_start_date: "mora biti veći od početnog datuma" + not_same_project: "ne pripada istom projektu" + circular_dependency: "Ova veza će stvoriti kružnu referencu" + cant_link_an_issue_with_a_descendant: "Problem ne može biti povezan sa jednim od svojih podzadataka" + + actionview_instancetag_blank_option: Molim odaberite + + general_text_No: 'Ne' + general_text_Yes: 'Da' + general_text_no: 'ne' + general_text_yes: 'da' + general_lang_name: 'Srpski' + general_csv_separator: ',' + general_csv_decimal_separator: '.' + general_csv_encoding: UTF-8 + general_pdf_encoding: UTF-8 + general_first_day_of_week: '1' + + notice_account_updated: Nalog je uspešno ažuriran. + notice_account_invalid_creditentials: Neispravno korisničko ime ili lozinka. + notice_account_password_updated: Lozinka je uspešno ažurirana. + notice_account_wrong_password: Pogrešna lozinka + notice_account_register_done: Korisnički nalog je uspešno kreiran. Kliknite na link koji ste dobili u e-poruci za aktivaciju. + notice_account_unknown_email: Nepoznat korisnik. + notice_can_t_change_password: Ovaj korisnički nalog za potvrdu identiteta koristi spoljni izvor. Nemoguće je promeniti lozinku. + notice_account_lost_email_sent: Poslata vam je e-poruka sa uputstvom za izbor nove lozinke + notice_account_activated: Vaš korisnički nalog je aktiviran. Sada se možete prijaviti. + notice_successful_create: Uspešno kreiranje. + notice_successful_update: Uspešno ažuriranje. + notice_successful_delete: Uspešno brisanje. + notice_successful_connection: Uspešno povezivanje. + notice_file_not_found: Strana kojoj želite pristupiti ne postoji ili je uklonjena. + notice_locking_conflict: Podatak je ažuriran od strane drugog korisnika. + notice_not_authorized: Niste ovlašćeni za pristup ovoj strani. + notice_email_sent: "E-poruka je poslata na {{value}}" + notice_email_error: "Dogodila se greška prilikom slanja e-poruke ({{value}})" + notice_feeds_access_key_reseted: Vaš RSS pristupni ključ je poništen. + notice_api_access_key_reseted: Vaš API pristupni ključ je poništen. + notice_failed_to_save_issues: "Neuspešno snimanje {{count}} problema od {{total}} odabranih: {{ids}}." + notice_failed_to_save_members: "Neuspešno snimanje člana(ova): {{errors}}." + notice_no_issue_selected: "Ni jedan problem nije odabran! Molimo, odaberite problem koji želite da menjate." + notice_account_pending: "Vaš nalog je kreiran i čeka na odobrenje administratora." + notice_default_data_loaded: Podrazumevano konfigurisanje je uspešno učitano. + notice_unable_delete_version: Verziju je nemoguće izbrisati. + notice_unable_delete_time_entry: Stavku evidencije vremena je nemoguće izbrisati. + notice_issue_done_ratios_updated: Odnos rešenih problema je ažuriran. + + error_can_t_load_default_data: "Podrazumevano konfigurisanje je nemoguće učitati: {{value}}" + error_scm_not_found: "Stavka ili ispravka nisu pronađene u spremištu." + error_scm_command_failed: "Greška se javila prilikom pokušaja pristupa spremištu: {{value}}" + error_scm_annotate: "Stavka ne postoji ili ne može biti označena." + error_issue_not_found_in_project: 'Problem nije pronađen ili ne pripada ovom projektu.' + error_no_tracker_in_project: 'Ni jedno praćenje nije povezano sa ovim projektom. Molimo proverite podešavanja projekta.' + error_no_default_issue_status: 'Podrazumevani status problema nije definisan. Molimo proverite vaše konfigurisanje (idite na "Administracija -> Statusi problema").' + error_can_not_delete_custom_field: Nemoguće je izbrisati prilagođeno polje + error_can_not_delete_tracker: "Ovo praćenje sadrži probleme i ne može biti obrisano." + error_can_not_remove_role: "Ova uloga je u upotrebi i ne može biti obrisana." + error_can_not_reopen_issue_on_closed_version: 'Problem dodeljen zatvorenoj verziji ne može biti ponovo otvoren' + error_can_not_archive_project: Ovaj projekat se ne može arhivirati + error_issue_done_ratios_not_updated: "Odnos rešenih problema nije ažuriran." + error_workflow_copy_source: 'Molimo odaberite izvorno praćenje ili ulogu' + error_workflow_copy_target: 'Molimo odaberite odredišno praćenje i ulogu' + error_unable_delete_issue_status: 'Status problema je nemoguće obrisati' + error_unable_to_connect: "Povezivanje sa ({{value}}) je nemoguće" + warning_attachments_not_saved: "{{count}} datoteka ne može biti snimljena." + + mail_subject_lost_password: "Vaša {{value}} lozinka" + mail_body_lost_password: 'Za promenu vaše lozinke, kliknite na sledeći link:' + mail_subject_register: "Aktivacija vašeg {{value}} naloga" + mail_body_register: 'Za aktivaciju vašeg naloga, kliknite na sledeći link:' + mail_body_account_information_external: "Vaš nalog {{value}} možete koristiti za prijavu." + mail_body_account_information: Informacije o vašem nalogu + mail_subject_account_activation_request: "Zahtev za aktivaciju naloga {{value}}" + mail_body_account_activation_request: "Novi korisnik ({{value}}) je registrovan. Nalog čeka na vaše odobrenje:" + mail_subject_reminder: "{{count}} problema dospeva narednih {{days}} dana" + mail_body_reminder: "{{count}} problema dodeljenih vama dospeva u narednih {{days}} dana:" + mail_subject_wiki_content_added: "Wiki stranica '{{page}}' je dodata" + mail_body_wiki_content_added: "{{author}} je dodao wiki stranicu '{{page}}'." + mail_subject_wiki_content_updated: "Wiki stranica '{{page}}' je ažurirana" + mail_body_wiki_content_updated: "{{author}} je ažurirao wiki stranicu '{{page}}'." + + gui_validation_error: jedna greška + gui_validation_error_plural: "{{count}} grešaka" + + field_name: Naziv + field_description: Opis + field_summary: Rezime + field_is_required: Obavezno + field_firstname: Ime + field_lastname: Prezime + field_mail: E-adresa + field_filename: Datoteka + field_filesize: Veličina + field_downloads: Preuzimanja + field_author: Autor + field_created_on: Kreirano + field_updated_on: Ažurirano + field_field_format: Format + field_is_for_all: Za sve projekte + field_possible_values: Moguće vrednosti + field_regexp: Regularan izraz + field_min_length: Minimalna dužina + field_max_length: Maksimalna dužina + field_value: Vrednost + field_category: Kategorija + field_title: Naslov + field_project: Projekat + field_issue: Problem + field_status: Status + field_notes: Beleške + field_is_closed: Zatvoren problem + field_is_default: Podrazumevana vrednost + field_tracker: Praćenje + field_subject: Predmet + field_due_date: Krajnji rok + field_assigned_to: Dodeljeno + field_priority: Prioritet + field_fixed_version: Odredišna verzija + field_user: Korisnik + field_principal: Glavni + field_role: Uloga + field_homepage: Početna stranica + field_is_public: Javno objavljivanje + field_parent: Potprojekat od + field_is_in_roadmap: Problemi prikazani u planu rada + field_login: Korisničko ime + field_mail_notification: Obaveštenja putem e-pošte + field_admin: Administrator + field_last_login_on: Poslednje povezivanje + field_language: Jezik + field_effective_date: Datum + field_password: Lozinka + field_new_password: Nova lozinka + field_password_confirmation: Potvrda lozinke + field_version: Verzija + field_type: Tip + field_host: Glavni računar + field_port: Port + field_account: Korisnički nalog + field_base_dn: Bazni DN + field_attr_login: Atribut prijavljivanja + field_attr_firstname: Atribut imena + field_attr_lastname: Atribut prezimena + field_attr_mail: Atribut e-adrese + field_onthefly: Kreiranje korisnika u toku rada + field_start_date: Početak + field_done_ratio: % urađeno + field_auth_source: Režim potvrde identiteta + field_hide_mail: Sakrij moju e-adresu + field_comments: Komentar + field_url: URL + field_start_page: Početna stranica + field_subproject: Potprojekat + field_hours: sati + field_activity: Aktivnost + field_spent_on: Datum + field_identifier: Identifikator + field_is_filter: Upotrebi kao filter + field_issue_to: Srodni problemi + field_delay: Kašnjenje + field_assignable: Problem može biti dodeljen ovoj ulozi + field_redirect_existing_links: Preusmeri postojeće veze + field_estimated_hours: Proteklo vreme + field_column_names: Kolone + field_time_zone: Vremenska zona + field_searchable: Može da se pretražuje + field_default_value: Podrazumevana vrednost + field_comments_sorting: Prikaži komentare + field_parent_title: Matična stranica + field_editable: Izmenljivo + field_watcher: Posmatrač + field_identity_url: OpenID URL + field_content: Sadržaj + field_group_by: Grupisanje rezultata po + field_sharing: Deljenje + field_parent_issue: Matični zadatak + + setting_app_title: Naslov aplikacije + setting_app_subtitle: Podnaslov aplikacije + setting_welcome_text: Tekst dobrodošlice + setting_default_language: Podrazumevani jezik + setting_login_required: Obavezna potvrda identiteta + setting_self_registration: Samoregistracija + setting_attachment_max_size: Maks. veličina priložene datoteke + setting_issues_export_limit: Ograničenje izvoza „problema“ + setting_mail_from: E-adresa pošiljaoca + setting_bcc_recipients: Primaoci „Bcc“ kopije + setting_plain_text_mail: Poruka sa čistim tekstom (bez HTML-a) + setting_host_name: Putanja i naziv glavnog računara + setting_text_formatting: Oblikovanje teksta + setting_wiki_compression: Kompresija Wiki istorije + setting_feeds_limit: Ograničenje sadržaja izvora vesti + setting_default_projects_public: Podrazumeva se javno prikazivanje novih projekata + setting_autofetch_changesets: Izvršavanje automatskog preuzimanja + setting_sys_api_enabled: Omogućavanje WS za upravljanje spremištem + setting_commit_ref_keywords: Referenciranje ključnih reči + setting_commit_fix_keywords: Popravljanje ključnih reči + setting_autologin: Automatska prijava + setting_date_format: Format datuma + setting_time_format: Format vremena + setting_cross_project_issue_relations: Dozvoli povezivanje problema iz unakrsnih projekata + setting_issue_list_default_columns: Podrazumevane kolone prikazane na spisku problema + setting_repositories_encodings: Kodiranje spremišta + setting_commit_logs_encoding: Kodiranje izvršnih poruka + setting_emails_footer: Podnožje stranice e-poruke + setting_protocol: Protokol + setting_per_page_options: Opcije prikaza objekata po stranici + setting_user_format: Format prikaza korisnika + setting_activity_days_default: Broj dana prikazanih na projektnoj aktivnosti + setting_display_subprojects_issues: Prikazuj probleme iz potprojekata na glavnom projektu, ukoliko nije drugačije navedeno + setting_enabled_scm: Omogućavanje SCM + setting_mail_handler_body_delimiters: "Skraćivanje e-poruke nakon jedne od ovih linija" + setting_mail_handler_api_enabled: Omogućavanje WS dolazne e-poruke + setting_mail_handler_api_key: API ključ + setting_sequential_project_identifiers: Generisanje sekvencijalnog imena projekta + setting_gravatar_enabled: Koristi Gravatar korisničke ikone + setting_gravatar_default: Podrazumevana Gravatar slika + setting_diff_max_lines_displayed: Maks. broj prikazanih različitih linija + setting_file_max_size_displayed: Maks. veličina tekst. datoteka prikazanih umetnuto + setting_repository_log_display_limit: Maks. broj revizija prikazanih u datoteci za evidenciju + setting_openid: Dozvoli OpenID prijavu i registraciju + setting_password_min_length: Minimalna dužina lozinke + setting_new_project_user_role_id: Kreatoru projekta (koji nije administrator) dodeljuje je uloga + setting_default_projects_modules: Podrazumevano omogućeni moduli za nove projekte + setting_issue_done_ratio: Izračunaj odnos rešenih problema + setting_issue_done_ratio_issue_field: koristeći polje problema + setting_issue_done_ratio_issue_status: koristeći status problema + setting_start_of_week: Prvi dan u sedmici + setting_rest_api_enabled: Omogući REST web usluge + setting_cache_formatted_text: Keširanje obrađenog teksta + + permission_add_project: Kreiranje projekta + permission_add_subprojects: Kreiranje potpojekta + permission_edit_project: Izmena projekata + permission_select_project_modules: Odabiranje modula projekta + permission_manage_members: Upravljanje članovima + permission_manage_project_activities: Upravljanje projektnim aktivnostima + permission_manage_versions: Upravljanje verzijama + permission_manage_categories: Upravljanje kategorijama problema + permission_view_issues: Pregled problema + permission_add_issues: Dodavanje problema + permission_edit_issues: Izmena problema + permission_manage_issue_relations: Upravljanje vezama između problema + permission_add_issue_notes: Dodavanje beleški + permission_edit_issue_notes: Izmena beleški + permission_edit_own_issue_notes: Izmena sopstvenih beleški + permission_move_issues: Pomeranje problema + permission_delete_issues: Brisanje problema + permission_manage_public_queries: Upravljanje javnim upitima + permission_save_queries: Snimanje upita + permission_view_gantt: Pregledanje Gantovog dijagrama + permission_view_calendar: Pregledanje kalendara + permission_view_issue_watchers: Pregledanje spiska posmatrača + permission_add_issue_watchers: Dodavanje posmatrača + permission_delete_issue_watchers: Brisanje posmatrača + permission_log_time: Beleženje utrošenog vremena + permission_view_time_entries: Pregledanje utrošenog vremena + permission_edit_time_entries: Izmena utrošenog vremena + permission_edit_own_time_entries: Izmena sopstvenog utrošenog vremena + permission_manage_news: Upravljanje vestima + permission_comment_news: Komentarisanje vesti + permission_manage_documents: Upravljanje dokumentima + permission_view_documents: Pregledanje dokumenata + permission_manage_files: Upravljanje datotekama + permission_view_files: Pregledanje datoteka + permission_manage_wiki: Upravljanje wiki stranicama + permission_rename_wiki_pages: Promena imena wiki stranicama + permission_delete_wiki_pages: Brisanje wiki stranica + permission_view_wiki_pages: Pregledanje wiki stranica + permission_view_wiki_edits: Pregledanje wiki istorije + permission_edit_wiki_pages: Izmena wiki stranica + permission_delete_wiki_pages_attachments: Brisanje priloženih datoteka + permission_protect_wiki_pages: Zaštita wiki stranica + permission_manage_repository: Upravljanje spremištem + permission_browse_repository: Pregledanje spremišta + permission_view_changesets: Pregledanje skupa promena + permission_commit_access: Potvrda pristupa + permission_manage_boards: Upravljanje forumima + permission_view_messages: Pregledanje poruka + permission_add_messages: Slanje poruka + permission_edit_messages: Izmena poruka + permission_edit_own_messages: Izmena sopstvenih poruka + permission_delete_messages: Brisanje poruka + permission_delete_own_messages: Brisanje sopstvenih poruka + permission_export_wiki_pages: Izvoz wiki stranica + permission_manage_subtasks: Upravljanje podzadacima + + project_module_issue_tracking: Praćenje problema + project_module_time_tracking: Praćenje vremena + project_module_news: Vesti + project_module_documents: Dokumenti + project_module_files: Datoteke + project_module_wiki: Wiki + project_module_repository: Spremište + project_module_boards: Forumi + + label_user: Korisnik + label_user_plural: Korisnici + label_user_new: Novi korisnik + label_user_anonymous: Anoniman + label_project: Projekat + label_project_new: Novi projekat + label_project_plural: Projekti + label_x_projects: + zero: nema projekata + one: jedan projekat + other: "{{count}} projekata" + label_project_all: Svi projekti + label_project_latest: Poslednji projekti + label_issue: Problem + label_issue_new: Novi problem + label_issue_plural: Problemi + label_issue_view_all: Prikaz svih problema + label_issues_by: "Problemi ({{value}})" + label_issue_added: Problem je dodat + label_issue_updated: Problem je ažuriran + label_document: Dokument + label_document_new: Novi dokument + label_document_plural: Dokumenti + label_document_added: Dokument je dodat + label_role: Uloga + label_role_plural: Uloge + label_role_new: Nova uloga + label_role_and_permissions: Uloge i dozvole + label_member: Član + label_member_new: Novi član + label_member_plural: Članovi + label_tracker: Praćenje + label_tracker_plural: Praćenja + label_tracker_new: Novo praćenje + label_workflow: Tok posla + label_issue_status: Status problema + label_issue_status_plural: Statusi problema + label_issue_status_new: Novi status + label_issue_category: Kategorija problema + label_issue_category_plural: Kategorije problema + label_issue_category_new: Nova kategorija + label_custom_field: Prilagođeno polje + label_custom_field_plural: Prilagođena polja + label_custom_field_new: Novo prilagođeno polje + label_enumerations: Nabrojiva lista + label_enumeration_new: Nova vrednost + label_information: Informacija + label_information_plural: Informacije + label_please_login: Molimo, prijavite se + label_register: Registracija + label_login_with_open_id_option: ili prijava sa OpenID + label_password_lost: Izgubljena lozinka + label_home: Početak + label_my_page: Moja stranica + label_my_account: Moj nalog + label_my_projects: Moji projekti + label_my_page_block: My page block + label_administration: Administracija + label_login: Prijava + label_logout: Odjava + label_help: Pomoć + label_reported_issues: Prijavljeni problemi + label_assigned_to_me_issues: Problemi dodeljeni meni + label_last_login: Poslednje povezivanje + label_registered_on: Registrovan + label_activity: Aktivnost + label_overall_activity: Celokupna aktivnost + label_user_activity: "Aktivnost korisnika {{value}}" + label_new: Novo + label_logged_as: Prijavljeni ste kao + label_environment: Okruženje + label_authentication: Potvrda identiteta + label_auth_source: Režim potvrde identiteta + label_auth_source_new: Novi režim potvrde identiteta + label_auth_source_plural: Režimi potvrde identiteta + label_subproject_plural: Potprojekti + label_subproject_new: Novi potprojekat + label_and_its_subprojects: "{{value}} i njegovi potprojekti" + label_min_max_length: Min. - Maks. dužina + label_list: Spisak + label_date: Datum + label_integer: Ceo broj + label_float: Sa pokretnim zarezom + label_boolean: Logički operator + label_string: Tekst + label_text: Dugi tekst + label_attribute: Osobina + label_attribute_plural: Osobine + label_download: "{{count}} preuzimanje" + label_download_plural: "{{count}} preuzimanja" + label_no_data: Nema podataka za prikazivanje + label_change_status: Promena statusa + label_history: Istorija + label_attachment: Datoteka + label_attachment_new: Nova datoteka + label_attachment_delete: Brisanje datoteke + label_attachment_plural: Datoteke + label_file_added: Datoteka je dodata + label_report: Izveštaj + label_report_plural: Izveštaji + label_news: Vesti + label_news_new: Dodavanje vesti + label_news_plural: Vesti + label_news_latest: Poslednje vesti + label_news_view_all: Prikaz svih vesti + label_news_added: Vesti su dodate + label_settings: Podešavanja + label_overview: Pregled + label_version: Verzija + label_version_new: Nova verzija + label_version_plural: Verzije + label_close_versions: Zatvori završene verzije + label_confirmation: Potvrda + label_export_to: 'Takođe dostupno i u varijanti:' + label_read: Čitanje... + label_public_projects: Javni projekti + label_open_issues: otvoren + label_open_issues_plural: otvorenih + label_closed_issues: zatvoren + label_closed_issues_plural: zatvorenih + label_x_open_issues_abbr_on_total: + zero: 0 otvorenih / {{total}} + one: 1 otvoren / {{total}} + other: "{{count}} otvorenih / {{total}}" + label_x_open_issues_abbr: + zero: 0 otvorenih + one: 1 otvoren + other: "{{count}} otvorenih" + label_x_closed_issues_abbr: + zero: 0 zatvorenih + one: 1 zatvoren + other: "{{count}} zatvorenih" + label_total: Ukupno + label_permissions: Dozvole + label_current_status: Trenutni status + label_new_statuses_allowed: Novi statusi dozvoljeni + label_all: svi + label_none: nijedan + label_nobody: nikome + label_next: Sledeće + label_previous: Prethodno + label_used_by: Koristio + label_details: Detalji + label_add_note: Dodaj belešku + label_per_page: Po strani + label_calendar: Kalendar + label_months_from: meseci od + label_gantt: Gantov dijagram + label_internal: Unutrašnji + label_last_changes: "poslednjih {{count}} promena" + label_change_view_all: Prikaži sve promene + label_personalize_page: Personalizuj ovu stranu + label_comment: Komentar + label_comment_plural: Komentari + label_x_comments: + zero: bez komentara + one: jedan komentar + other: "{{count}} komentara" + label_comment_add: Dodaj komentar + label_comment_added: Komentar dodat + label_comment_delete: Obriši komentare + label_query: Prilagođen upit + label_query_plural: Prilagođeni upiti + label_query_new: Novi upit + label_filter_add: Dodavanje filtera + label_filter_plural: Filteri + label_equals: je + label_not_equals: nije + label_in_less_than: manje od + label_in_more_than: više od + label_greater_or_equal: '>=' + label_less_or_equal: '<=' + label_in: u + label_today: danas + label_all_time: sve vreme + label_yesterday: juče + label_this_week: ove sedmice + label_last_week: poslednje sedmice + label_last_n_days: "poslednjih {{count}} dana" + label_this_month: ovog meseca + label_last_month: poslednjeg meseca + label_this_year: ove godine + label_date_range: Vremenski period + label_less_than_ago: pre manje od nekoliko dana + label_more_than_ago: pre više od nekoliko dana + label_ago: pre nekoliko dana + label_contains: sadrži + label_not_contains: ne sadrži + label_day_plural: dana + label_repository: Spremište + label_repository_plural: Spremišta + label_browse: Pregledanje + label_modification: "{{count}} promena" + label_modification_plural: "{{count}} promena" + label_branch: Grana + label_tag: Oznaka + label_revision: Revizija + label_revision_plural: Revizije + label_revision_id: "Revizija {{value}}" + label_associated_revisions: Pridružene revizije + label_added: dodato + label_modified: promenjeno + label_copied: kopirano + label_renamed: preimenovano + label_deleted: izbrisano + label_latest_revision: Poslednja revizija + label_latest_revision_plural: Poslednje revizije + label_view_revisions: Pregled revizija + label_view_all_revisions: Pregled svih revizija + label_max_size: Maksimalna veličina + label_sort_highest: Premeštanje na vrh + label_sort_higher: Premeštanje na gore + label_sort_lower: Premeštanje na dole + label_sort_lowest: Premeštanje na dno + label_roadmap: Plan rada + label_roadmap_due_in: "Dospeva {{value}}" + label_roadmap_overdue: "{{value}} najkasnije" + label_roadmap_no_issues: Nema problema za ovu verziju + label_search: Pretraga + label_result_plural: Rezultati + label_all_words: Sve reči + label_wiki: Wiki + label_wiki_edit: Wiki izmena + label_wiki_edit_plural: Wiki izmene + label_wiki_page: Wiki stranica + label_wiki_page_plural: Wiki stranice + label_index_by_title: Indeksiranje po naslovu + label_index_by_date: Indeksiranje po datumu + label_current_version: Trenutna verzija + label_preview: Pregled + label_feed_plural: Izvori vesti + label_changes_details: Detalji svih promena + label_issue_tracking: Praćenje problema + label_spent_time: Utrošeno vreme + label_overall_spent_time: Celokupno utrošeno vreme + label_f_hour: "{{value}} sat" + label_f_hour_plural: "{{value}} sati" + label_time_tracking: Praćenje vremena + label_change_plural: Promene + label_statistics: Statistika + label_commits_per_month: Izvršenja mesečno + label_commits_per_author: Izvršenja po autoru + label_view_diff: Pogledaj razlike + label_diff_inline: unutra + label_diff_side_by_side: uporedo + label_options: Opcije + label_copy_workflow_from: Kopiranje toka posla od + label_permissions_report: Izveštaj o dozvolama + label_watched_issues: Posmatrani problemi + label_related_issues: Srodni problemi + label_applied_status: Primenjeni statusi + label_loading: Učitavanje... + label_relation_new: Nova relacija + label_relation_delete: Brisanje relacije + label_relates_to: srodnih sa + label_duplicates: dupliranih + label_duplicated_by: dupliranih od + label_blocks: odbijenih + label_blocked_by: odbijenih od + label_precedes: prethodi + label_follows: praćenih + label_end_to_start: od kraja do početka + label_end_to_end: od kraja do kraja + label_start_to_start: od početka do početka + label_start_to_end: od početka do kraja + label_stay_logged_in: Ostanite prijavljeni + label_disabled: onemogućeno + label_show_completed_versions: Prikazivanje završene verzije + label_me: meni + label_board: Forum + label_board_new: Novi forum + label_board_plural: Forumi + label_board_locked: Zaključana + label_board_sticky: Lepljiva + label_topic_plural: Teme + label_message_plural: Poruke + label_message_last: Poslednja poruka + label_message_new: Nova poruka + label_message_posted: Poruka je dodata + label_reply_plural: Odgovori + label_send_information: Pošalji korisniku detalje naloga + label_year: Godina + label_month: Mesec + label_week: Sedmica + label_date_from: Šalje + label_date_to: Prima + label_language_based: Bazirano na jeziku korisnika + label_sort_by: "Sortirano po {{value}}" + label_send_test_email: Slanje probne e-poruke + label_feeds_access_key: RSS pristupni ključ + label_missing_feeds_access_key: RSS pristupni ključ nedostaje + label_feeds_access_key_created_on: "RSS pristupni ključ je napravljen pre {{value}}" + label_module_plural: Moduli + label_added_time_by: "Dodao {{author}} pre {{age}}" + label_updated_time_by: "Ažurirao {{author}} pre {{age}}" + label_updated_time: "Ažurirano pre {{value}}" + label_jump_to_a_project: Skok na projekat... + label_file_plural: Datoteke + label_changeset_plural: Skupovi promena + label_default_columns: Podrazumevane kolone + label_no_change_option: (Bez promena) + label_bulk_edit_selected_issues: Grupna izmena odabranih problema + label_theme: Tema + label_default: Podrazumevano + label_search_titles_only: Pretražuj samo naslove + label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" + label_user_mail_option_selected: "Za bilo koji događaj na samo odabranim projektima..." + label_user_mail_option_none: "Samo za stvari koje pratim ili u koje sam uključen" + label_user_mail_no_self_notified: "Ne želim biti obaveštavan za promene koje sam pravim" + label_registration_activation_by_email: aktivacija naloga putem e-poruke + label_registration_manual_activation: ručna aktivacija naloga + label_registration_automatic_activation: automatska aktivacija naloga + label_display_per_page: "Broj stavki po stranici: {{value}}" + label_age: Starost + label_change_properties: Promeni svojstva + label_general: Opšti + label_more: Više + label_scm: SCM + label_plugins: Dodatne komponente + label_ldap_authentication: LDAP potvrda identiteta + label_downloads_abbr: D/L + label_optional_description: Opciono opis + label_add_another_file: Dodaj još jednu datoteku + label_preferences: Podešavanja + label_chronological_order: po hronološkom redosledu + label_reverse_chronological_order: po obrnutom hronološkom redosledu + label_planning: Planiranje + label_incoming_emails: Dolazne e-poruke + label_generate_key: Generisanje ključa + label_issue_watchers: Posmatrači + label_example: Primer + label_display: Prikaz + label_sort: Sortiranje + label_ascending: Rastući niz + label_descending: Opadajući niz + label_date_from_to: Od {{start}} do {{end}} + label_wiki_content_added: Wiki stranica je dodata + label_wiki_content_updated: Wiki stranica je ažurirana + label_group: Grupa + label_group_plural: Grupe + label_group_new: Nova grupa + label_time_entry_plural: Utrošeno vreme + label_version_sharing_none: Nije deljeno + label_version_sharing_descendants: Sa potprojektima + label_version_sharing_hierarchy: Sa hijerarhijom projekta + label_version_sharing_tree: Sa stablom projekta + label_version_sharing_system: Sa svim projektima + label_update_issue_done_ratios: Ažuriraj odnos rešenih problema + label_copy_source: Izvor + label_copy_target: Odredište + label_copy_same_as_target: Isto kao odredište + label_display_used_statuses_only: Prikazuj statuse korišćene samo od strane ovog praćenja + label_api_access_key: API pristupni ključ + label_missing_api_access_key: Nedostaje API pristupni ključ + label_api_access_key_created_on: "API pristupni ključ je kreiran pre {{value}}" + label_profile: Profil + label_subtask_plural: Podzadatak + label_project_copy_notifications: Pošalji e-poruku sa obaveštenjem prilikom kopiranja projekta + + button_login: Prijava + button_submit: Pošalji + button_save: Snimi + button_check_all: Uključi sve + button_uncheck_all: Isključi sve + button_delete: Izbriši + button_create: Kreiraj + button_create_and_continue: Kreiraj i nastavi + button_test: Test + button_edit: Izmeni + button_add: Dodaj + button_change: Promeni + button_apply: Primeni + button_clear: Obriši + button_lock: Zaključaj + button_unlock: Otključaj + button_download: Preuzmi + button_list: Spisak + button_view: Prikaži + button_move: Pomeri + button_move_and_follow: Pomeri i prati + button_back: Nazad + button_cancel: Poništi + button_activate: Aktiviraj + button_sort: Sortiraj + button_log_time: Evidentiraj vreme + button_rollback: Povratak na ovu verziju + button_watch: Prati + button_unwatch: Ne prati više + button_reply: Odgovori + button_archive: Arhiviraj + button_unarchive: Vrati iz arhive + button_reset: Poništi + button_rename: Preimenuj + button_change_password: Promeni lozinku + button_copy: Kopiraj + button_copy_and_follow: Kopiraj i prati + button_annotate: Pribeleži + button_update: Ažuriraj + button_configure: Podesi + button_quote: Pod navodnicima + button_duplicate: Dupliraj + button_show: Prikaži + + status_active: aktivni + status_registered: registrovani + status_locked: zaključani + + version_status_open: otvoren + version_status_locked: zaključan + version_status_closed: zatvoren + + field_active: Aktivan + + text_select_mail_notifications: Odaberi akcije za koje će obaveštenje biti poslato putem e-pošte. + text_regexp_info: npr. ^[A-Z0-9]+$ + text_min_max_length_info: 0 znači bez ograničenja + text_project_destroy_confirmation: Jeste li sigurni da želite da izbrišete ovaj projekat i sve pripadajuće podatke? + text_subprojects_destroy_warning: "Potprojekti: {{value}} će takođe biti izbrisan." + text_workflow_edit: Odaberite ulogu i praćenje za izmenu toka posla + text_are_you_sure: Jeste li sigurni? + text_journal_changed: "{{label}} promenjen od {{old}} u {{new}}" + text_journal_set_to: "{{label}} postavljen u {{value}}" + text_journal_deleted: "{{label}} izbrisano ({{old}})" + text_journal_added: "{{label}} {{value}} dodato" + text_tip_task_begin_day: zadatak počinje ovog dana + text_tip_task_end_day: zadatak se završava ovog dana + text_tip_task_begin_end_day: zadatak počinje i završava ovog dana + text_project_identifier_info: 'Dozvoljena su samo mala slova (a-š), brojevi i crtice.
    Jednom snimljen identifikator više se ne može promeniti.' + text_caracters_maximum: "Najviše {{count}} znak(ova)." + text_caracters_minimum: "Broj znakova mora biti najmanje {{count}}." + text_length_between: "Broj znakova mora biti između {{min}} i {{max}}." + text_tracker_no_workflow: Ovo praćenje nema definisan tok posla + text_unallowed_characters: Nedozvoljeni znakovi + text_comma_separated: Dozvoljene su višestruke vrednosti (odvojene zarezom). + text_line_separated: Dozvoljene su višestruke vrednosti (jedan red za svaku vrednost). + text_issues_ref_in_commit_messages: Referenciranje i popravljanje problema u izvršnim porukama + text_issue_added: "{{author}} je prijavio problem {{id}}." + text_issue_updated: "{{author}} je ažurirao problem {{id}}." + text_wiki_destroy_confirmation: Jeste li sigurni da želite da obrišete wiki i sav sadržaj? + text_issue_category_destroy_question: "Nekoliko problema ({{count}}) je dodeljeno ovoj kategoriji. Šta želite da uradite?" + text_issue_category_destroy_assignments: Ukloni dodeljene kategorije + text_issue_category_reassign_to: Dodeli ponovo probleme ovoj kategoriji + text_user_mail_option: "Za neizabrane projekte, dobićete samo obaveštenje o stvarima koje pratite ili ste uključeni (npr. problemi čiji ste vi autor ili zastupnik)." + text_no_configuration_data: "Uloge, praćenja, statusi problema i toka posla još uvek nisu podešeni.\nPreporučljivo je da učitate podrazumevano konfigurisanje. Izmena je moguća nakon prvog učitavanja." + text_load_default_configuration: Učitaj podrazumevano konfigurisanje + text_status_changed_by_changeset: "Primenjeno u skupu sa promenama {{value}}." + text_issues_destroy_confirmation: 'Jeste li sigurni da želite da izbrišete odabrane probleme?' + text_select_project_modules: 'Odaberite module koje želite omogućiti za ovaj projekat:' + text_default_administrator_account_changed: Podrazumevani administratorski nalog je promenjen + text_file_repository_writable: Fascikla priloženih datoteka je upisiva + text_plugin_assets_writable: Fascikla elemenata dodatnih komponenti je upisiva + text_rmagick_available: RMagick je dostupan (opciono) + text_destroy_time_entries_question: "{{hours}} sati je prijavljeno za ovaj problem koji želite izbrisati. Šta želite da uradite?" + text_destroy_time_entries: Izbriši prijavljene sate + text_assign_time_entries_to_project: Dodeli prijavljene sate projektu + text_reassign_time_entries: 'Dodeli ponovo prijavljene sate ovom problemu:' + text_user_wrote: "{{value}} je napisao:" + text_enumeration_destroy_question: "{{count}} objekat(a) je dodeljeno ovoj vrednosti." + text_enumeration_category_reassign_to: 'Dodeli ih ponovo ovoj vrednosti:' + text_email_delivery_not_configured: "Isporuka e-poruka nije konfigurisana i obaveštenja su onemogućena.\nPodesite vaš SMTP server u config/email.yml i pokrenite ponovo aplikaciju za njihovo omogućavanje." + text_repository_usernames_mapping: "Odaberite ili ažurirajte Redmine korisnike mapiranjem svakog korisničkog imena pronađenog u evidenciji spremišta.\nKorisnici sa istim Redmine imenom i imenom spremišta ili e-adresom su automatski mapirani." + text_diff_truncated: '... Ova razlika je isečena jer je dostignuta maksimalna veličina prikaza.' + text_custom_field_possible_values_info: 'Jedan red za svaku vrednost' + text_wiki_page_destroy_question: "Ova stranica ima {{descendants}} podređenih stranica i podstranica. Šta želite da uradite?" + text_wiki_page_nullify_children: "Zadrži podređene stranice kao korene stranice" + text_wiki_page_destroy_children: "Izbriši podređene stranice i sve njihove podstranice" + text_wiki_page_reassign_children: "Dodeli ponovo podređene stranice ovoj matičnoj stranici" + text_own_membership_delete_confirmation: "Nakon uklanjanja pojedinih ili svih vaših dozvola nećete više moći da uređujete ovaj projekat.\nŽelite li da nastavite?" + text_zoom_in: Uvećaj + text_zoom_out: Umanji + + default_role_manager: Menadžer + default_role_developer: Programer + default_role_reporter: Izveštač + default_tracker_bug: Greška + default_tracker_feature: Funkcionalnost + default_tracker_support: Podrška + default_issue_status_new: Novo + default_issue_status_in_progress: U toku + default_issue_status_resolved: Rešeno + default_issue_status_feedback: Povratna informacija + default_issue_status_closed: Zatvoreno + default_issue_status_rejected: Odbijeno + default_doc_category_user: Korisnička dokumentacija + default_doc_category_tech: Tehnička dokumentacija + default_priority_low: Nizak + default_priority_normal: Normalan + default_priority_high: Visok + default_priority_urgent: Hitno + default_priority_immediate: Neposredno + default_activity_design: Dizajn + default_activity_development: Razvoj + + enumeration_issue_priorities: Prioriteti problema + enumeration_doc_categories: Kategorije dokumenta + enumeration_activities: Aktivnosti (praćenje vremena) + enumeration_system_activity: Sistemska aktivnost + diff --git a/config/locales/sr.yml b/config/locales/sr.yml index f52d9e06..1bcd3616 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -10,60 +10,60 @@ sr: short: "%e %b" long: "%B %e, %Y" - day_names: [Nedelja, Ponedeljak, Utorak, Sreda, Četvrtak, Petak, Subota] - abbr_day_names: [Ned, Pon, Uto, Sre, Čet, Pet, Sub] + day_names: [недеља, понедељак, уторак, среда, четвртак, петак, субота] + abbr_day_names: [нед, пон, уто, сре, чет, пет, суб] # Don't forget the nil at the beginning; there's no such thing as a 0th month - month_names: [~, Januar, Februar, Mart, April, Maj, Jun, Jul, Avgust, Septembar, Oktobar, Novembar, Decembar] - abbr_month_names: [~, Jan, Feb, Mar, Apr, Maj, Jun, Jul, Avg, Sep, Okt, Nov, Dec] + month_names: [~, јануар, фебруар, март, април, мај, јун, јул, август, септембар, октобар, новембар, децембар] + abbr_month_names: [~, јан, феб, мар, апр, мај, јун, јул, авг, сеп, окт, нов, дец] # Used in date_select and datime_select. order: [ :day, :month, :year ] time: formats: - default: "%d.%m.%Y. u %H:%M" + default: "%d.%m.%Y. у %H:%M" time: "%H:%M" - short: "%d. %b u %H:%M" - long: "%d. %B %Y u %H:%M" + short: "%d. %b у %H:%M" + long: "%d. %B %Y у %H:%M" am: "am" pm: "pm" datetime: distance_in_words: - half_a_minute: "pola minuta" + half_a_minute: "пола минута" less_than_x_seconds: - one: "manje od jedne sekunde" - other: "manje od {{count}} sek." + one: "мање од једне секунде" + other: "мање од {{count}} сек." x_seconds: - one: "jedna sekunda" - other: "{{count}} sek." + one: "једна секунда" + other: "{{count}} сек." less_than_x_minutes: - one: "manje od minuta" - other: "manje od {{count}} min." + one: "мање од минута" + other: "мање од {{count}} мин." x_minutes: - one: "jedan minut" - other: "{{count}} min." + one: "један минут" + other: "{{count}} мин." about_x_hours: - one: "približno jedan sat" - other: "približno {{count}} sati" + one: "приближно један сат" + other: "приближно {{count}} сати" x_days: - one: "jedan dan" - other: "{{count}} dana" + one: "један дан" + other: "{{count}} дана" about_x_months: - one: "približno jedan mesec" - other: "približno {{count}} meseci" + one: "приближно један месец" + other: "приближно {{count}} месеци" x_months: - one: "jedan mesec" - other: "{{count}} meseci" + one: "један месец" + other: "{{count}} месеци" about_x_years: - one: "približno godinu dana" - other: "približno {{count}} god." + one: "приближно годину дана" + other: "приближно {{count}} год." over_x_years: - one: "preko godinu dana" - other: "preko {{count}} god." + one: "преко годину дана" + other: "преко {{count}} год." almost_x_years: - one: "skoro godinu dana" - other: "skoro {{count}} god." + one: "скоро годину дана" + other: "скоро {{count}} год." number: human: @@ -85,823 +85,823 @@ sr: # Used in array.to_sentence. support: array: - sentence_connector: "i" + sentence_connector: "и" skip_last_comma: false activerecord: errors: messages: - inclusion: "nije uključen u spisak" - exclusion: "je rezervisan" - invalid: "je neispravan" - confirmation: "potvrda ne odgovara" - accepted: "mora biti prihvaćen" - empty: "ne može biti prazno" - blank: "ne može biti prazno" - too_long: "je predugačka (maksimum znakova je {{count}})" - too_short: "je prekratka (minimum znakova je {{count}})" - wrong_length: "je pogrešne dužine (broj znakova mora biti {{count}})" - taken: "je već u upotrebi" - not_a_number: "nije broj" - not_a_date: "nije ispravan datum" - greater_than: "mora biti veći od {{count}}" - greater_than_or_equal_to: "mora biti veći ili jednak {{count}}" - equal_to: "mora biti jednak {{count}}" - less_than: "mora biti manji od {{count}}" - less_than_or_equal_to: "mora biti manji ili jednak {{count}}" - odd: "mora biti paran" - even: "mora biti neparan" - greater_than_start_date: "mora biti veći od početnog datuma" - not_same_project: "ne pripada istom projektu" - circular_dependency: "Ova veza će stvoriti kružnu referencu" + inclusion: "није укључен у списак" + exclusion: "је резервисан" + invalid: "је неисправан" + confirmation: "потврда не одговара" + accepted: "мора бити прихваћен" + empty: "не може бити празно" + blank: "не може бити празно" + too_long: "је предугачка (максимум знакова је {{count}})" + too_short: "је прекратка (минимум знакова је {{count}})" + wrong_length: "је погрешне дужине (број знакова мора бити {{count}})" + taken: "је већ у употреби" + not_a_number: "није број" + not_a_date: "није исправан датум" + greater_than: "мора бити већи од {{count}}" + greater_than_or_equal_to: "мора бити већи или једнак {{count}}" + equal_to: "мора бити једнак {{count}}" + less_than: "мора бити мањи од {{count}}" + less_than_or_equal_to: "мора бити мањи или једнак {{count}}" + odd: "мора бити паран" + even: "мора бити непаран" + greater_than_start_date: "мора бити већи од почетног датума" + not_same_project: "не припада истом пројекту" + circular_dependency: "Ова веза ће створити кружну референцу" + cant_link_an_issue_with_a_descendant: "Проблем не може бити повезан са једним од својих подзадатака" - actionview_instancetag_blank_option: Molim odaberite + actionview_instancetag_blank_option: Молим одаберите - general_text_No: 'Ne' - general_text_Yes: 'Da' - general_text_no: 'ne' - general_text_yes: 'da' - general_lang_name: 'Srpski' + general_text_No: 'Не' + general_text_Yes: 'Да' + general_text_no: 'не' + general_text_yes: 'да' + general_lang_name: 'Српски' general_csv_separator: ',' general_csv_decimal_separator: '.' general_csv_encoding: UTF-8 general_pdf_encoding: UTF-8 general_first_day_of_week: '1' - notice_account_updated: Nalog je uspešno ažuriran. - notice_account_invalid_creditentials: Neispravno korisničko ime ili lozinka. - notice_account_password_updated: Lozinka je uspešno ažurirana. - notice_account_wrong_password: Pogrešna lozinka - notice_account_register_done: Korisnički nalog je uspešno kreiran. Kliknite na link koji ste dobili u email poruci za aktivaciju. - notice_account_unknown_email: Nepoznat korisnik. - notice_can_t_change_password: Ovaj korisnički nalog za proveru identiteta koristi spoljni izvor. Nemoguće je promeniti lozinku. - notice_account_lost_email_sent: Poslata vam je email poruka sa uputstvom za izbor nove lozinke - notice_account_activated: Vaš korisnički nalog je aktiviran. Sada se možete prijaviti. - notice_successful_create: Uspešno kreiranje. - notice_successful_update: Uspešno ažuriranje. - notice_successful_delete: Uspešno brisanje. - notice_successful_connection: Uspešno povezivanje. - notice_file_not_found: Strana kojoj želite pristupiti ne postoji ili je uklonjena. - notice_locking_conflict: Podatak je ažuriran od strane drugog korisnika. - notice_not_authorized: Niste ovlašćeni za pristup ovoj strani. - notice_email_sent: "Poruka je poslata na adresu {{value}}" - notice_email_error: "Dogodila se greška prilikom slanja poruke ({{value}})" - notice_feeds_access_key_reseted: Vaš RSS pristupni ključ je poništen. - notice_api_access_key_reseted: Vaš API pristupni ključ je poništen. - notice_failed_to_save_issues: "Neuspešno snimanje {{count}} problema od {{total}} odabranih: {{ids}}." - notice_no_issue_selected: "Ni jedan problem nije odabran! Molim, odaberite problem koji želite da menjate." - notice_account_pending: "Vaš nalog je kreiran i čeka na odobrenje administratora." - notice_default_data_loaded: Podrazumevano konfigurisanje je uspešno učitano. - notice_unable_delete_version: Nemoguće je obrisati verziju. - notice_issue_done_ratios_updated: Odnos rešenih problema je ažuriran. + notice_account_updated: Налог је успешно ажуриран. + notice_account_invalid_creditentials: Неисправно корисничко име или лозинка. + notice_account_password_updated: Лозинка је успешно ажурирана. + notice_account_wrong_password: Погрешна лозинка + notice_account_register_done: Кориснички налог је успешно креиран. Кликните на линк који сте добили у е-поруци за активацију. + notice_account_unknown_email: Непознат корисник. + notice_can_t_change_password: Овај кориснички налог за потврду идентитета користи спољни извор. Немогуће је променити лозинку. + notice_account_lost_email_sent: Послата вам је е-порука са упутством за избор нове лозинке + notice_account_activated: Ваш кориснички налог је активиран. Сада се можете пријавити. + notice_successful_create: Успешно креирање. + notice_successful_update: Успешно ажурирање. + notice_successful_delete: Успешно брисање. + notice_successful_connection: Успешно повезивање. + notice_file_not_found: Страна којој желите приступити не постоји или је уклоњена. + notice_locking_conflict: Податак је ажуриран од стране другог корисника. + notice_not_authorized: Нисте овлашћени за приступ овој страни. + notice_email_sent: "E-порука је послата на {{value}}" + notice_email_error: "Догодила се грешка приликом слања е-поруке ({{value}})" + notice_feeds_access_key_reseted: Ваш RSS приступни кључ је поништен. + notice_api_access_key_reseted: Ваш API приступни кључ је поништен. + notice_failed_to_save_issues: "Неуспешно снимање {{count}} проблема од {{total}} одабраних: {{ids}}." + notice_failed_to_save_members: "Неуспешно снимање члана(ова): {{errors}}." + notice_no_issue_selected: "Ни један проблем није одабран! Молимо, одаберите проблем који желите да мењате." + notice_account_pending: "Ваш налог је креиран и чека на одобрење администратора." + notice_default_data_loaded: Подразумевано конфигурисање је успешно учитано. + notice_unable_delete_version: Верзију је немогуће избрисати. + notice_unable_delete_time_entry: Ставку евиденције времена је немогуће избрисати. + notice_issue_done_ratios_updated: Однос решених проблема је ажуриран. - error_can_t_load_default_data: "Podrazumevano konfigurisanje je nemoguće učitati: {{value}}" - error_scm_not_found: "Stavka ili ispravka nisu pronađene u spremištu." - error_scm_command_failed: "Greška se javila prilikom pokušaja pristupa spremištu: {{value}}" - error_scm_annotate: "Stavka ne postoji ili ne može biti označena." - error_issue_not_found_in_project: 'Problem nije pronađen ili ne pripada ovom projektu.' - error_no_tracker_in_project: 'Ni jedan tragač nije povezan sa ovim projektom. Molimo proverite podešavanja projekta.' - error_no_default_issue_status: 'Podrazumevani status problema nije definisan. Molimo proverite vaše konfigurisanje (Idite na "Administracija -> Statusi problema").' - error_can_not_reopen_issue_on_closed_version: 'Problem dodeljen zatvorenoj verziji ne može biti ponovo otvoren' - error_can_not_archive_project: Ovaj projekat se ne može arhivirati - error_issue_done_ratios_not_updated: "Odnos rešenih problema nije ažuriran." - error_workflow_copy_source: 'Molimo odaberite izvornog tragača ili ulogu' - error_workflow_copy_target: 'Molimo odaberite krajnjeg tragača i ulogu' + error_can_t_load_default_data: "Подразумевано конфигурисање је немогуће учитати: {{value}}" + error_scm_not_found: "Ставка или исправка нису пронађене у спремишту." + error_scm_command_failed: "Грешка се јавила приликом покушаја приступа спремишту: {{value}}" + error_scm_annotate: "Ставка не постоји или не може бити означена." + error_issue_not_found_in_project: 'Проблем није пронађен или не припада овом пројекту.' + error_no_tracker_in_project: 'Ни једно праћење није повезано са овим пројектом. Молимо проверите подешавања пројекта.' + error_no_default_issue_status: 'Подразумевани статус проблема није дефинисан. Молимо проверите ваше конфигурисање (идите на "Администрација -> Статуси проблема").' + error_can_not_delete_custom_field: Немогуће је избрисати прилагођено поље + error_can_not_delete_tracker: "Ово праћење садржи проблеме и не може бити обрисано." + error_can_not_remove_role: "Ова улога је у употреби и не може бити обрисана." + error_can_not_reopen_issue_on_closed_version: 'Проблем додељен затвореној верзији не може бити поново отворен' + error_can_not_archive_project: Овај пројекат се не може архивирати + error_issue_done_ratios_not_updated: "Однос решених проблема није ажуриран." + error_workflow_copy_source: 'Молимо одаберите изворно праћење или улогу' + error_workflow_copy_target: 'Молимо одаберите одредишно праћење и улогу' + error_unable_delete_issue_status: 'Статус проблема је немогуће обрисати' + error_unable_to_connect: "Повезивање са ({{value}}) је немогуће" + warning_attachments_not_saved: "{{count}} датотека не може бити снимљена." - warning_attachments_not_saved: "{{count}} datoteka ne može biti snimljeno." + mail_subject_lost_password: "Ваша {{value}} лозинка" + mail_body_lost_password: 'За промену ваше лозинке, кликните на следећи линк:' + mail_subject_register: "Активација вашег {{value}} налога" + mail_body_register: 'За активацију вашег налога, кликните на следећи линк:' + mail_body_account_information_external: "Ваш налог {{value}} можете користити за пријаву." + mail_body_account_information: Информације о вашем налогу + mail_subject_account_activation_request: "Захтев за активацију налога {{value}}" + mail_body_account_activation_request: "Нови корисник ({{value}}) је регистрован. Налог чека на ваше одобрење:" + mail_subject_reminder: "{{count}} проблема доспева наредних {{days}} дана" + mail_body_reminder: "{{count}} проблема додељених вама доспева у наредних {{days}} дана:" + mail_subject_wiki_content_added: "Wiki страница '{{page}}' је додата" + mail_body_wiki_content_added: "{{author}} је додао wiki страницу '{{page}}'." + mail_subject_wiki_content_updated: "Wiki страница '{{page}}' је ажурирана" + mail_body_wiki_content_updated: "{{author}} је ажурирао wiki страницу '{{page}}'." - mail_subject_lost_password: "Vaša {{value}} lozinka" - mail_body_lost_password: 'Za promenu vaše lozinke, kliknite na sledeći link:' - mail_subject_register: "Aktivacija vašeg {{value}} naloga" - mail_body_register: 'Za aktivaciju vašeg naloga, kliknite na sledeći link:' - mail_body_account_information_external: "Možete koristiti vaš nalog {{value}} za prijavu." - mail_body_account_information: Informacije o vašem nalogu - mail_subject_account_activation_request: "Zahtev za aktivaciju naloga {{value}}" - mail_body_account_activation_request: "Novi korisnik ({{value}}) je registrovan. Nalog čeka na vaše odobrenje:" - mail_subject_reminder: "{{count}} problema dospeva narednih {{days}} dana" - mail_body_reminder: "{{count}} problema dodeljenih vama dospeva u narednih {{days}} dana:" - mail_subject_wiki_content_added: "'{{page}}' wiki strana je dodato" - mail_body_wiki_content_added: "{{author}} je dodao '{{page}}' wiki strana." - mail_subject_wiki_content_updated: "'{{page}}' wiki strana je ažurirano" - mail_body_wiki_content_updated: "{{author}} je ažurirao '{{page}}' wiki strana." + gui_validation_error: једна грешка + gui_validation_error_plural: "{{count}} грешака" - gui_validation_error: jedna greška - gui_validation_error_plural: "{{count}} grešaka" - - field_name: Naziv - field_description: Opis - field_summary: Rezime - field_is_required: Obavezno - field_firstname: Ime - field_lastname: Prezime - field_mail: Email adresa - field_filename: Datoteka - field_filesize: Veličina - field_downloads: Preuzimanja - field_author: Autor - field_created_on: Kreirano - field_updated_on: Ažurirano - field_field_format: Format - field_is_for_all: Za sve projekte - field_possible_values: Moguće vrednosti - field_regexp: Regularan izraz - field_min_length: Minimalna dužina - field_max_length: Maksimalna dužina - field_value: Vrednost - field_category: Kategorija - field_title: Naslov - field_project: Projekat - field_issue: Problem - field_status: Status - field_notes: Beleške - field_is_closed: Zatvoren problem - field_is_default: Podrazumevana vrednost - field_tracker: Tragač - field_subject: Predmet - field_due_date: Krajnji rok - field_assigned_to: Dodeljeno - field_priority: Prioritet - field_fixed_version: Odredišna verzija - field_user: Korisnik - field_role: Uloga - field_homepage: Početna strana - field_is_public: Javno - field_parent: Potprojekat od - field_is_in_roadmap: Problemi prikazani u planu rada - field_login: Korisničko ime - field_mail_notification: Email obaveštenja - field_admin: Administrator - field_last_login_on: Poslednje povezivanje - field_language: Jezik - field_effective_date: Datum - field_password: Lozinka - field_new_password: Nova lozinka - field_password_confirmation: Potvrda lozinke - field_version: Verzija - field_type: Tip - field_host: Glavni računar - field_port: Priključak - field_account: Korisnički nalog - field_base_dn: Bazni DN - field_attr_login: Atribut prijavljivanja - field_attr_firstname: Atribut imena - field_attr_lastname: Atribut prezimena - field_attr_mail: Atribut email adrese - field_onthefly: Kreiranje korisnika u toku rada - field_start_date: Početak - field_done_ratio: % urađeno - field_auth_source: Režim provere identiteta - field_hide_mail: Sakrij moju email adresu - field_comments: Komentar + field_name: Назив + field_description: Опис + field_summary: Резиме + field_is_required: Обавезно + field_firstname: Име + field_lastname: Презиме + field_mail: Е-адреса + field_filename: Датотека + field_filesize: Величина + field_downloads: Преузимања + field_author: Аутор + field_created_on: Креирано + field_updated_on: Ажурирано + field_field_format: Формат + field_is_for_all: За све пројекте + field_possible_values: Могуће вредности + field_regexp: Регуларан израз + field_min_length: Минимална дужина + field_max_length: Максимална дужина + field_value: Вредност + field_category: Категорија + field_title: Наслов + field_project: Пројекат + field_issue: Проблем + field_status: Статус + field_notes: Белешке + field_is_closed: Затворен проблем + field_is_default: Подразумевана вредност + field_tracker: Праћење + field_subject: Предмет + field_due_date: Крајњи рок + field_assigned_to: Додељено + field_priority: Приоритет + field_fixed_version: Одредишна верзија + field_user: Корисник + field_principal: Главни + field_role: Улога + field_homepage: Почетна страница + field_is_public: Јавно објављивање + field_parent: Потпројекат од + field_is_in_roadmap: Проблеми приказани у плану рада + field_login: Корисничко име + field_mail_notification: Обавештења путем е-поште + field_admin: Администратор + field_last_login_on: Последње повезивање + field_language: Језик + field_effective_date: Датум + field_password: Лозинка + field_new_password: Нова лозинка + field_password_confirmation: Потврда лозинке + field_version: Верзија + field_type: Тип + field_host: Главни рачунар + field_port: Порт + field_account: Кориснички налог + field_base_dn: Базни DN + field_attr_login: Атрибут пријављивања + field_attr_firstname: Атрибут имена + field_attr_lastname: Атрибут презимена + field_attr_mail: Атрибут е-адресе + field_onthefly: Креирање корисника у току рада + field_start_date: Почетак + field_done_ratio: % урађено + field_auth_source: Режим потврде идентитета + field_hide_mail: Сакриј моју е-адресу + field_comments: Коментар field_url: URL - field_start_page: Početna strana - field_subproject: Potprojekat - field_hours: sati - field_activity: Aktivnost - field_spent_on: Datum - field_identifier: Identifikator - field_is_filter: Upotrebi kao filter - field_issue_to: Povezani problemi - field_delay: Kašnjenje - field_assignable: Problem može biti dodeljen ovoj ulozi - field_redirect_existing_links: Preusmeri postojeće veze - field_estimated_hours: Proteklo vreme - field_column_names: Kolone - field_time_zone: Vremenska zona - field_searchable: Pretraživa - field_default_value: Podrazumevana vrednost - field_comments_sorting: Prikaži komentare - field_parent_title: Matična strana - field_editable: Izmeljivo - field_watcher: Posmatrač + field_start_page: Почетна страница + field_subproject: Потпројекат + field_hours: сати + field_activity: Активност + field_spent_on: Датум + field_identifier: Идентификатор + field_is_filter: Употреби као филтер + field_issue_to: Сродни проблеми + field_delay: Кашњење + field_assignable: Проблем може бити додељен овој улози + field_redirect_existing_links: Преусмери постојеће везе + field_estimated_hours: Протекло време + field_column_names: Колоне + field_time_zone: Временска зона + field_searchable: Може да се претражује + field_default_value: Подразумевана вредност + field_comments_sorting: Прикажи коментаре + field_parent_title: Матична страница + field_editable: Изменљиво + field_watcher: Посматрач field_identity_url: OpenID URL - field_content: Sadržaj - field_group_by: Grupiši rezultate po - field_sharing: Deljenje + field_content: Садржај + field_group_by: Груписање резултата по + field_sharing: Дељење + field_parent_issue: Матични задатак - setting_app_title: Naslov aplikacije - setting_app_subtitle: Podnaslov aplikacije - setting_welcome_text: Tekst dobrodošlice - setting_default_language: Podrazumevani jezik - setting_login_required: Obavezna provera identiteta - setting_self_registration: Samoregistracija - setting_attachment_max_size: Maks. veličina priložene datoteke - setting_issues_export_limit: Ograničenje izvoza problema - setting_mail_from: Email adresa emisije - setting_bcc_recipients: Primaoci nevidljive kopije poruke (bcc) - setting_plain_text_mail: Poruka sa čistim tekstom (bez HTML-a) - setting_host_name: Putanja i naziv glavnog računara - setting_text_formatting: Oblikovanje teksta - setting_wiki_compression: Kompresija Wiki istorije - setting_feeds_limit: Ograničenje sadržaja izvora vesti - setting_default_projects_public: Novi projekti su javni ako se drugačije ne navede - setting_autofetch_changesets: Izvršavanje automatskog preuzimanja - setting_sys_api_enabled: Omogući WS za upravljanje spremištem - setting_commit_ref_keywords: Referenciranje ključnih reči - setting_commit_fix_keywords: Popravljanje ključnih reči - setting_autologin: Automatska prijava - setting_date_format: Format datuma - setting_time_format: Format vremena - setting_cross_project_issue_relations: Dozvoli relacije problema iz unakrsnih projekata - setting_issue_list_default_columns: Podrazumevane kolone prikazane na spisku problema - setting_repositories_encodings: Kodiranje spremišta - setting_commit_logs_encoding: Kodiranje izvršnih poruka - setting_emails_footer: Podnožje email poruke - setting_protocol: Protokol - setting_per_page_options: Opcije prikaza objekata po strani - setting_user_format: Format prikaza korisnika - setting_activity_days_default: Broj dana prikazanih na projektnoj aktivnosti - setting_display_subprojects_issues: Prikazuj probleme iz potprojekata na glavnom projektu ukoliko nije drugačije navedeno - setting_enabled_scm: Omogući SCM - setting_mail_handler_body_delimiters: "Skrati poruku nakon jedne od ovih linija" - setting_mail_handler_api_enabled: Omogući WS dolazne poruke - setting_mail_handler_api_key: API ključ - setting_sequential_project_identifiers: Generisanje sekvencijalnog imena projekta - setting_gravatar_enabled: Koristi Gravatar korisničke ikone - setting_gravatar_default: Podrazumevana Gravatar slika - setting_diff_max_lines_displayed: Maks. broj prikazanih različitih linija - setting_file_max_size_displayed: Maks. veličina tekstualnih datoteka prikazanih unutra - setting_repository_log_display_limit: Maks. broj revizija prikazan u datoteci za evidenciju - setting_openid: Dozvoli OpenID prijavu i registraciju - setting_password_min_length: Minimalna dužina lozinke - setting_new_project_user_role_id: Uloga dodeljena korisniku (koji nije administrator), kreatoru projekta - setting_default_projects_modules: Podrazumevano omogućeni moduli za nove projekte - setting_issue_done_ratio: Izračunaj odnos rešenih problema - setting_issue_done_ratio_issue_field: koristeći polje problema - setting_issue_done_ratio_issue_status: koristeći status problema - setting_start_of_week: Prvi dan u sedmici - setting_rest_api_enabled: Omogući REST web usluge - setting_cache_formatted_text: Keširaj obrađen tekst + setting_app_title: Наслов апликације + setting_app_subtitle: Поднаслов апликације + setting_welcome_text: Текст добродошлице + setting_default_language: Подразумевани језик + setting_login_required: Обавезна потврда идентитета + setting_self_registration: Саморегистрација + setting_attachment_max_size: Макс. величина приложене датотеке + setting_issues_export_limit: Ограничење извоза „проблема“ + setting_mail_from: Е-адреса пошиљаоца + setting_bcc_recipients: Примаоци „Bcc“ копије + setting_plain_text_mail: Порука са чистим текстом (без HTML-а) + setting_host_name: Путања и назив главног рачунара + setting_text_formatting: Обликовање текста + setting_wiki_compression: Компресија Wiki историје + setting_feeds_limit: Ограничење садржаја извора вести + setting_default_projects_public: Подразумева се јавно приказивање нових пројеката + setting_autofetch_changesets: Извршавање аутоматског преузимања + setting_sys_api_enabled: Омогућавање WS за управљање спремиштем + setting_commit_ref_keywords: Референцирање кључних речи + setting_commit_fix_keywords: Поправљање кључних речи + setting_autologin: Аутоматска пријава + setting_date_format: Формат датума + setting_time_format: Формат времена + setting_cross_project_issue_relations: Дозволи повезивање проблема из унакрсних пројеката + setting_issue_list_default_columns: Подразумеване колоне приказане на списку проблема + setting_repositories_encodings: Кодирање спремишта + setting_commit_logs_encoding: Кодирање извршних порука + setting_emails_footer: Подножје странице е-поруке + setting_protocol: Протокол + setting_per_page_options: Опције приказа објеката по страници + setting_user_format: Формат приказа корисника + setting_activity_days_default: Број дана приказаних на пројектној активности + setting_display_subprojects_issues: Приказуј проблеме из потпројеката на главном пројекту, уколико није другачије наведено + setting_enabled_scm: Омогућавање SCM + setting_mail_handler_body_delimiters: "Скраћивање е-поруке након једне од ових линија" + setting_mail_handler_api_enabled: Омогућавање WS долазне е-поруке + setting_mail_handler_api_key: API кључ + setting_sequential_project_identifiers: Генерисање секвенцијалног имена пројекта + setting_gravatar_enabled: Користи Gravatar корисничке иконе + setting_gravatar_default: Подразумевана Gravatar слика + setting_diff_max_lines_displayed: Макс. број приказаних различитих линија + setting_file_max_size_displayed: Макс. величина текст. датотека приказаних уметнуто + setting_repository_log_display_limit: Макс. број ревизија приказаних у датотеци за евиденцију + setting_openid: Дозволи OpenID пријаву и регистрацију + setting_password_min_length: Минимална дужина лозинке + setting_new_project_user_role_id: Креатору пројекта (који није администратор) додељује је улога + setting_default_projects_modules: Подразумевано омогућени модули за нове пројекте + setting_issue_done_ratio: Израчунај однос решених проблема + setting_issue_done_ratio_issue_field: користећи поље проблема + setting_issue_done_ratio_issue_status: користећи статус проблема + setting_start_of_week: Први дан у седмици + setting_rest_api_enabled: Омогући REST web услуге + setting_cache_formatted_text: Кеширање обрађеног текста - permission_add_project: Kreiranje projekta - permission_add_subprojects: Kreiranje potpojekta - permission_edit_project: Izmena projekata - permission_select_project_modules: Odabiranje modula projekta - permission_manage_members: Upravljanje članovima - permission_manage_project_activities: Upravljanje projektnim aktivnostima - permission_manage_versions: Upravljanje verzijama - permission_manage_categories: Upravljanje kategorijama problema - permission_view_issues: Pregled problema - permission_add_issues: Dodavanje problema - permission_edit_issues: Izmena problema - permission_manage_issue_relations: Upravljanje relacijama između problema - permission_add_issue_notes: Dodavanje beleški - permission_edit_issue_notes: Izmena beleški - permission_edit_own_issue_notes: Izmena sopstvenih beleški - permission_move_issues: Pomeranje problema - permission_delete_issues: Brisanje problema - permission_manage_public_queries: Upravljanje javnim upitima - permission_save_queries: Snimanje upita - permission_view_gantt: Pregledanje Gantovog dijagrama - permission_view_calendar: Pregledanje kalendara - permission_view_issue_watchers: Pregledanje spiska posmatrača - permission_add_issue_watchers: Dodavanje posmatrača - permission_delete_issue_watchers: Brisanje posmatrača - permission_log_time: Beleženje utrošenog vremena - permission_view_time_entries: Pregledanje utrošenog vremena - permission_edit_time_entries: Izmena utrošenog vremena - permission_edit_own_time_entries: Izmena sopstvenog utrošenog vremena - permission_manage_news: Upravljanje vestima - permission_comment_news: Komentarisanje vesti - permission_manage_documents: Upravljanje dokumentima - permission_view_documents: Pregledanje dokumenata - permission_manage_files: Upravljanje datotekama - permission_view_files: Pregledanje datoteka - permission_manage_wiki: Upravljanje wiki stranama - permission_rename_wiki_pages: Promena imena wiki stranama - permission_delete_wiki_pages: Brisanje wiki strana - permission_view_wiki_pages: Pregledanje wiki strana - permission_view_wiki_edits: Pregledanje wiki istorije - permission_edit_wiki_pages: Izmena wiki strana - permission_delete_wiki_pages_attachments: Brisanje priloženih datoteka - permission_protect_wiki_pages: Zaštita wiki strana - permission_manage_repository: Upravljanje spremištem - permission_browse_repository: Pregledanje spremišta - permission_view_changesets: Pregledanje skupa promena - permission_commit_access: Potvrda pristupa - permission_manage_boards: Upravljanje forumima - permission_view_messages: Pregledanje poruka - permission_add_messages: Slanje poruka - permission_edit_messages: Izmena poruka - permission_edit_own_messages: Izmena sopstvenih poruka - permission_delete_messages: Brisanje poruka - permission_delete_own_messages: Brisanje sopstvenih poruka - permission_export_wiki_pages: Izvoz wiki strana + permission_add_project: Креирање пројекта + permission_add_subprojects: Креирање потпојекта + permission_edit_project: Измена пројеката + permission_select_project_modules: Одабирање модула пројекта + permission_manage_members: Управљање члановима + permission_manage_project_activities: Управљање пројектним активностима + permission_manage_versions: Управљање верзијама + permission_manage_categories: Управљање категоријама проблема + permission_view_issues: Преглед проблема + permission_add_issues: Додавање проблема + permission_edit_issues: Измена проблема + permission_manage_issue_relations: Управљање везама између проблема + permission_add_issue_notes: Додавање белешки + permission_edit_issue_notes: Измена белешки + permission_edit_own_issue_notes: Измена сопствених белешки + permission_move_issues: Померање проблема + permission_delete_issues: Брисање проблема + permission_manage_public_queries: Управљање јавним упитима + permission_save_queries: Снимање упита + permission_view_gantt: Прегледање Гантовог дијаграма + permission_view_calendar: Прегледање календара + permission_view_issue_watchers: Прегледање списка посматрача + permission_add_issue_watchers: Додавање посматрача + permission_delete_issue_watchers: Брисање посматрача + permission_log_time: Бележење утрошеног времена + permission_view_time_entries: Прегледање утрошеног времена + permission_edit_time_entries: Измена утрошеног времена + permission_edit_own_time_entries: Измена сопственог утрошеног времена + permission_manage_news: Управљање вестима + permission_comment_news: Коментарисање вести + permission_manage_documents: Управљање документима + permission_view_documents: Прегледање докумената + permission_manage_files: Управљање датотекама + permission_view_files: Прегледање датотека + permission_manage_wiki: Управљање wiki страницама + permission_rename_wiki_pages: Промена имена wiki страницама + permission_delete_wiki_pages: Брисање wiki страница + permission_view_wiki_pages: Прегледање wiki страница + permission_view_wiki_edits: Прегледање wiki историје + permission_edit_wiki_pages: Измена wiki страница + permission_delete_wiki_pages_attachments: Брисање приложених датотека + permission_protect_wiki_pages: Заштита wiki страница + permission_manage_repository: Управљање спремиштем + permission_browse_repository: Прегледање спремишта + permission_view_changesets: Прегледање скупа промена + permission_commit_access: Потврда приступа + permission_manage_boards: Управљање форумима + permission_view_messages: Прегледање порука + permission_add_messages: Слање порука + permission_edit_messages: Измена порука + permission_edit_own_messages: Измена сопствених порука + permission_delete_messages: Брисање порука + permission_delete_own_messages: Брисање сопствених порука + permission_export_wiki_pages: Извоз wiki страница + permission_manage_subtasks: Управљање подзадацима - project_module_issue_tracking: Traganje za problemom - project_module_time_tracking: Vreme traganja - project_module_news: Vesti - project_module_documents: Dokumenta - project_module_files: Datoteke + project_module_issue_tracking: Праћење проблема + project_module_time_tracking: Праћење времена + project_module_news: Вести + project_module_documents: Документи + project_module_files: Датотеке project_module_wiki: Wiki - project_module_repository: Spremište - project_module_boards: Forumi + project_module_repository: Спремиште + project_module_boards: Форуми - label_user: Korisnik - label_user_plural: Korisnici - label_user_new: Novi korisnik - label_user_anonymous: Anoniman - label_project: Projekat - label_project_new: Novi projekat - label_project_plural: Projekti + label_user: Корисник + label_user_plural: Корисници + label_user_new: Нови корисник + label_user_anonymous: Анониман + label_project: Пројекат + label_project_new: Нови пројекат + label_project_plural: Пројекти label_x_projects: - zero: nema projekata - one: jedan projekat - other: "{{count}} projekata" - label_project_all: Svi projekti - label_project_latest: Poslednji projekti - label_issue: Problem - label_issue_new: Novi problem - label_issue_plural: Problemi - label_issue_view_all: Prikaz svih problema - label_issues_by: "Problemi - {{value}}" - label_issue_added: Problem je dodat - label_issue_updated: Problem je ažuriran - label_document: Dokument - label_document_new: Novi dokument - label_document_plural: Dokumenti - label_document_added: Dokument je dodat - label_role: Uloga - label_role_plural: Uloge - label_role_new: Nova uloga - label_role_and_permissions: Uloge i dozvole - label_member: Član - label_member_new: Novi član - label_member_plural: Članovi - label_tracker: Tragač - label_tracker_plural: Tragači - label_tracker_new: Novi tragač - label_workflow: Tok rada - label_issue_status: Status problema - label_issue_status_plural: Statusi problema - label_issue_status_new: Novi status - label_issue_category: Kategorija problema - label_issue_category_plural: Kategorije problema - label_issue_category_new: Nova kategorija - label_custom_field: Prilagođeno polje - label_custom_field_plural: Prilagođena polja - label_custom_field_new: Novo prilagođeno polje - label_enumerations: Nabrojiva lista - label_enumeration_new: Nova vrednost - label_information: Informacija - label_information_plural: Informacije - label_please_login: Molimo, prijavite se - label_register: Registracija - label_login_with_open_id_option: ili prijava sa OpenID - label_password_lost: Izgubljena lozinka - label_home: Početak - label_my_page: Moja strana - label_my_account: Moj nalog - label_my_projects: Moji projekti - label_administration: Administracija - label_login: Prijava - label_logout: Odjava - label_help: Pomoć - label_reported_issues: Prijavljeni problemi - label_assigned_to_me_issues: Problemi dodoljeni meni - label_last_login: Poslednje povezivanje - label_registered_on: Registrovan - label_activity: Aktivnost - label_overall_activity: Obuhvatna aktivnost - label_user_activity: "Aktivnost korisnika {{value}}" - label_new: Novo - label_logged_as: Prijavljeni ste kao - label_environment: Okruženje - label_authentication: Provera identiteta - label_auth_source: Režim provere identiteta - label_auth_source_new: Novi režim provere identiteta - label_auth_source_plural: Režimi provere identiteta - label_subproject_plural: Potprojekti - label_subproject_new: Novi potprojekat - label_and_its_subprojects: "{{value}} i njegovi potprojekti" - label_min_max_length: Min. - Maks. dužina - label_list: Spisak - label_date: Datum - label_integer: Ceo broj - label_float: Sa pokretnim zarezom - label_boolean: Logički operator - label_string: Tekst - label_text: Dugi tekst - label_attribute: Osobina - label_attribute_plural: Osobine - label_download: "{{count}} preuzimanje" - label_download_plural: "{{count}} preuzimanja" - label_no_data: Nema podataka za prikazivanje - label_change_status: Promena statusa - label_history: Istorija - label_attachment: Datoteka - label_attachment_new: Nova datoteka - label_attachment_delete: Brisanje datoteke - label_attachment_plural: Datoteke - label_file_added: Datoteka dodata - label_report: Izveštaj - label_report_plural: Izveštaji - label_news: Vesti - label_news_new: Dodavanje vesti - label_news_plural: Vesti - label_news_latest: Poslednje vesti - label_news_view_all: Prikaz svih vesti - label_news_added: Vesti dodato - label_settings: Podešavanja - label_overview: Pregled - label_version: Verzija - label_version_new: Nova verzija - label_version_plural: Verzije - label_close_versions: Zatvori završene verzije - label_confirmation: Potvrda - label_export_to: 'Takođe dostupno i u varijanti:' - label_read: Čitanje... - label_public_projects: Javni projekti - label_open_issues: otvoren - label_open_issues_plural: otvorenih - label_closed_issues: zatvoren - label_closed_issues_plural: zatvorenih + zero: нема пројеката + one: један пројекат + other: "{{count}} пројеката" + label_project_all: Сви пројекти + label_project_latest: Последњи пројекти + label_issue: Проблем + label_issue_new: Нови проблем + label_issue_plural: Проблеми + label_issue_view_all: Приказ свих проблема + label_issues_by: "Проблеми ({{value}})" + label_issue_added: Проблем је додат + label_issue_updated: Проблем је ажуриран + label_document: Документ + label_document_new: Нови документ + label_document_plural: Документи + label_document_added: Документ је додат + label_role: Улога + label_role_plural: Улоге + label_role_new: Нова улога + label_role_and_permissions: Улоге и дозволе + label_member: Члан + label_member_new: Нови члан + label_member_plural: Чланови + label_tracker: Праћење + label_tracker_plural: Праћења + label_tracker_new: Ново праћење + label_workflow: Ток посла + label_issue_status: Статус проблема + label_issue_status_plural: Статуси проблема + label_issue_status_new: Нови статус + label_issue_category: Категорија проблема + label_issue_category_plural: Категорије проблема + label_issue_category_new: Нова категорија + label_custom_field: Прилагођено поље + label_custom_field_plural: Прилагођена поља + label_custom_field_new: Ново прилагођено поље + label_enumerations: Набројива листа + label_enumeration_new: Нова вредност + label_information: Информација + label_information_plural: Информације + label_please_login: Молимо, пријавите се + label_register: Регистрација + label_login_with_open_id_option: или пријава са OpenID + label_password_lost: Изгубљена лозинка + label_home: Почетак + label_my_page: Моја страница + label_my_account: Мој налог + label_my_projects: Моји пројекти + label_my_page_block: My page block + label_administration: Администрација + label_login: Пријава + label_logout: Одјава + label_help: Помоћ + label_reported_issues: Пријављени проблеми + label_assigned_to_me_issues: Проблеми додељени мени + label_last_login: Последње повезивање + label_registered_on: Регистрован + label_activity: Активност + label_overall_activity: Целокупна активност + label_user_activity: "Активност корисника {{value}}" + label_new: Ново + label_logged_as: Пријављени сте као + label_environment: Окружење + label_authentication: Потврда идентитета + label_auth_source: Режим потврде идентитета + label_auth_source_new: Нови режим потврде идентитета + label_auth_source_plural: Режими потврде идентитета + label_subproject_plural: Потпројекти + label_subproject_new: Нови потпројекат + label_and_its_subprojects: "{{value}} и његови потпројекти" + label_min_max_length: Мин. - Макс. дужина + label_list: Списак + label_date: Датум + label_integer: Цео број + label_float: Са покретним зарезом + label_boolean: Логички оператор + label_string: Текст + label_text: Дуги текст + label_attribute: Особина + label_attribute_plural: Особине + label_download: "{{count}} преузимање" + label_download_plural: "{{count}} преузимања" + label_no_data: Нема података за приказивање + label_change_status: Промена статуса + label_history: Историја + label_attachment: Датотека + label_attachment_new: Нова датотека + label_attachment_delete: Брисање датотеке + label_attachment_plural: Датотеке + label_file_added: Датотека је додата + label_report: Извештај + label_report_plural: Извештаји + label_news: Вести + label_news_new: Додавање вести + label_news_plural: Вести + label_news_latest: Последње вести + label_news_view_all: Приказ свих вести + label_news_added: Вести су додате + label_settings: Подешавања + label_overview: Преглед + label_version: Верзија + label_version_new: Нова верзија + label_version_plural: Верзије + label_close_versions: Затвори завршене верзије + label_confirmation: Потврда + label_export_to: 'Такође доступно и у варијанти:' + label_read: Читање... + label_public_projects: Јавни пројекти + label_open_issues: отворен + label_open_issues_plural: отворених + label_closed_issues: затворен + label_closed_issues_plural: затворених label_x_open_issues_abbr_on_total: - zero: 0 otvorenih / {{total}} - one: 1 otvoren / {{total}} - other: "{{count}} otvorenih / {{total}}" + zero: 0 отворених / {{total}} + one: 1 отворен / {{total}} + other: "{{count}} отворених / {{total}}" label_x_open_issues_abbr: - zero: 0 otvorenih - one: 1 otvoren - other: "{{count}} otvorenih" + zero: 0 отворених + one: 1 отворен + other: "{{count}} отворених" label_x_closed_issues_abbr: - zero: 0 zatvorenih - one: 1 zatvoren - other: "{{count}} zatvorenih" - label_total: Ukupno - label_permissions: Ovlašćenja - label_current_status: Trenutni status - label_new_statuses_allowed: Novi statusi dozvoljeni - label_all: svi - label_none: nijedan - label_nobody: nikome - label_next: Sledeće - label_previous: Prethodno - label_used_by: Koristio - label_details: Detalji - label_add_note: Dodaj belešku - label_per_page: Po strani - label_calendar: Kalendar - label_months_from: meseci od - label_gantt: Gantov dijagram - label_internal: Unutrašlji - label_last_changes: "poslednjih {{count}} promena" - label_change_view_all: Prikaži sve promene - label_personalize_page: Personalizujte ovu stranu - label_comment: Komentar - label_comment_plural: Komentari + zero: 0 затворених + one: 1 затворен + other: "{{count}} затворених" + label_total: Укупно + label_permissions: Дозволе + label_current_status: Тренутни статус + label_new_statuses_allowed: Нови статуси дозвољени + label_all: сви + label_none: ниједан + label_nobody: никоме + label_next: Следеће + label_previous: Претходно + label_used_by: Користио + label_details: Детаљи + label_add_note: Додај белешку + label_per_page: По страни + label_calendar: Календар + label_months_from: месеци од + label_gantt: Гантов дијаграм + label_internal: Унутрашњи + label_last_changes: "последњих {{count}} промена" + label_change_view_all: Прикажи све промене + label_personalize_page: Персонализуј ову страну + label_comment: Коментар + label_comment_plural: Коментари label_x_comments: - zero: bez komentara - one: jedan komentar - other: "{{count}} komentara" - label_comment_add: Dodaj komentar - label_comment_added: Komentar dodat - label_comment_delete: Obriši komentare - label_query: Prilagođen upit - label_query_plural: Prilagođeni upiti - label_query_new: Novi upit - label_filter_add: Dodaj filter - label_filter_plural: Filteri - label_equals: je - label_not_equals: nije - label_in_less_than: manje od - label_in_more_than: više od + zero: без коментара + one: један коментар + other: "{{count}} коментара" + label_comment_add: Додај коментар + label_comment_added: Коментар додат + label_comment_delete: Обриши коментаре + label_query: Прилагођен упит + label_query_plural: Прилагођени упити + label_query_new: Нови упит + label_filter_add: Додавање филтера + label_filter_plural: Филтери + label_equals: је + label_not_equals: није + label_in_less_than: мање од + label_in_more_than: више од label_greater_or_equal: '>=' label_less_or_equal: '<=' - label_in: u - label_today: danas - label_all_time: sve vreme - label_yesterday: juče - label_this_week: ove sedmice - label_last_week: poslednje sedmice - label_last_n_days: "poslednjih {{count}} dana" - label_this_month: ovog meseca - label_last_month: poslednjeg meseca - label_this_year: ove godine - label_date_range: Vremenski period - label_less_than_ago: pre manje od nekoliko dana - label_more_than_ago: pre više od nekoliko dana - label_ago: pre nekoliko dana - label_contains: sadrži - label_not_contains: ne sadrži - label_day_plural: dana - label_repository: Spremište - label_repository_plural: Spremišta - label_browse: Pregledanje - label_modification: "{{count}} promena" - label_modification_plural: "{{count}} promena" - label_branch: Grana - label_tag: Oznaka - label_revision: Revizija - label_revision_plural: Revizije - label_revision_id: "Revizija {{value}}" - label_associated_revisions: Pridružene revizije - label_added: dodato - label_modified: promenjeno - label_copied: kopirano - label_renamed: preimenovano - label_deleted: obrisano - label_latest_revision: Poslednja revizija - label_latest_revision_plural: Poslednje revizije - label_view_revisions: Pregled revizija - label_view_all_revisions: Pregled svih revizija - label_max_size: Maksimalna veličina - label_sort_highest: Premesti na vrh - label_sort_higher: Premesti na gore - label_sort_lower: Premesti na dole - label_sort_lowest: Premesti na dno - label_roadmap: Plan rada - label_roadmap_due_in: "Dospeva {{value}}" - label_roadmap_overdue: "{{value}} najkasnije" - label_roadmap_no_issues: Nema problema za ovu verziju - label_search: Pretraga - label_result_plural: Rezultati - label_all_words: Sve reči + label_in: у + label_today: данас + label_all_time: све време + label_yesterday: јуче + label_this_week: ове седмице + label_last_week: последње седмице + label_last_n_days: "последњих {{count}} дана" + label_this_month: овог месеца + label_last_month: последњег месеца + label_this_year: ове године + label_date_range: Временски период + label_less_than_ago: пре мање од неколико дана + label_more_than_ago: пре више од неколико дана + label_ago: пре неколико дана + label_contains: садржи + label_not_contains: не садржи + label_day_plural: дана + label_repository: Спремиште + label_repository_plural: Спремишта + label_browse: Прегледање + label_modification: "{{count}} промена" + label_modification_plural: "{{count}} промена" + label_branch: Грана + label_tag: Ознака + label_revision: Ревизија + label_revision_plural: Ревизије + label_revision_id: "Ревизија {{value}}" + label_associated_revisions: Придружене ревизије + label_added: додато + label_modified: промењено + label_copied: копирано + label_renamed: преименовано + label_deleted: избрисано + label_latest_revision: Последња ревизија + label_latest_revision_plural: Последње ревизије + label_view_revisions: Преглед ревизија + label_view_all_revisions: Преглед свих ревизија + label_max_size: Максимална величина + label_sort_highest: Премештање на врх + label_sort_higher: Премештање на горе + label_sort_lower: Премештање на доле + label_sort_lowest: Премештање на дно + label_roadmap: План рада + label_roadmap_due_in: "Доспева {{value}}" + label_roadmap_overdue: "{{value}} најкасније" + label_roadmap_no_issues: Нема проблема за ову верзију + label_search: Претрага + label_result_plural: Резултати + label_all_words: Све речи label_wiki: Wiki - label_wiki_edit: Wiki izmena - label_wiki_edit_plural: Wiki izmene - label_wiki_page: Wiki strana - label_wiki_page_plural: Wiki strane - label_index_by_title: Indeksiranje po naslovu - label_index_by_date: Indeksiranje po datumu - label_current_version: Trenutna verzija - label_preview: Pregled - label_feed_plural: Izvori vesti - label_changes_details: Detalji svih promena - label_issue_tracking: Praćenje problema - label_spent_time: Utrošeno vreme - label_f_hour: "{{value}} sat" - label_f_hour_plural: "{{value}} sati" - label_time_tracking: Vreme praćenja - label_change_plural: Promene - label_statistics: Statistika - label_commits_per_month: Potvrda mesečno - label_commits_per_author: Potvrda po autoru - label_view_diff: Pogledaj razlike - label_diff_inline: unutra - label_diff_side_by_side: uporedo - label_options: Opcije - label_copy_workflow_from: Kopiraj tok rada od - label_permissions_report: Izveštaj o ovlašćenjima - label_watched_issues: Posmatrani problemi - label_related_issues: Povezani problemi - label_applied_status: Primenjeni statusi - label_loading: Učitavanje... - label_relation_new: Nova relacija - label_relation_delete: Obriši relaciju - label_relates_to: povezanih sa - label_duplicates: dupliranih - label_duplicated_by: dupliranih od - label_blocks: odbijenih - label_blocked_by: odbijenih od - label_precedes: prethodi - label_follows: praćenih - label_end_to_start: od kraja do početka - label_end_to_end: od kraja do kraja - label_start_to_start: od početka do početka - label_start_to_end: od početka do kraja - label_stay_logged_in: Ostani prijavljen - label_disabled: onemogućeno - label_show_completed_versions: Prikaži završene verzije - label_me: meni - label_board: Forum - label_board_new: Novi forum - label_board_plural: Forumi - label_board_locked: Zaključana - label_board_sticky: Lepljiva - label_topic_plural: Teme - label_message_plural: Poruke - label_message_last: Poslednja poruka - label_message_new: Nova poruka - label_message_posted: Poruka je dodata - label_reply_plural: Odgovori - label_send_information: Pošalji detalje naloga korisniku - label_year: Godina - label_month: Mesec - label_week: Sedmica - label_date_from: Šalje - label_date_to: Prima - label_language_based: Bazirano na jeziku korisnika - label_sort_by: "Poređano po {{value}}" - label_send_test_email: Pošalji probnu poruku - label_feeds_access_key: RSS pristupni ključ - label_missing_feeds_access_key: RSS pristupni ključ nedostaje - label_feeds_access_key_created_on: "RSS pristupni ključ je napravljen pre {{value}}" - label_module_plural: Moduli - label_added_time_by: "Dodao {{author}} pre {{age}}" - label_updated_time_by: "Ažurirao {{author}} pre {{age}}" - label_updated_time: "Ažurirano pre {{value}}" - label_jump_to_a_project: Skok na projekat... - label_file_plural: Datoteke - label_changeset_plural: Skupovi promena - label_default_columns: Podrazumevane kolone - label_no_change_option: (Bez promena) - label_bulk_edit_selected_issues: Grupna izmena odabranih problema - label_theme: Tema - label_default: Podrazumevano - label_search_titles_only: Pretražuj samo naslove - label_user_mail_option_all: "Za bilo koji događaj na svim mojim projektima" - label_user_mail_option_selected: "Za bilo koji događaj na samo odabranim projektima..." - label_user_mail_option_none: "Samo za stvari koje pratim ili sam uključen" - label_user_mail_no_self_notified: "Ne želim biti obaveštavan za promene koje sam pravim" - label_registration_activation_by_email: aktivacija naloga putem email-a - label_registration_manual_activation: ručna aktivacija naloga - label_registration_automatic_activation: automatska aktivacija naloga - label_display_per_page: "Broj stavki po strani: {{value}}" - label_age: Starost - label_change_properties: Promeni svojstva - label_general: Opšti - label_more: Više + label_wiki_edit: Wiki измена + label_wiki_edit_plural: Wiki измене + label_wiki_page: Wiki страница + label_wiki_page_plural: Wiki странице + label_index_by_title: Индексирање по наслову + label_index_by_date: Индексирање по датуму + label_current_version: Тренутна верзија + label_preview: Преглед + label_feed_plural: Извори вести + label_changes_details: Детаљи свих промена + label_issue_tracking: Праћење проблема + label_spent_time: Утрошено време + label_overall_spent_time: Целокупно утрошено време + label_f_hour: "{{value}} сат" + label_f_hour_plural: "{{value}} сати" + label_time_tracking: Праћење времена + label_change_plural: Промене + label_statistics: Статистика + label_commits_per_month: Извршења месечно + label_commits_per_author: Извршења по аутору + label_view_diff: Погледај разлике + label_diff_inline: унутра + label_diff_side_by_side: упоредо + label_options: Опције + label_copy_workflow_from: Копирање тока посла од + label_permissions_report: Извештај о дозволама + label_watched_issues: Посматрани проблеми + label_related_issues: Сродни проблеми + label_applied_status: Примењени статуси + label_loading: Учитавање... + label_relation_new: Нова релација + label_relation_delete: Брисање релације + label_relates_to: сродних са + label_duplicates: дуплираних + label_duplicated_by: дуплираних од + label_blocks: одбијених + label_blocked_by: одбијених од + label_precedes: претходи + label_follows: праћених + label_end_to_start: од краја до почетка + label_end_to_end: од краја до краја + label_start_to_start: од почетка до почетка + label_start_to_end: од почетка до краја + label_stay_logged_in: Останите пријављени + label_disabled: онемогућено + label_show_completed_versions: Приказивање завршене верзије + label_me: мени + label_board: Форум + label_board_new: Нови форум + label_board_plural: Форуми + label_board_locked: Закључана + label_board_sticky: Лепљива + label_topic_plural: Теме + label_message_plural: Поруке + label_message_last: Последња порука + label_message_new: Нова порука + label_message_posted: Порука је додата + label_reply_plural: Одговори + label_send_information: Пошаљи кориснику детаље налога + label_year: Година + label_month: Месец + label_week: Седмица + label_date_from: Шаље + label_date_to: Прима + label_language_based: Базирано на језику корисника + label_sort_by: "Сортирано по {{value}}" + label_send_test_email: Слање пробне е-поруке + label_feeds_access_key: RSS приступни кључ + label_missing_feeds_access_key: RSS приступни кључ недостаје + label_feeds_access_key_created_on: "RSS приступни кључ је направљен пре {{value}}" + label_module_plural: Модули + label_added_time_by: "Додао {{author}} пре {{age}}" + label_updated_time_by: "Ажурирао {{author}} пре {{age}}" + label_updated_time: "Ажурирано пре {{value}}" + label_jump_to_a_project: Скок на пројекат... + label_file_plural: Датотеке + label_changeset_plural: Скупови промена + label_default_columns: Подразумеване колоне + label_no_change_option: (Без промена) + label_bulk_edit_selected_issues: Групна измена одабраних проблема + label_theme: Тема + label_default: Подразумевано + label_search_titles_only: Претражуј само наслове + label_user_mail_option_all: "За било који догађај на свим мојим пројектима" + label_user_mail_option_selected: "За било који догађај на само одабраним пројектима..." + label_user_mail_option_none: "Само за ствари које пратим или у које сам укључен" + label_user_mail_no_self_notified: "Не желим бити обавештаван за промене које сам правим" + label_registration_activation_by_email: активација налога путем е-поруке + label_registration_manual_activation: ручна активација налога + label_registration_automatic_activation: аутоматска активација налога + label_display_per_page: "Број ставки по страници: {{value}}" + label_age: Старост + label_change_properties: Промени својства + label_general: Општи + label_more: Више label_scm: SCM - label_plugins: Dodaci - label_ldap_authentication: LDAP provera identiteta + label_plugins: Додатне компоненте + label_ldap_authentication: LDAP потврда идентитета label_downloads_abbr: D/L - label_optional_description: Opciono opis - label_add_another_file: Dodaj još jednu datoteku - label_preferences: Podešavanja - label_chronological_order: po hronološkom redosledu - label_reverse_chronological_order: po obrnutom hronološkom redosledu - label_planning: Planiranje - label_incoming_emails: Dolazne poruke - label_generate_key: Generiši ključ - label_issue_watchers: Posmatrači - label_example: Primer - label_display: Prikaz - label_sort: Redosled - label_ascending: Rastući niz - label_descending: Opadajući niz - label_date_from_to: Od {{start}} do {{end}} - label_wiki_content_added: Wiki strana je dodata - label_wiki_content_updated: Wiki strana je ažurirana - label_group: Grupa - label_group_plural: Grupe - label_group_new: Nova grupa - label_time_entry_plural: Provedeno vreme - label_version_sharing_none: Nije deljeno - label_version_sharing_descendants: Sa potprojektima - label_version_sharing_hierarchy: Sa hijerarhijom projekta - label_version_sharing_tree: Sa stablom projekta - label_version_sharing_system: Sa svim projektima - label_update_issue_done_ratios: Ažuriraj odnos rešenih problema - label_copy_source: Izvor - label_copy_target: Odredište - label_copy_same_as_target: Isto kao odredište - label_display_used_statuses_only: Prikazuj statuse korišćene samo od strane ovog tragača - label_api_access_key: API pristupni ključ - label_missing_api_access_key: API pristupni ključ nedostaje - label_api_access_key_created_on: "API pristupni ključ je kreiran pre {{value}}" - label_project_copy_notifications: Pošalji email poruku sa obaveštenjem prilikom kopiranja projekta + label_optional_description: Опционо опис + label_add_another_file: Додај још једну датотеку + label_preferences: Подешавања + label_chronological_order: по хронолошком редоследу + label_reverse_chronological_order: по обрнутом хронолошком редоследу + label_planning: Планирање + label_incoming_emails: Долазне е-поруке + label_generate_key: Генерисање кључа + label_issue_watchers: Посматрачи + label_example: Пример + label_display: Приказ + label_sort: Сортирање + label_ascending: Растући низ + label_descending: Опадајући низ + label_date_from_to: Од {{start}} до {{end}} + label_wiki_content_added: Wiki страница је додата + label_wiki_content_updated: Wiki страница је ажурирана + label_group: Група + label_group_plural: Групе + label_group_new: Нова група + label_time_entry_plural: Утрошено време + label_version_sharing_none: Није дељено + label_version_sharing_descendants: Са потпројектима + label_version_sharing_hierarchy: Са хијерархијом пројекта + label_version_sharing_tree: Са стаблом пројекта + label_version_sharing_system: Са свим пројектима + label_update_issue_done_ratios: Ажурирај однос решених проблема + label_copy_source: Извор + label_copy_target: Одредиште + label_copy_same_as_target: Исто као одредиште + label_display_used_statuses_only: Приказуј статусе коришћене само од стране овог праћења + label_api_access_key: API приступни кључ + label_missing_api_access_key: Недостаје API приступни кључ + label_api_access_key_created_on: "API приступни кључ је креиран пре {{value}}" + label_profile: Профил + label_subtask_plural: Подзадатак + label_project_copy_notifications: Пошаљи е-поруку са обавештењем приликом копирања пројекта - button_login: Prijava - button_submit: Pošalji - button_save: Snimi - button_check_all: Uključi sve - button_uncheck_all: Isključi sve - button_delete: Obriši - button_create: Napravi - button_create_and_continue: Napravi i nastavi - button_test: Test - button_edit: Izmeni - button_add: Dodaj - button_change: Promeni - button_apply: Primeni - button_clear: Obriši - button_lock: Zaključaj - button_unlock: Otključaj - button_download: Preuzmi - button_list: Spisak - button_view: Prikaz - button_move: Pomeri - button_move_and_follow: Pomeri i prati - button_back: Nazad - button_cancel: Poništi - button_activate: Aktiviraj - button_sort: Poređaj - button_log_time: Evidentiranje vremena - button_rollback: Povratak na ovu verziju - button_watch: Prati - button_unwatch: Ne prati više - button_reply: Odgovori - button_archive: Arhiviraj - button_unarchive: Vrati iz arhive - button_reset: Poništi - button_rename: Reimenuj - button_change_password: Promena lozinke - button_copy: Kopiraj - button_copy_and_follow: Kopiraj i prati - button_annotate: Pribeleži - button_update: Ažuriraj - button_configure: Podesi - button_quote: Pod navodnicima - button_duplicate: Dupliraj - button_show: Prikaži + button_login: Пријава + button_submit: Пошаљи + button_save: Сними + button_check_all: Укључи све + button_uncheck_all: Искључи све + button_delete: Избриши + button_create: Креирај + button_create_and_continue: Креирај и настави + button_test: Тест + button_edit: Измени + button_add: Додај + button_change: Промени + button_apply: Примени + button_clear: Обриши + button_lock: Закључај + button_unlock: Откључај + button_download: Преузми + button_list: Списак + button_view: Прикажи + button_move: Помери + button_move_and_follow: Помери и прати + button_back: Назад + button_cancel: Поништи + button_activate: Активирај + button_sort: Сортирај + button_log_time: Евидентирај време + button_rollback: Повратак на ову верзију + button_watch: Прати + button_unwatch: Не прати више + button_reply: Одговори + button_archive: Архивирај + button_unarchive: Врати из архиве + button_reset: Поништи + button_rename: Преименуј + button_change_password: Промени лозинку + button_copy: Копирај + button_copy_and_follow: Копирај и прати + button_annotate: Прибележи + button_update: Ажурирај + button_configure: Подеси + button_quote: Под наводницима + button_duplicate: Дуплирај + button_show: Прикажи - status_active: aktivni - status_registered: registrovani - status_locked: zaključani + status_active: активни + status_registered: регистровани + status_locked: закључани - version_status_open: otvoren - version_status_locked: zaključan - version_status_closed: zatvoren + version_status_open: отворен + version_status_locked: закључан + version_status_closed: затворен - field_active: Aktivan + field_active: Активан - text_select_mail_notifications: Odaberi akcije za koje će email obaveštenje biti poslato. - text_regexp_info: npr. ^[A-Z0-9]+$ - text_min_max_length_info: 0 znači bez ograničenja - text_project_destroy_confirmation: Jeste li sigurni da želite da obrišete ovaj projekat i sve pripadajuće podatke? - text_subprojects_destroy_warning: "Potpojekat: {{value}} će takođe biti obrisan." - text_workflow_edit: Odaberite ulogu i tragača za izmenu toka rada - text_are_you_sure: Jeste li sigurni? - text_journal_changed: "{{label}} promenjen od {{old}} u {{new}}" - text_journal_set_to: "{{label}} postavljen u {{value}}" - text_journal_deleted: "{{label}} obrisano ({{old}})" - text_journal_added: "{{label}} {{value}} dodato" - text_tip_task_begin_day: zadatak počinje ovog dana - text_tip_task_end_day: zadatak se završava ovog dana - text_tip_task_begin_end_day: zadatak počinje i završava istog dana - text_project_identifier_info: 'Dozvoljena su samo mala slova (a-š), brojevi i crtice.
    Jednom snimljen, identifikator se ne može promeniti.' - text_caracters_maximum: "{{count}} znak(ova) najviše." - text_caracters_minimum: "Broj znakova mora biti najmanje {{count}}." - text_length_between: "Broj znakova mora biti između {{min}} i {{max}}." - text_tracker_no_workflow: Tok rada nije definisan za ovog tragača - text_unallowed_characters: Nedozvoljeni znakovi - text_comma_separated: Višestruke vrednosti su dozvoljene (odvojene zarezom). - text_line_separated: Višestruke vrednosti su dozvoljene (jedan red za svaku vrednost). - text_issues_ref_in_commit_messages: Referenciranje i popravljanje problema u izvršnim porukama - text_issue_added: "Problem {{id}} je prijavio {{author}}." - text_issue_updated: "Problem {{id}} je ažurirao {{author}}." - text_wiki_destroy_confirmation: Jeste li sigurni da želite da obrišete wiki i sav sadržaj? - text_issue_category_destroy_question: "Nekoliko problema ({{count}}) je dodeljeno ovoj kategoriji. Šta želite da uradite?" - text_issue_category_destroy_assignments: Ukloni dodoljene kategorije - text_issue_category_reassign_to: Dodeli ponovo probleme ovoj kategoriji - text_user_mail_option: "Za neizabrane projekte, dobićete samo obaveštenje o stvarima koje pratite ili ste uključeni (npr. problemi čiji ste vi autor ili zastupnik)." - text_no_configuration_data: "Uloge, tragači, statusi problema i procesa rada još uvek nisu podešeni.\nPreporučljivo je da učitate podrazumevano konfigurisanje. Izmena je moguća nakon prvog učitavanja." - text_load_default_configuration: Učitaj podrazumevano konfigurisanje - text_status_changed_by_changeset: "Primenjeno u skupu sa promenama {{value}}." - text_issues_destroy_confirmation: 'Jeste li sigurni da želite da obrišete odabrane probleme?' - text_select_project_modules: 'Odaberite module koje želite omogućiti za ovaj projekat:' - text_default_administrator_account_changed: Podrazumevani administratorski nalog je promenjen - text_file_repository_writable: Fascikla priloženih datoteka je upisiva - text_plugin_assets_writable: Fascikla elemenata dodatka je upisiva - text_rmagick_available: RMagick je dostupan (opciono) - text_destroy_time_entries_question: "{{hours}} sati je prijavljeno za ovaj problem koji želite obrisati. Šta želite da uradite?" - text_destroy_time_entries: Obriši prijavljene sate - text_assign_time_entries_to_project: Dodeli prijavljene sate projektu - text_reassign_time_entries: 'Dodeli ponovo prijavljene sate ovom problemu:' - text_user_wrote: "{{value}} je napisao:" - text_enumeration_destroy_question: "{{count}} objekat(a) je dodeljeno ovoj vrednosti." - text_enumeration_category_reassign_to: 'Dodeli ih ponovo ovoj vrednosti:' - text_email_delivery_not_configured: "Isporuka email poruka nije konfigurisana i obaveštavanja su onemogućena.\nPodesite vaš SMTP server u config/email.yml i pokrenite ponovo aplikaciju za njihovo omogućavanje." - text_repository_usernames_mapping: "Odaberite ili ažurirajte Redmine korisnike mapiranjem na svako korisničko ime pronađeno u evidenciji spremišta.\nKorisnici sa istim Redmine imenom i imenom spremišta ili email adresom su automatski mapirani." - text_diff_truncated: '... Ova razlika je isečena zato što je dostignuta maksimalna veličina koja može biti prikazana.' - text_custom_field_possible_values_info: 'Jedan red za svaku vrednost' - text_wiki_page_destroy_question: "Ova strana ima {{descendants}} strana naslednika i potomaka. Šta želite da uradite?" - text_wiki_page_nullify_children: "Zadrži strane naslednika kao korene strane" - text_wiki_page_destroy_children: "Obriši strane naslednika i svih njihovih potomaka" - text_wiki_page_reassign_children: "Dodeli ponovo strane naslednika njihovoj roditeljskoj strani" - text_own_membership_delete_confirmation: "Uklanjanjem pojedinih ili svih vaših dozvola nećete više moći za uređujete ovaj projekat nakon toga.\nŽelite li da nastavite?" + text_select_mail_notifications: Одабери акције за које ће обавештење бити послато путем е-поште. + text_regexp_info: нпр. ^[A-Z0-9]+$ + text_min_max_length_info: 0 значи без ограничења + text_project_destroy_confirmation: Јесте ли сигурни да желите да избришете овај пројекат и све припадајуће податке? + text_subprojects_destroy_warning: "Потпројекти: {{value}} ће такође бити избрисан." + text_workflow_edit: Одаберите улогу и праћење за измену тока посла + text_are_you_sure: Јесте ли сигурни? + text_journal_changed: "{{label}} промењен од {{old}} у {{new}}" + text_journal_set_to: "{{label}} постављен у {{value}}" + text_journal_deleted: "{{label}} избрисано ({{old}})" + text_journal_added: "{{label}} {{value}} додато" + text_tip_task_begin_day: задатак почиње овог дана + text_tip_task_end_day: задатак се завршава овог дана + text_tip_task_begin_end_day: задатак почиње и завршава овог дана + text_project_identifier_info: 'Дозвољена су само мала слова (a-ш), бројеви и цртице.
    Једном снимљен идентификатор више се не може променити.' + text_caracters_maximum: "Највише {{count}} знак(ова)." + text_caracters_minimum: "Број знакова мора бити најмање {{count}}." + text_length_between: "Број знакова мора бити између {{min}} и {{max}}." + text_tracker_no_workflow: Ово праћење нема дефинисан ток посла + text_unallowed_characters: Недозвољени знакови + text_comma_separated: Дозвољене су вишеструке вредности (одвојене зарезом). + text_line_separated: Дозвољене су вишеструке вредности (један ред за сваку вредност). + text_issues_ref_in_commit_messages: Референцирање и поправљање проблема у извршним порукама + text_issue_added: "{{author}} је пријавио проблем {{id}}." + text_issue_updated: "{{author}} је ажурирао проблем {{id}}." + text_wiki_destroy_confirmation: Јесте ли сигурни да желите да обришете wiki и сав садржај? + text_issue_category_destroy_question: "Неколико проблема ({{count}}) је додељено овој категорији. Шта желите да урадите?" + text_issue_category_destroy_assignments: Уклони додељене категорије + text_issue_category_reassign_to: Додели поново проблеме овој категорији + text_user_mail_option: "За неизабране пројекте, добићете само обавештење о стварима које пратите или сте укључени (нпр. проблеми чији сте ви аутор или заступник)." + text_no_configuration_data: "Улоге, праћења, статуси проблема и тока посла још увек нису подешени.\nПрепоручљиво је да учитате подразумевано конфигурисање. Измена је могућа након првог учитавања." + text_load_default_configuration: Учитај подразумевано конфигурисање + text_status_changed_by_changeset: "Примењено у скупу са променама {{value}}." + text_issues_destroy_confirmation: 'Јесте ли сигурни да желите да избришете одабране проблеме?' + text_select_project_modules: 'Одаберите модуле које желите омогућити за овај пројекат:' + text_default_administrator_account_changed: Подразумевани администраторски налог је промењен + text_file_repository_writable: Фасцикла приложених датотека је уписива + text_plugin_assets_writable: Фасцикла елемената додатних компоненти је уписива + text_rmagick_available: RMagick је доступан (опционо) + text_destroy_time_entries_question: "{{hours}} сати је пријављено за овај проблем који желите избрисати. Шта желите да урадите?" + text_destroy_time_entries: Избриши пријављене сате + text_assign_time_entries_to_project: Додели пријављене сате пројекту + text_reassign_time_entries: 'Додели поново пријављене сате овом проблему:' + text_user_wrote: "{{value}} је написао:" + text_enumeration_destroy_question: "{{count}} објекат(а) је додељено овој вредности." + text_enumeration_category_reassign_to: 'Додели их поново овој вредности:' + text_email_delivery_not_configured: "Испорука е-порука није конфигурисана и обавештења су онемогућена.\nПодесите ваш SMTP сервер у config/email.yml и покрените поново апликацију за њихово омогућавање." + text_repository_usernames_mapping: "Одаберите или ажурирајте Redmine кориснике мапирањем сваког корисничког имена пронађеног у евиденцији спремишта.\nКорисници са истим Redmine именом и именом спремишта или е-адресом су аутоматски мапирани." + text_diff_truncated: '... Ова разлика је исечена јер је достигнута максимална величина приказа.' + text_custom_field_possible_values_info: 'Један ред за сваку вредност' + text_wiki_page_destroy_question: "Ова страница има {{descendants}} подређених страница и подстраница. Шта желите да урадите?" + text_wiki_page_nullify_children: "Задржи подређене странице као корене странице" + text_wiki_page_destroy_children: "Избриши подређене странице и све њихове подстранице" + text_wiki_page_reassign_children: "Додели поново подређене странице овој матичној страници" + text_own_membership_delete_confirmation: "Након уклањања појединих или свих ваших дозвола нећете више моћи да уређујете овај пројекат.\nЖелите ли да наставите?" + text_zoom_in: Увећај + text_zoom_out: Умањи - default_role_manager: Menadžer - default_role_developer: Programer - default_role_reporter: Izveštač - default_tracker_bug: Greška - default_tracker_feature: Funkcionalnost - default_tracker_support: Podrška - default_issue_status_new: Novo - default_issue_status_in_progress: U toku - default_issue_status_resolved: Rešeno - default_issue_status_feedback: Povratna informacija - default_issue_status_closed: Zatvoreno - default_issue_status_rejected: Odbijeno - default_doc_category_user: Korisnička dokumentacija - default_doc_category_tech: Tehnička dokumentacija - default_priority_low: Nizak - default_priority_normal: Normalan - default_priority_high: Visok - default_priority_urgent: Hitno - default_priority_immediate: Neposredno - default_activity_design: Dizajn - default_activity_development: Razvoj + default_role_manager: Менаџер + default_role_developer: Програмер + default_role_reporter: Извештач + default_tracker_bug: Грешка + default_tracker_feature: Функционалност + default_tracker_support: Подршка + default_issue_status_new: Ново + default_issue_status_in_progress: У току + default_issue_status_resolved: Решено + default_issue_status_feedback: Повратна информација + default_issue_status_closed: Затворено + default_issue_status_rejected: Одбијено + default_doc_category_user: Корисничка документација + default_doc_category_tech: Техничка документација + default_priority_low: Низак + default_priority_normal: Нормалан + default_priority_high: Висок + default_priority_urgent: Хитно + default_priority_immediate: Непосредно + default_activity_design: Дизајн + default_activity_development: Развој - enumeration_issue_priorities: Prioriteti problema - enumeration_doc_categories: Kategorije dokumenta - enumeration_activities: Aktivnosti (vremenski praćene) - enumeration_system_activity: Sistemska aktivnost - - error_can_not_delete_custom_field: Unable to delete custom field - permission_manage_subtasks: Manage subtasks - label_profile: Profile - error_unable_to_connect: Unable to connect ({{value}}) - error_can_not_remove_role: This role is in use and can not be deleted. - field_parent_issue: Parent task - error_unable_delete_issue_status: Unable to delete issue status - label_subtask_plural: Subtasks - error_can_not_delete_tracker: This tracker contains issues and can't be deleted. - field_principal: Principal - label_my_page_block: My page block - notice_failed_to_save_members: "Failed to save member(s): {{errors}}." - text_zoom_out: Zoom out - text_zoom_in: Zoom in - notice_unable_delete_time_entry: Unable to delete time log entry. - label_overall_spent_time: Overall spent time + enumeration_issue_priorities: Приоритети проблема + enumeration_doc_categories: Категорије документа + enumeration_activities: Активности (праћење времена) + enumeration_system_activity: Системска активност + \ No newline at end of file diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 35ebc105..42f0bc97 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -905,9 +905,9 @@ sv: text_issues_destroy_confirmation: 'Är du säker på att du vill radera markerade ärende(n) ?' text_select_project_modules: 'Välj vilka moduler som ska vara aktiva för projektet:' text_default_administrator_account_changed: Standardadministratörens konto ändrat - text_file_repository_writable: Arkivet för bifogade filer är skrivbar - text_plugin_assets_writable: Arkivet för plug-ins är skrivbar - text_rmagick_available: RMagick tillgängligt (valfritt) + text_file_repository_writable: Arkivet för bifogade filer är skrivbart + text_plugin_assets_writable: Arkivet för plug-ins är skrivbart + text_rmagick_available: RMagick tillgängligt (ej obligatoriskt) text_destroy_time_entries_question: "{{hours}} timmar har rapporterats på ärendena du är på väg att ta bort. Vad vill du göra ?" text_destroy_time_entries: Ta bort rapporterade timmar text_assign_time_entries_to_project: Tilldela rapporterade timmar till projektet diff --git a/public/javascripts/calendar/lang/calendar-it.js b/public/javascripts/calendar/lang/calendar-it.js index fbc80c93..2c3379c7 100644 --- a/public/javascripts/calendar/lang/calendar-it.js +++ b/public/javascripts/calendar/lang/calendar-it.js @@ -9,6 +9,9 @@ // Unicode is the answer to a real internationalized world. Also please // include your contact information in the header, as can be seen above. +// Italian translation +// by Diego Pierotto (ita.translations@tiscali.it) + // full day names Calendar._DN = new Array ("Domenica", @@ -83,19 +86,19 @@ Calendar._TT["INFO"] = "Informazioni sul calendario"; Calendar._TT["ABOUT"] = "DHTML Date/Time Selector\n" + -"(c) dynarch.com 2002-2005 / Author: Mihai Bazon\n" + // don't translate this this ;-) -"For latest version visit: http://www.dynarch.com/projects/calendar/\n" + -"Distributed under GNU LGPL. See http://gnu.org/licenses/lgpl.html for details." + +"(c) dynarch.com 2002-2005 / Autore: Mihai Bazon\n" + // don't translate this this ;-) +"Per l'ultima versione visita: http://www.dynarch.com/projects/calendar/\n" + +"Distribuito sotto i termini GNU LGPL. Vedi http://gnu.org/licenses/lgpl.html per maggiori dettagli." + "\n\n" + -"Date selection:\n" + -"- Use the \xab, \xbb buttons to select year\n" + -"- Use the " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " buttons to select month\n" + -"- Hold mouse button on any of the above buttons for faster selection."; +"Selezione data:\n" + +"- Usa i tasti \xab, \xbb per selezionare l'anno\n" + +"- Usa i tasti " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " per selezionare il mese\n" + +"- Tieni premuto il tasto del mouse su uno qualunque dei tasti sopra per una selezione più veloce."; Calendar._TT["ABOUT_TIME"] = "\n\n" + -"Time selection:\n" + -"- Click on any of the time parts to increase it\n" + -"- or Shift-click to decrease it\n" + -"- or click and drag for faster selection."; +"Selezione ora:\n" + +"- Fai click su una delle ore per incrementarla\n" + +"- oppure Shift-click per diminuirla\n" + +"- oppure click e trascina per una selezione più veloce."; Calendar._TT["PREV_YEAR"] = "Anno prec. (tieni premuto per menu)"; Calendar._TT["PREV_MONTH"] = "Mese prec. (tieni premuto per menu)"; diff --git a/public/javascripts/calendar/lang/calendar-sr-CY.js b/public/javascripts/calendar/lang/calendar-sr-CY.js deleted file mode 100644 index a43b49e1..00000000 --- a/public/javascripts/calendar/lang/calendar-sr-CY.js +++ /dev/null @@ -1,127 +0,0 @@ -// ** I18N - -// Calendar SR language -// Author: Dragan Matic, -// Encoding: any -// Distributed under the same terms as the calendar itself. - -// For translators: please use UTF-8 if possible. We strongly believe that -// Unicode is the answer to a real internationalized world. Also please -// include your contact information in the header, as can be seen above. - -// full day names -Calendar._DN = new Array -("Недеља", - "Понедељак", - "Уторак", - "Среда", - "Четвртак", - "Петак", - "Субота", - "Недеља"); - -// Please note that the following array of short day names (and the same goes -// for short month names, _SMN) isn't absolutely necessary. We give it here -// for exemplification on how one can customize the short day names, but if -// they are simply the first N letters of the full name you can simply say: -// -// Calendar._SDN_len = N; // short day name length -// Calendar._SMN_len = N; // short month name length -// -// If N = 3 then this is not needed either since we assume a value of 3 if not -// present, to be compatible with translation files that were written before -// this feature. - -// short day names -Calendar._SDN = new Array -("Нед", - "Пон", - "Уто", - "Сре", - "Чет", - "Пет", - "Суб", - "Нед"); - -// First day of the week. "0" means display Sunday first, "1" means display -// Monday first, etc. -Calendar._FD = 1; - -// full month names -Calendar._MN = new Array -("Јануар", - "Фебруар", - "Март", - "Април", - "Мај", - "Јун", - "Јул", - "Август", - "Септембар", - "Октобар", - "Новембар", - "Децембар"); - -// short month names -Calendar._SMN = new Array -("јан", - "феб", - "мар", - "апр", - "мај", - "јун", - "јул", - "авг", - "сеп", - "окт", - "нов", - "дец"); - -// tooltips -Calendar._TT = {}; -Calendar._TT["INFO"] = "О календару"; - -Calendar._TT["ABOUT"] = -"DHTML бирач датума/времена\n" + -"(c) dynarch.com 2002-2005 / Аутор: Mihai Bazon\n" + // don't translate this this ;-) -"За новију верзију посетите: http://www.dynarch.com/projects/calendar/\n" + -"Дистрибуира се под GNU LGPL. Погледајте http://gnu.org/licenses/lgpl.html за детаљe." + -"\n\n" + -"Избор датума:\n" + -"- Користите \xab, \xbb тастере за избор године\n" + -"- Користите " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " тастере за избор месеца\n" + -"- Задржите тастер миша на било ком тастеру изнад за бржи избор."; -Calendar._TT["ABOUT_TIME"] = "\n\n" + -"Избор времена:\n" + -"- Кликните на било који део времена за повећање\n" + -"- или Shift-клик за умањење\n" + -"- или кликните и превуците за бржи одабир."; - -Calendar._TT["PREV_YEAR"] = "Претходна година (задржати за мени)"; -Calendar._TT["PREV_MONTH"] = "Претходни месец (задржати за мени)"; -Calendar._TT["GO_TODAY"] = "На данашњи дан"; -Calendar._TT["NEXT_MONTH"] = "Наредни месец (задржати за мени)"; -Calendar._TT["NEXT_YEAR"] = "Наредна година (задржати за мени)"; -Calendar._TT["SEL_DATE"] = "Избор датума"; -Calendar._TT["DRAG_TO_MOVE"] = "Превуците за премештање"; -Calendar._TT["PART_TODAY"] = " (данас)"; - -// the following is to inform that "%s" is to be the first day of week -// %s will be replaced with the day name. -Calendar._TT["DAY_FIRST"] = "%s као први дан у седмици"; - -// This may be locale-dependent. It specifies the week-end days, as an array -// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 -// means Monday, etc. -Calendar._TT["WEEKEND"] = "6,7"; - -Calendar._TT["CLOSE"] = "Затвори"; -Calendar._TT["TODAY"] = "Данас"; -Calendar._TT["TIME_PART"] = "(Shift-) клик или превлачење за измену вредности"; - -// date formats -Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y."; -Calendar._TT["TT_DATE_FORMAT"] = "%a, %e. %b"; - -Calendar._TT["WK"] = "сед."; -Calendar._TT["TIME"] = "Време:"; diff --git a/public/javascripts/calendar/lang/calendar-sr-yu.js b/public/javascripts/calendar/lang/calendar-sr-yu.js new file mode 100644 index 00000000..8fd5ceb8 --- /dev/null +++ b/public/javascripts/calendar/lang/calendar-sr-yu.js @@ -0,0 +1,127 @@ +// ** I18N + +// Calendar SR language +// Author: Dragan Matic, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("nedelja", + "ponedeljak", + "utorak", + "sreda", + "četvrtak", + "petak", + "subota", + "nedelja"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("ned", + "pon", + "uto", + "sre", + "čet", + "pet", + "sub", + "ned"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("januar", + "februar", + "mart", + "april", + "maj", + "jun", + "jul", + "avgust", + "septembar", + "oktobar", + "novembar", + "decembar"); + +// short month names +Calendar._SMN = new Array +("jan", + "feb", + "mar", + "apr", + "maj", + "jun", + "jul", + "avg", + "sep", + "okt", + "nov", + "dec"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "O kalendaru"; + +Calendar._TT["ABOUT"] = +"DHTML birač datuma/vremena\n" + +"(c) dynarch.com 2002-2005 / Autor: Mihai Bazon\n" + // don't translate this this ;-) +"Za noviju verziju posetite: http://www.dynarch.com/projects/calendar/\n" + +"Distribuira se pod GNU LGPL. Pogledajte http://gnu.org/licenses/lgpl.html za detalje." + +"\n\n" + +"Izbor datuma:\n" + +"- Koristite \xab, \xbb tastere za izbor godine\n" + +"- Koristite " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " tastere za izbor meseca\n" + +"- Zadržite taster miša na bilo kom tasteru iznad za brži izbor."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Izbor vremena:\n" + +"- Kliknite na bilo koji deo vremena za povećanje\n" + +"- ili Shift-klik za umanjenje\n" + +"- ili kliknite i prevucite za brži odabir."; + +Calendar._TT["PREV_YEAR"] = "Prethodna godina (zadržati za meni)"; +Calendar._TT["PREV_MONTH"] = "Prethodni mesec (zadržati za meni)"; +Calendar._TT["GO_TODAY"] = "Na današnji dan"; +Calendar._TT["NEXT_MONTH"] = "Naredni mesec (zadržati za meni)"; +Calendar._TT["NEXT_YEAR"] = "Naredna godina (zadržati za meni)"; +Calendar._TT["SEL_DATE"] = "Izbor datuma"; +Calendar._TT["DRAG_TO_MOVE"] = "Prevucite za premeštanje"; +Calendar._TT["PART_TODAY"] = " (danas)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s kao prvi dan u sedmici"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "6,7"; + +Calendar._TT["CLOSE"] = "Zatvori"; +Calendar._TT["TODAY"] = "Danas"; +Calendar._TT["TIME_PART"] = "(Shift-) klik ili prevlačenje za izmenu vrednosti"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y."; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e. %b"; + +Calendar._TT["WK"] = "sed."; +Calendar._TT["TIME"] = "Vreme:"; diff --git a/public/javascripts/calendar/lang/calendar-sr.js b/public/javascripts/calendar/lang/calendar-sr.js index 67637334..2fa58d73 100644 --- a/public/javascripts/calendar/lang/calendar-sr.js +++ b/public/javascripts/calendar/lang/calendar-sr.js @@ -1,127 +1,127 @@ -// ** I18N - -// Calendar SR language -// Author: Dragan Matic, -// Encoding: any -// Distributed under the same terms as the calendar itself. - -// For translators: please use UTF-8 if possible. We strongly believe that -// Unicode is the answer to a real internationalized world. Also please -// include your contact information in the header, as can be seen above. - -// full day names -Calendar._DN = new Array -("Nedelja", - "Ponedeljak", - "Utorak", - "Sreda", - "Četvrtak", - "Petak", - "Subota", - "Nedelja"); - -// Please note that the following array of short day names (and the same goes -// for short month names, _SMN) isn't absolutely necessary. We give it here -// for exemplification on how one can customize the short day names, but if -// they are simply the first N letters of the full name you can simply say: -// -// Calendar._SDN_len = N; // short day name length -// Calendar._SMN_len = N; // short month name length -// -// If N = 3 then this is not needed either since we assume a value of 3 if not -// present, to be compatible with translation files that were written before -// this feature. - -// short day names -Calendar._SDN = new Array -("Ned", - "Pon", - "Uto", - "Sre", - "Čet", - "Pet", - "Sub", - "Ned"); - -// First day of the week. "0" means display Sunday first, "1" means display -// Monday first, etc. -Calendar._FD = 1; - -// full month names -Calendar._MN = new Array -("Januar", - "Februar", - "Mart", - "April", - "Maj", - "Jun", - "Jul", - "Avgust", - "Septembar", - "Oktobar", - "Novembar", - "Decembar"); - -// short month names -Calendar._SMN = new Array -("jan", - "feb", - "mar", - "apr", - "maj", - "jun", - "jul", - "avg", - "sep", - "okt", - "nov", - "dec"); - -// tooltips -Calendar._TT = {}; -Calendar._TT["INFO"] = "O kalendaru"; - -Calendar._TT["ABOUT"] = -"DHTML birač datuma/vremena\n" + -"(c) dynarch.com 2002-2005 / Autor: Mihai Bazon\n" + // don't translate this this ;-) -"Za noviju verziju posetite: http://www.dynarch.com/projects/calendar/\n" + -"Distribuira se pod GNU LGPL. Pogledajte http://gnu.org/licenses/lgpl.html za detalje." + -"\n\n" + -"Izbor datuma:\n" + -"- Koristite \xab, \xbb tastere za izbor godine\n" + -"- Koristite " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " tastere za izbor meseca\n" + -"- Zadržite taster miša na bilo kom tasteru iznad za brži izbor."; -Calendar._TT["ABOUT_TIME"] = "\n\n" + -"Izbor vremena:\n" + -"- Kliknite na bilo koji deo vremena za povećanje\n" + -"- ili Shift-klik za umanjenje\n" + -"- ili kliknite i prevucite za brži odabir."; - -Calendar._TT["PREV_YEAR"] = "Prethodna godina (zadržati za meni)"; -Calendar._TT["PREV_MONTH"] = "Prethodni mesec (zadržati za meni)"; -Calendar._TT["GO_TODAY"] = "Na današnji dan"; -Calendar._TT["NEXT_MONTH"] = "Naredni mesec (zadržati za meni)"; -Calendar._TT["NEXT_YEAR"] = "Naredna godina (zadržati za meni)"; -Calendar._TT["SEL_DATE"] = "Izbor datuma"; -Calendar._TT["DRAG_TO_MOVE"] = "Prevucite za premeštanje"; -Calendar._TT["PART_TODAY"] = " (danas)"; - -// the following is to inform that "%s" is to be the first day of week -// %s will be replaced with the day name. -Calendar._TT["DAY_FIRST"] = "%s kao prvi dan u sedmici"; - -// This may be locale-dependent. It specifies the week-end days, as an array -// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 -// means Monday, etc. -Calendar._TT["WEEKEND"] = "6,7"; - -Calendar._TT["CLOSE"] = "Zatvori"; -Calendar._TT["TODAY"] = "Danas"; -Calendar._TT["TIME_PART"] = "(Shift-) klik ili prevlačenje za izmenu vrednosti"; - -// date formats -Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y."; -Calendar._TT["TT_DATE_FORMAT"] = "%a, %e. %b"; - -Calendar._TT["WK"] = "sed."; -Calendar._TT["TIME"] = "Vreme:"; +// ** I18N + +// Calendar SR language +// Author: Dragan Matic, +// Encoding: any +// Distributed under the same terms as the calendar itself. + +// For translators: please use UTF-8 if possible. We strongly believe that +// Unicode is the answer to a real internationalized world. Also please +// include your contact information in the header, as can be seen above. + +// full day names +Calendar._DN = new Array +("недеља", + "понедељак", + "уторак", + "среда", + "четвртак", + "петак", + "субота", + "недеља"); + +// Please note that the following array of short day names (and the same goes +// for short month names, _SMN) isn't absolutely necessary. We give it here +// for exemplification on how one can customize the short day names, but if +// they are simply the first N letters of the full name you can simply say: +// +// Calendar._SDN_len = N; // short day name length +// Calendar._SMN_len = N; // short month name length +// +// If N = 3 then this is not needed either since we assume a value of 3 if not +// present, to be compatible with translation files that were written before +// this feature. + +// short day names +Calendar._SDN = new Array +("нед", + "пон", + "уто", + "сре", + "чет", + "пет", + "суб", + "нед"); + +// First day of the week. "0" means display Sunday first, "1" means display +// Monday first, etc. +Calendar._FD = 1; + +// full month names +Calendar._MN = new Array +("јануар", + "фебруар", + "март", + "април", + "мај", + "јун", + "јул", + "август", + "септембар", + "октобар", + "новембар", + "децембар"); + +// short month names +Calendar._SMN = new Array +("јан", + "феб", + "мар", + "апр", + "мај", + "јун", + "јул", + "авг", + "сеп", + "окт", + "нов", + "дец"); + +// tooltips +Calendar._TT = {}; +Calendar._TT["INFO"] = "О календару"; + +Calendar._TT["ABOUT"] = +"DHTML бирач датума/времена\n" + +"(c) dynarch.com 2002-2005 / Аутор: Mihai Bazon\n" + // don't translate this this ;-) +"За новију верзију посетите: http://www.dynarch.com/projects/calendar/\n" + +"Дистрибуира се под GNU LGPL. Погледајте http://gnu.org/licenses/lgpl.html за детаљe." + +"\n\n" + +"Избор датума:\n" + +"- Користите \xab, \xbb тастере за избор године\n" + +"- Користите " + String.fromCharCode(0x2039) + ", " + String.fromCharCode(0x203a) + " тастере за избор месеца\n" + +"- Задржите тастер миша на било ком тастеру изнад за бржи избор."; +Calendar._TT["ABOUT_TIME"] = "\n\n" + +"Избор времена:\n" + +"- Кликните на било који део времена за повећање\n" + +"- или Shift-клик за умањење\n" + +"- или кликните и превуците за бржи одабир."; + +Calendar._TT["PREV_YEAR"] = "Претходна година (задржати за мени)"; +Calendar._TT["PREV_MONTH"] = "Претходни месец (задржати за мени)"; +Calendar._TT["GO_TODAY"] = "На данашњи дан"; +Calendar._TT["NEXT_MONTH"] = "Наредни месец (задржати за мени)"; +Calendar._TT["NEXT_YEAR"] = "Наредна година (задржати за мени)"; +Calendar._TT["SEL_DATE"] = "Избор датума"; +Calendar._TT["DRAG_TO_MOVE"] = "Превуците за премештање"; +Calendar._TT["PART_TODAY"] = " (данас)"; + +// the following is to inform that "%s" is to be the first day of week +// %s will be replaced with the day name. +Calendar._TT["DAY_FIRST"] = "%s као први дан у седмици"; + +// This may be locale-dependent. It specifies the week-end days, as an array +// of comma-separated numbers. The numbers are from 0 to 6: 0 means Sunday, 1 +// means Monday, etc. +Calendar._TT["WEEKEND"] = "6,7"; + +Calendar._TT["CLOSE"] = "Затвори"; +Calendar._TT["TODAY"] = "Данас"; +Calendar._TT["TIME_PART"] = "(Shift-) клик или превлачење за измену вредности"; + +// date formats +Calendar._TT["DEF_DATE_FORMAT"] = "%d.%m.%Y."; +Calendar._TT["TT_DATE_FORMAT"] = "%a, %e. %b"; + +Calendar._TT["WK"] = "сед."; +Calendar._TT["TIME"] = "Време:"; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-it.js b/public/javascripts/jstoolbar/lang/jstoolbar-it.js index bf7fcefb..99749b40 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-it.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-it.js @@ -1,3 +1,6 @@ +// Italian translation +// by Diego Pierotto (ita.translations@tiscali.it) + jsToolBar.strings = {}; jsToolBar.strings['Strong'] = 'Grassetto'; jsToolBar.strings['Italic'] = 'Corsivo'; @@ -8,7 +11,7 @@ jsToolBar.strings['Heading 1'] = 'Titolo 1'; jsToolBar.strings['Heading 2'] = 'Titolo 2'; jsToolBar.strings['Heading 3'] = 'Titolo 3'; jsToolBar.strings['Unordered list'] = 'Elenco puntato'; -jsToolBar.strings['Ordered list'] = 'Numerazione'; +jsToolBar.strings['Ordered list'] = 'Elenco numerato'; jsToolBar.strings['Quote'] = 'Aumenta rientro'; jsToolBar.strings['Unquote'] = 'Riduci rientro'; jsToolBar.strings['Preformatted text'] = 'Testo preformattato'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sr-yu.js b/public/javascripts/jstoolbar/lang/jstoolbar-sr-yu.js new file mode 100644 index 00000000..0e231e02 --- /dev/null +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sr-yu.js @@ -0,0 +1,16 @@ +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Podebljano'; +jsToolBar.strings['Italic'] = 'Kurziv'; +jsToolBar.strings['Underline'] = 'Podvučeno'; +jsToolBar.strings['Deleted'] = 'Obrisano'; +jsToolBar.strings['Code'] = 'Ugrađeni kôd'; +jsToolBar.strings['Heading 1'] = 'Naslov 1'; +jsToolBar.strings['Heading 2'] = 'Naslov 2'; +jsToolBar.strings['Heading 3'] = 'Naslov 3'; +jsToolBar.strings['Unordered list'] = 'Lista nabrajanja'; +jsToolBar.strings['Ordered list'] = 'Uređena lista'; +jsToolBar.strings['Quote'] = 'Pod navodnicima'; +jsToolBar.strings['Unquote'] = 'Ukloni navodnike'; +jsToolBar.strings['Preformatted text'] = 'Prethodno formatiran tekst'; +jsToolBar.strings['Wiki link'] = 'Veza prema Wiki strani'; +jsToolBar.strings['Image'] = 'Slika'; diff --git a/public/javascripts/jstoolbar/lang/jstoolbar-sr.js b/public/javascripts/jstoolbar/lang/jstoolbar-sr.js index 0e231e02..75a768ad 100644 --- a/public/javascripts/jstoolbar/lang/jstoolbar-sr.js +++ b/public/javascripts/jstoolbar/lang/jstoolbar-sr.js @@ -1,16 +1,16 @@ -jsToolBar.strings = {}; -jsToolBar.strings['Strong'] = 'Podebljano'; -jsToolBar.strings['Italic'] = 'Kurziv'; -jsToolBar.strings['Underline'] = 'Podvučeno'; -jsToolBar.strings['Deleted'] = 'Obrisano'; -jsToolBar.strings['Code'] = 'Ugrađeni kôd'; -jsToolBar.strings['Heading 1'] = 'Naslov 1'; -jsToolBar.strings['Heading 2'] = 'Naslov 2'; -jsToolBar.strings['Heading 3'] = 'Naslov 3'; -jsToolBar.strings['Unordered list'] = 'Lista nabrajanja'; -jsToolBar.strings['Ordered list'] = 'Uređena lista'; -jsToolBar.strings['Quote'] = 'Pod navodnicima'; -jsToolBar.strings['Unquote'] = 'Ukloni navodnike'; -jsToolBar.strings['Preformatted text'] = 'Prethodno formatiran tekst'; -jsToolBar.strings['Wiki link'] = 'Veza prema Wiki strani'; -jsToolBar.strings['Image'] = 'Slika'; +jsToolBar.strings = {}; +jsToolBar.strings['Strong'] = 'Подебљано'; +jsToolBar.strings['Italic'] = 'Курзив'; +jsToolBar.strings['Underline'] = 'Подвучено'; +jsToolBar.strings['Deleted'] = 'Обрисано'; +jsToolBar.strings['Code'] = 'Уграђени кôд'; +jsToolBar.strings['Heading 1'] = 'Наслов 1'; +jsToolBar.strings['Heading 2'] = 'Наслов 2'; +jsToolBar.strings['Heading 3'] = 'Наслов 3'; +jsToolBar.strings['Unordered list'] = 'Листа набрајања'; +jsToolBar.strings['Ordered list'] = 'Уређена листа'; +jsToolBar.strings['Quote'] = 'Под наводницима'; +jsToolBar.strings['Unquote'] = 'Уклони наводнике'; +jsToolBar.strings['Preformatted text'] = 'Претходно форматиран текст'; +jsToolBar.strings['Wiki link'] = 'Веза према Wiki страни'; +jsToolBar.strings['Image'] = 'Слика'; From d60cc50d99b4509bb0f7ece323a0913a9cdecf03 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 22 Aug 2010 19:48:32 +0000 Subject: [PATCH 110/777] Merged r4004 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@4016 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- config/locales/bg.yml | 14 +++++++++----- config/locales/ca.yml | 4 ++++ config/locales/cs.yml | 6 +++++- config/locales/el.yml | 6 +++++- config/locales/en-GB.yml | 5 +++++ config/locales/eu.yml | 4 ++++ config/locales/hr.yml | 4 ++++ config/locales/lv.yml | 4 ++++ config/locales/mn.yml | 4 ++++ config/locales/nl.yml | 6 +++++- config/locales/ru.yml | 4 ++-- config/locales/sl.yml | 7 ++++--- config/locales/sr-YU.yml | 4 ++++ config/locales/sr.yml | 6 +++++- config/locales/th.yml | 6 +++++- config/locales/uk.yml | 4 ++++ 16 files changed, 73 insertions(+), 15 deletions(-) diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 8b2b2370..320c2091 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -63,7 +63,11 @@ bg: one: "almost 1 year" other: "almost {{count}} years" - number: + number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: precision: 1 @@ -71,13 +75,13 @@ bg: storage_units: format: "%n %u" units: - kb: KB - tb: TB - gb: GB byte: one: Byte other: Bytes - mb: 'MB' + kb: "KB" + mb: "MB" + gb: "GB" + tb: "TB" # Used in array.to_sentence. support: diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 1e47d3d6..913d2f3a 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -64,6 +64,10 @@ ca: other: "almost {{count}} years" number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: delimiter: "" diff --git a/config/locales/cs.yml b/config/locales/cs.yml index de4ad44c..9ceb21e8 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -63,7 +63,11 @@ cs: one: "almost 1 year" other: "almost {{count}} years" - number: + number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: precision: 1 diff --git a/config/locales/el.yml b/config/locales/el.yml index a9146a61..cb4941c2 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -66,7 +66,11 @@ el: one: "almost 1 year" other: "almost {{count}} years" - number: + number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: precision: 1 diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 118efbb4..ad99fec7 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -64,6 +64,11 @@ en-GB: other: "almost {{count}} years" number: + format: + separator: "." + delimiter: " " + precision: 3 + currency: format: format: "%u%n" diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 741d3298..350f238c 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -68,6 +68,10 @@ eu: other: "ia {{count}} urte" number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: delimiter: "" diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 728a6d8e..442adefe 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -64,6 +64,10 @@ hr: other: "preko {{count}} godina" number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: delimiter: "" diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 351f8528..70822de5 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -61,6 +61,10 @@ lv: other: "gandrīz {{count}} gadus" number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: delimiter: " " diff --git a/config/locales/mn.yml b/config/locales/mn.yml index 568e1f34..5b4b79e8 100644 --- a/config/locales/mn.yml +++ b/config/locales/mn.yml @@ -64,6 +64,10 @@ mn: other: "бараг {{count}} жил" number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: delimiter: "" diff --git a/config/locales/nl.yml b/config/locales/nl.yml index f2e0529e..46c5ca86 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -63,7 +63,11 @@ nl: one: "almost 1 year" other: "almost {{count}} years" - number: + number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: precision: 1 diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 4812e2ad..468be454 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -41,7 +41,7 @@ ru: number: format: - separator: "." + separator: "," delimiter: " " precision: 3 @@ -64,7 +64,7 @@ ru: human: format: delimiter: "" - precision: 1 + precision: 2 # Rails 2.2 # storage_units: [байт, КБ, МБ, ГБ, ТБ] diff --git a/config/locales/sl.yml b/config/locales/sl.yml index aac2e433..a51cd972 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -63,10 +63,11 @@ sl: one: "almost 1 year" other: "almost {{count}} years" - number: + number: format: - separator: ',' - delimiter: '.' + separator: "," + delimiter: "." + precision: 3 human: format: precision: 1 diff --git a/config/locales/sr-YU.yml b/config/locales/sr-YU.yml index 2cc0c098..bc8a854a 100644 --- a/config/locales/sr-YU.yml +++ b/config/locales/sr-YU.yml @@ -66,6 +66,10 @@ sr-YU: other: "skoro {{count}} god." number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: delimiter: "" diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 1bcd3616..0c022ee9 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -66,6 +66,10 @@ sr: other: "скоро {{count}} год." number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: delimiter: "" @@ -904,4 +908,4 @@ sr: enumeration_doc_categories: Категорије документа enumeration_activities: Активности (праћење времена) enumeration_system_activity: Системска активност - \ No newline at end of file + diff --git a/config/locales/th.yml b/config/locales/th.yml index 2c127f3d..eaf4cc28 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -63,7 +63,11 @@ th: one: "almost 1 year" other: "almost {{count}} years" - number: + number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: precision: 1 diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 1a590dc0..951a546b 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -64,6 +64,10 @@ uk: other: "almost {{count}} years" number: + format: + separator: "." + delimiter: "" + precision: 3 human: format: precision: 1 From 86e986f01452ecf3c2bdf8156f2e0d2c8c0dee07 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sun, 22 Aug 2010 19:48:38 +0000 Subject: [PATCH 111/777] Merged r4005 from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/branches/1.0-stable@4017 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/layouts/base.rhtml | 1 + config/locales/bg.yml | 1 + config/locales/bs.yml | 1 + config/locales/ca.yml | 1 + config/locales/cs.yml | 1 + config/locales/da.yml | 1 + config/locales/de.yml | 1 + config/locales/el.yml | 1 + config/locales/en-GB.yml | 1 + config/locales/en.yml | 7 +++++ config/locales/es.yml | 1 + config/locales/eu.yml | 1 + config/locales/fi.yml | 1 + config/locales/fr.yml | 1 + config/locales/gl.yml | 1 + config/locales/he.yml | 1 + config/locales/hr.yml | 1 + config/locales/hu.yml | 1 + config/locales/id.yml | 1 + config/locales/it.yml | 1 + config/locales/ja.yml | 1 + config/locales/ko.yml | 1 + config/locales/lt.yml | 1 + config/locales/lv.yml | 1 + config/locales/mn.yml | 1 + config/locales/nl.yml | 1 + config/locales/no.yml | 1 + config/locales/pl.yml | 1 + config/locales/pt-BR.yml | 1 + config/locales/pt.yml | 1 + config/locales/ro.yml | 1 + config/locales/ru.yml | 1 + config/locales/sk.yml | 1 + config/locales/sl.yml | 1 + config/locales/sr-YU.yml | 1 + config/locales/sr.yml | 1 + config/locales/sv.yml | 1 + config/locales/th.yml | 1 + config/locales/tr.yml | 1 + config/locales/uk.yml | 1 + config/locales/vi.yml | 1 + config/locales/zh-TW.yml | 1 + config/locales/zh.yml | 1 + .../application.css => stylesheets/rtl.css} | 28 +++++++++++++++---- .../themes/rtl/stylesheets/context_menu.css | 6 ---- 45 files changed, 71 insertions(+), 12 deletions(-) rename public/{themes/rtl/stylesheets/application.css => stylesheets/rtl.css} (76%) delete mode 100644 public/themes/rtl/stylesheets/context_menu.css diff --git a/app/views/layouts/base.rhtml b/app/views/layouts/base.rhtml index 2daae7cb..0393815b 100644 --- a/app/views/layouts/base.rhtml +++ b/app/views/layouts/base.rhtml @@ -7,6 +7,7 @@ <%= favicon %> <%= stylesheet_link_tag 'application', :media => 'all' %> +<%= stylesheet_link_tag 'rtl', :media => 'all' if l(:direction) == 'rtl' %> <%= javascript_include_tag :defaults %> <%= heads_for_wiki_formatter %> <%= yield :header_tags -%> - +

    From be4e4c80f754e8c70314bca0734d22f36b0472d2 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Mon, 28 Feb 2011 20:23:28 +0000 Subject: [PATCH 317/777] Stringify avatar to prevent "can't convert nil into String" errors on gantt (#7317). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4968 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/helpers/gantt.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb index c0490e60..1279cb5e 100644 --- a/lib/redmine/helpers/gantt.rb +++ b/lib/redmine/helpers/gantt.rb @@ -357,7 +357,7 @@ module Redmine subject = "" if issue.assigned_to.present? assigned_string = l(:field_assigned_to) + ": " + issue.assigned_to.name - subject << view.avatar(issue.assigned_to, :class => 'gravatar icon-gravatar', :size => 10, :title => assigned_string) + subject << view.avatar(issue.assigned_to, :class => 'gravatar icon-gravatar', :size => 10, :title => assigned_string).to_s end subject << view.link_to_issue(issue) subject << '' From 8eaa4d10e5cb343fa03c960e2e1e333c058445a6 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 04:43:30 +0000 Subject: [PATCH 318/777] scm: add notes "local repository" in Git and Mercurial setting. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4974 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/repositories_helper.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 329e0daf..841ea3b9 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -190,11 +190,13 @@ module RepositoriesHelper end def mercurial_field_tags(form, repository) - content_tag('p', form.text_field(:url, :label => :label_mercurial_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) + content_tag('p', form.text_field(:url, :label => :label_mercurial_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) + + '
    local repository (e.g. /hgrepo, c:\hgrepo)' ) end def git_field_tags(form, repository) - content_tag('p', form.text_field(:url, :label => :label_git_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) + content_tag('p', form.text_field(:url, :label => :label_git_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) + + '
    a bare and local repository (e.g. /gitrepo, c:\gitrepo)') end def cvs_field_tags(form, repository) From 9c3c35e8b814a3c468d42238619215b92c665909 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 05:14:03 +0000 Subject: [PATCH 319/777] scm: add scm specific human_attribute_name for input validation. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4975 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/repository/bazaar.rb | 7 +++++++ app/models/repository/cvs.rb | 8 ++++++++ app/models/repository/darcs.rb | 7 +++++++ app/models/repository/filesystem.rb | 7 +++++++ app/models/repository/git.rb | 7 +++++++ app/models/repository/mercurial.rb | 7 +++++++ 6 files changed, 43 insertions(+) diff --git a/app/models/repository/bazaar.rb b/app/models/repository/bazaar.rb index 9d7977e7..d68fabc9 100644 --- a/app/models/repository/bazaar.rb +++ b/app/models/repository/bazaar.rb @@ -21,6 +21,13 @@ class Repository::Bazaar < Repository attr_protected :root_url validates_presence_of :url + ATTRIBUTE_KEY_NAMES = { + "url" => "Root directory", + } + def self.human_attribute_name(attribute_key_name) + ATTRIBUTE_KEY_NAMES[attribute_key_name] || super + end + def self.scm_adapter_class Redmine::Scm::Adapters::BazaarAdapter end diff --git a/app/models/repository/cvs.rb b/app/models/repository/cvs.rb index 1c479d1b..e3dfced6 100644 --- a/app/models/repository/cvs.rb +++ b/app/models/repository/cvs.rb @@ -21,6 +21,14 @@ require 'digest/sha1' class Repository::Cvs < Repository validates_presence_of :url, :root_url + ATTRIBUTE_KEY_NAMES = { + "url" => "CVSROOT", + "root_url" => "Module", + } + def self.human_attribute_name(attribute_key_name) + ATTRIBUTE_KEY_NAMES[attribute_key_name] || super + end + def self.scm_adapter_class Redmine::Scm::Adapters::CvsAdapter end diff --git a/app/models/repository/darcs.rb b/app/models/repository/darcs.rb index dc3f0cee..c6d7cafd 100644 --- a/app/models/repository/darcs.rb +++ b/app/models/repository/darcs.rb @@ -20,6 +20,13 @@ require 'redmine/scm/adapters/darcs_adapter' class Repository::Darcs < Repository validates_presence_of :url + ATTRIBUTE_KEY_NAMES = { + "url" => "Root directory", + } + def self.human_attribute_name(attribute_key_name) + ATTRIBUTE_KEY_NAMES[attribute_key_name] || super + end + def self.scm_adapter_class Redmine::Scm::Adapters::DarcsAdapter end diff --git a/app/models/repository/filesystem.rb b/app/models/repository/filesystem.rb index 4be6b528..f06ad97c 100644 --- a/app/models/repository/filesystem.rb +++ b/app/models/repository/filesystem.rb @@ -24,6 +24,13 @@ class Repository::Filesystem < Repository attr_protected :root_url validates_presence_of :url + ATTRIBUTE_KEY_NAMES = { + "url" => "Root directory", + } + def self.human_attribute_name(attribute_key_name) + ATTRIBUTE_KEY_NAMES[attribute_key_name] || super + end + def self.scm_adapter_class Redmine::Scm::Adapters::FilesystemAdapter end diff --git a/app/models/repository/git.rb b/app/models/repository/git.rb index 63faea66..fb5c26a7 100644 --- a/app/models/repository/git.rb +++ b/app/models/repository/git.rb @@ -21,6 +21,13 @@ class Repository::Git < Repository attr_protected :root_url validates_presence_of :url + ATTRIBUTE_KEY_NAMES = { + "url" => "Path to repository", + } + def self.human_attribute_name(attribute_key_name) + ATTRIBUTE_KEY_NAMES[attribute_key_name] || super + end + def self.scm_adapter_class Redmine::Scm::Adapters::GitAdapter end diff --git a/app/models/repository/mercurial.rb b/app/models/repository/mercurial.rb index 98575a56..021e60b0 100644 --- a/app/models/repository/mercurial.rb +++ b/app/models/repository/mercurial.rb @@ -26,6 +26,13 @@ class Repository::Mercurial < Repository FETCH_AT_ONCE = 100 # number of changesets to fetch at once + ATTRIBUTE_KEY_NAMES = { + "url" => "Root directory", + } + def self.human_attribute_name(attribute_key_name) + ATTRIBUTE_KEY_NAMES[attribute_key_name] || super + end + def self.scm_adapter_class Redmine::Scm::Adapters::MercurialAdapter end From 57298dcc82b4de078a84933e4aa75b32cba1d47f Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 05:49:14 +0000 Subject: [PATCH 320/777] scm: code clean up at test/unit/changeset_test.rb. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4976 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/changeset_test.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/test/unit/changeset_test.rb b/test/unit/changeset_test.rb index d1dbb44e..3884096b 100644 --- a/test/unit/changeset_test.rb +++ b/test/unit/changeset_test.rb @@ -259,7 +259,6 @@ class ChangesetTest < ActiveSupport::TestCase def test_comments_should_be_converted_all_latin1_to_utf8 with_settings :commit_logs_encoding => 'ISO-8859-1' do - c = Changeset.new s1 = "\xC2\x80" s2 = "\xc3\x82\xc2\x80" if s1.respond_to?(:force_encoding) From 57455eff5fa07d0e359f20744603ddc76d0727ce Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 07:03:21 +0000 Subject: [PATCH 321/777] scm: bazaar: change project id of unit app test from 1 to 3. Project id 1 has Subversion fixtures. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4977 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/repository_bazaar_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/repository_bazaar_test.rb b/test/unit/repository_bazaar_test.rb index 55d3b8a2..38f2af49 100644 --- a/test/unit/repository_bazaar_test.rb +++ b/test/unit/repository_bazaar_test.rb @@ -25,7 +25,7 @@ class RepositoryBazaarTest < ActiveSupport::TestCase REPOSITORY_PATH.gsub!(/\/+/, '/') def setup - @project = Project.find(1) + @project = Project.find(3) assert @repository = Repository::Bazaar.create(:project => @project, :url => "file:///#{REPOSITORY_PATH}") end From e5619d536837bae4c9abce28993439df90ab45f9 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 07:12:56 +0000 Subject: [PATCH 322/777] scm: darcs: change project id of unit app test from 1 to 3. Project id 1 has Subversion fixtures. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4978 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/repository_darcs_test.rb | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/test/unit/repository_darcs_test.rb b/test/unit/repository_darcs_test.rb index d470bebf..ef833e93 100644 --- a/test/unit/repository_darcs_test.rb +++ b/test/unit/repository_darcs_test.rb @@ -19,25 +19,26 @@ require File.expand_path('../../test_helper', __FILE__) class RepositoryDarcsTest < ActiveSupport::TestCase fixtures :projects - + # No '..' in the repository path REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/darcs_repository' - + def setup - @project = Project.find(1) - assert @repository = Repository::Darcs.create(:project => @project, :url => REPOSITORY_PATH) + @project = Project.find(3) + @repository = Repository::Darcs.create(:project => @project, :url => REPOSITORY_PATH) + assert @repository end - + if File.directory?(REPOSITORY_PATH) def test_fetch_changesets_from_scratch @repository.fetch_changesets @repository.reload - + assert_equal 6, @repository.changesets.count assert_equal 13, @repository.changes.count assert_equal "Initial commit.", @repository.changesets.find_by_revision('1').comments end - + def test_fetch_changesets_incremental @repository.fetch_changesets # Remove changesets with revision > 3 @@ -48,8 +49,10 @@ class RepositoryDarcsTest < ActiveSupport::TestCase @repository.fetch_changesets assert_equal 6, @repository.changesets.count end - + def test_deleted_files_should_not_be_listed + @repository.fetch_changesets + @repository.reload entries = @repository.entries('sources') assert entries.detect {|e| e.name == 'watchers_controller.rb'} assert_nil entries.detect {|e| e.name == 'welcome_controller.rb'} From aae9747e65cd75f78572c74fd2878ec8139ed5e6 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 07:38:05 +0000 Subject: [PATCH 323/777] scm: darcs: refactor functional test. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4979 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- .../repositories_darcs_controller_test.rb | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/test/functional/repositories_darcs_controller_test.rb b/test/functional/repositories_darcs_controller_test.rb index 0a5d57a8..a315f9fa 100644 --- a/test/functional/repositories_darcs_controller_test.rb +++ b/test/functional/repositories_darcs_controller_test.rb @@ -26,26 +26,33 @@ class RepositoriesDarcsControllerTest < ActionController::TestCase # No '..' in the repository path REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/darcs_repository' + PRJ_ID = 3 def setup @controller = RepositoriesController.new @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil - Repository::Darcs.create(:project => Project.find(3), :url => REPOSITORY_PATH) + @project = Project.find(PRJ_ID) + @repository = Repository::Darcs.create(:project => @project, :url => REPOSITORY_PATH) + assert @repository end - + if File.directory?(REPOSITORY_PATH) def test_show - get :show, :id => 3 + @repository.fetch_changesets + @repository.reload + get :show, :id => PRJ_ID assert_response :success assert_template 'show' assert_not_nil assigns(:entries) assert_not_nil assigns(:changesets) end - + def test_browse_root - get :show, :id => 3 + @repository.fetch_changesets + @repository.reload + get :show, :id => PRJ_ID assert_response :success assert_template 'show' assert_not_nil assigns(:entries) @@ -54,9 +61,11 @@ class RepositoriesDarcsControllerTest < ActionController::TestCase assert assigns(:entries).detect {|e| e.name == 'sources' && e.kind == 'dir'} assert assigns(:entries).detect {|e| e.name == 'README' && e.kind == 'file'} end - + def test_browse_directory - get :show, :id => 3, :path => ['images'] + @repository.fetch_changesets + @repository.reload + get :show, :id => PRJ_ID, :path => ['images'] assert_response :success assert_template 'show' assert_not_nil assigns(:entries) @@ -66,27 +75,31 @@ class RepositoriesDarcsControllerTest < ActionController::TestCase assert_equal 'file', entry.kind assert_equal 'images/edit.png', entry.path end - + def test_browse_at_given_revision - Project.find(3).repository.fetch_changesets - get :show, :id => 3, :path => ['images'], :rev => 1 + @repository.fetch_changesets + @repository.reload + get :show, :id => PRJ_ID, :path => ['images'], :rev => 1 assert_response :success assert_template 'show' assert_not_nil assigns(:entries) assert_equal ['delete.png'], assigns(:entries).collect(&:name) end - + def test_changes - get :changes, :id => 3, :path => ['images', 'edit.png'] + @repository.fetch_changesets + @repository.reload + get :changes, :id => PRJ_ID, :path => ['images', 'edit.png'] assert_response :success assert_template 'changes' assert_tag :tag => 'h2', :content => 'edit.png' end - + def test_diff - Project.find(3).repository.fetch_changesets + @repository.fetch_changesets + @repository.reload # Full diff of changeset 5 - get :diff, :id => 3, :rev => 5 + get :diff, :id => PRJ_ID, :rev => 5 assert_response :success assert_template 'diff' # Line 22 removed From ab8bdf282b01cc99c7ab18b0b24427e77d6d8a7c Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 09:47:06 +0000 Subject: [PATCH 324/777] scm: add log_encoding column to repositories table (#1735). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4980 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- .../20110228000000_add_repositories_log_encoding.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 db/migrate/20110228000000_add_repositories_log_encoding.rb diff --git a/db/migrate/20110228000000_add_repositories_log_encoding.rb b/db/migrate/20110228000000_add_repositories_log_encoding.rb new file mode 100644 index 00000000..85cadafc --- /dev/null +++ b/db/migrate/20110228000000_add_repositories_log_encoding.rb @@ -0,0 +1,9 @@ +class AddRepositoriesLogEncoding < ActiveRecord::Migration + def self.up + add_column :repositories, :log_encoding, :string, :limit => 64, :default => nil + end + + def self.down + remove_column :repositories, :log_encoding + end +end From 231fcf6fd8f0269a737d652b6ffe00df7ca2a462 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 10:14:47 +0000 Subject: [PATCH 325/777] scm: copy global log encoding setting to repository (#1735). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4981 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- ...228000100_copy_repositories_log_encoding.rb | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 db/migrate/20110228000100_copy_repositories_log_encoding.rb diff --git a/db/migrate/20110228000100_copy_repositories_log_encoding.rb b/db/migrate/20110228000100_copy_repositories_log_encoding.rb new file mode 100644 index 00000000..4d975f80 --- /dev/null +++ b/db/migrate/20110228000100_copy_repositories_log_encoding.rb @@ -0,0 +1,18 @@ +class CopyRepositoriesLogEncoding < ActiveRecord::Migration + def self.up + encoding = Setting.commit_logs_encoding.to_s.strip + encoding = encoding.blank? ? 'UTF-8' : encoding + Repository.find(:all).each do |repo| + scm = repo.scm_name + case scm + when 'Subversion', 'Mercurial', 'Git', 'Filesystem' + repo.update_attribute(:log_encoding, nil) + else + repo.update_attribute(:log_encoding, encoding) + end + end + end + + def self.down + end +end From e383414c31284e816f5230414c125cb42056febe Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 10:27:30 +0000 Subject: [PATCH 326/777] scm: add feature of per project repository log encoding setting (#1735). Subversion, Mercurial and Git supports UTF-8 log. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4982 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/repositories_helper.rb | 12 ++++++++--- app/models/repository.rb | 2 +- app/models/repository/bazaar.rb | 3 ++- app/models/repository/cvs.rb | 3 ++- app/models/repository/darcs.rb | 3 ++- .../repositories_bazaar_controller_test.rb | 12 +++++++---- .../repositories_cvs_controller_test.rb | 3 ++- .../repositories_darcs_controller_test.rb | 4 +++- test/unit/changeset_test.rb | 21 ++++++++++--------- test/unit/helpers/application_helper_test.rb | 4 +++- test/unit/repository_bazaar_test.rb | 7 +++++-- test/unit/repository_cvs_test.rb | 8 ++++--- test/unit/repository_darcs_test.rb | 4 +++- test/unit/repository_test.rb | 11 ++++++---- 14 files changed, 63 insertions(+), 34 deletions(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 841ea3b9..4bea43d2 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -186,7 +186,9 @@ module RepositoriesHelper end def darcs_field_tags(form, repository) - content_tag('p', form.text_field(:url, :label => :label_darcs_path, :size => 60, :required => true, :disabled => (repository && !repository.new_record?))) + content_tag('p', form.text_field(:url, :label => :label_darcs_path, :size => 60, :required => true, :disabled => (repository && !repository.new_record?))) + + content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS, + :label => 'Commit messages encoding', :required => true)) end def mercurial_field_tags(form, repository) @@ -201,11 +203,15 @@ module RepositoriesHelper def cvs_field_tags(form, repository) content_tag('p', form.text_field(:root_url, :label => :label_cvs_path, :size => 60, :required => true, :disabled => !repository.new_record?)) + - content_tag('p', form.text_field(:url, :label => :label_cvs_module, :size => 30, :required => true, :disabled => !repository.new_record?)) + content_tag('p', form.text_field(:url, :label => :label_cvs_module, :size => 30, :required => true, :disabled => !repository.new_record?)) + + content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS, + :label => 'Commit messages encoding', :required => true)) end def bazaar_field_tags(form, repository) - content_tag('p', form.text_field(:url, :label => :label_bazaar_path, :size => 60, :required => true, :disabled => (repository && !repository.new_record?))) + content_tag('p', form.text_field(:url, :label => :label_bazaar_path, :size => 60, :required => true, :disabled => (repository && !repository.new_record?))) + + content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS, + :label => 'Commit messages encoding', :required => true)) end def filesystem_field_tags(form, repository) diff --git a/app/models/repository.rb b/app/models/repository.rb index bddbbbec..07e24af2 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -191,7 +191,7 @@ class Repository < ActiveRecord::Base end def repo_log_encoding - encoding = Setting.commit_logs_encoding.to_s.strip + encoding = log_encoding.to_s.strip encoding.blank? ? 'UTF-8' : encoding end diff --git a/app/models/repository/bazaar.rb b/app/models/repository/bazaar.rb index d68fabc9..3ae8b28f 100644 --- a/app/models/repository/bazaar.rb +++ b/app/models/repository/bazaar.rb @@ -19,10 +19,11 @@ require 'redmine/scm/adapters/bazaar_adapter' class Repository::Bazaar < Repository attr_protected :root_url - validates_presence_of :url + validates_presence_of :url, :log_encoding ATTRIBUTE_KEY_NAMES = { "url" => "Root directory", + "log_encoding" => "Commit messages encoding", } def self.human_attribute_name(attribute_key_name) ATTRIBUTE_KEY_NAMES[attribute_key_name] || super diff --git a/app/models/repository/cvs.rb b/app/models/repository/cvs.rb index e3dfced6..2ee82a74 100644 --- a/app/models/repository/cvs.rb +++ b/app/models/repository/cvs.rb @@ -19,11 +19,12 @@ require 'redmine/scm/adapters/cvs_adapter' require 'digest/sha1' class Repository::Cvs < Repository - validates_presence_of :url, :root_url + validates_presence_of :url, :root_url, :log_encoding ATTRIBUTE_KEY_NAMES = { "url" => "CVSROOT", "root_url" => "Module", + "log_encoding" => "Commit messages encoding", } def self.human_attribute_name(attribute_key_name) ATTRIBUTE_KEY_NAMES[attribute_key_name] || super diff --git a/app/models/repository/darcs.rb b/app/models/repository/darcs.rb index c6d7cafd..c8870e29 100644 --- a/app/models/repository/darcs.rb +++ b/app/models/repository/darcs.rb @@ -18,10 +18,11 @@ require 'redmine/scm/adapters/darcs_adapter' class Repository::Darcs < Repository - validates_presence_of :url + validates_presence_of :url, :log_encoding ATTRIBUTE_KEY_NAMES = { "url" => "Root directory", + "log_encoding" => "Commit messages encoding", } def self.human_attribute_name(attribute_key_name) ATTRIBUTE_KEY_NAMES[attribute_key_name] || super diff --git a/test/functional/repositories_bazaar_controller_test.rb b/test/functional/repositories_bazaar_controller_test.rb index 5f7de1de..576b710c 100644 --- a/test/functional/repositories_bazaar_controller_test.rb +++ b/test/functional/repositories_bazaar_controller_test.rb @@ -32,9 +32,13 @@ class RepositoriesBazaarControllerTest < ActionController::TestCase @request = ActionController::TestRequest.new @response = ActionController::TestResponse.new User.current = nil - Repository::Bazaar.create(:project => Project.find(3), :url => REPOSITORY_PATH) + @project = Project.find(3) + @repository = Repository::Bazaar.create( + :project => @project, :url => REPOSITORY_PATH, + :log_encoding => 'UTF-8') + assert @repository end - + if File.directory?(REPOSITORY_PATH) def test_show get :show, :id => 3 @@ -43,7 +47,7 @@ class RepositoriesBazaarControllerTest < ActionController::TestCase assert_not_nil assigns(:entries) assert_not_nil assigns(:changesets) end - + def test_browse_root get :show, :id => 3 assert_response :success @@ -53,7 +57,7 @@ class RepositoriesBazaarControllerTest < ActionController::TestCase assert assigns(:entries).detect {|e| e.name == 'directory' && e.kind == 'dir'} assert assigns(:entries).detect {|e| e.name == 'doc-mkdir.txt' && e.kind == 'file'} end - + def test_browse_directory get :show, :id => 3, :path => ['directory'] assert_response :success diff --git a/test/functional/repositories_cvs_controller_test.rb b/test/functional/repositories_cvs_controller_test.rb index ca040e3f..6a6be388 100644 --- a/test/functional/repositories_cvs_controller_test.rb +++ b/test/functional/repositories_cvs_controller_test.rb @@ -41,7 +41,8 @@ class RepositoriesCvsControllerTest < ActionController::TestCase @project = Project.find(PRJ_ID) @repository = Repository::Cvs.create(:project => Project.find(PRJ_ID), :root_url => REPOSITORY_PATH, - :url => MODULE_NAME) + :url => MODULE_NAME, + :log_encoding => 'UTF-8') assert @repository end diff --git a/test/functional/repositories_darcs_controller_test.rb b/test/functional/repositories_darcs_controller_test.rb index a315f9fa..d78149ca 100644 --- a/test/functional/repositories_darcs_controller_test.rb +++ b/test/functional/repositories_darcs_controller_test.rb @@ -34,7 +34,9 @@ class RepositoriesDarcsControllerTest < ActionController::TestCase @response = ActionController::TestResponse.new User.current = nil @project = Project.find(PRJ_ID) - @repository = Repository::Darcs.create(:project => @project, :url => REPOSITORY_PATH) + @repository = Repository::Darcs.create( + :project => @project, :url => REPOSITORY_PATH, + :log_encoding => 'UTF-8') assert @repository end diff --git a/test/unit/changeset_test.rb b/test/unit/changeset_test.rb index 3884096b..767192db 100644 --- a/test/unit/changeset_test.rb +++ b/test/unit/changeset_test.rb @@ -220,12 +220,13 @@ class ChangesetTest < ActiveSupport::TestCase changeset = Changeset.find_by_revision('10') assert_nil changeset.next end - + def test_comments_should_be_converted_to_utf8 - with_settings :commit_logs_encoding => 'ISO-8859-1' do proj = Project.find(3) str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") - r = Repository::Bazaar.create!(:project => proj, :url => '/tmp/test/bazaar') + r = Repository::Bazaar.create!( + :project => proj, :url => '/tmp/test/bazaar', + :log_encoding => 'ISO-8859-1' ) assert r c = Changeset.new(:repository => r, :committed_on => Time.now, @@ -234,14 +235,14 @@ class ChangesetTest < ActiveSupport::TestCase :comments => str) assert( c.save ) assert_equal "Texte encodé en ISO-8859-1.", c.comments - end end def test_invalid_utf8_sequences_in_comments_should_be_stripped - with_settings :commit_logs_encoding => 'UTF-8' do proj = Project.find(3) str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") - r = Repository::Bazaar.create!(:project => proj, :url => '/tmp/test/bazaar') + r = Repository::Bazaar.create!( + :project => proj, :url => '/tmp/test/bazaar', + :log_encoding => 'UTF-8' ) assert r c = Changeset.new(:repository => r, :committed_on => Time.now, @@ -254,11 +255,9 @@ class ChangesetTest < ActiveSupport::TestCase else assert_equal "Texte encod en ISO-8859-1.", c.comments end - end end def test_comments_should_be_converted_all_latin1_to_utf8 - with_settings :commit_logs_encoding => 'ISO-8859-1' do s1 = "\xC2\x80" s2 = "\xc3\x82\xc2\x80" if s1.respond_to?(:force_encoding) @@ -271,7 +270,10 @@ class ChangesetTest < ActiveSupport::TestCase assert_equal s3.encode('UTF-8'), s4 end proj = Project.find(3) - r = Repository::Bazaar.create!(:project => proj, :url => '/tmp/test/bazaar') + r = Repository::Bazaar.create!( + :project => proj, :url => '/tmp/test/bazaar', + :log_encoding => 'ISO-8859-1' ) + assert r assert r c = Changeset.new(:repository => r, :committed_on => Time.now, @@ -280,7 +282,6 @@ class ChangesetTest < ActiveSupport::TestCase :comments => s1) assert( c.save ) assert_equal s2, c.comments - end end def test_identifier diff --git a/test/unit/helpers/application_helper_test.rb b/test/unit/helpers/application_helper_test.rb index 69eaf745..aa2c6277 100644 --- a/test/unit/helpers/application_helper_test.rb +++ b/test/unit/helpers/application_helper_test.rb @@ -292,7 +292,9 @@ RAW 'commit:20080308225258-98289-abcd456efg.gz' => changeset_link, } @project = Project.find(3) - r = Repository::Darcs.create!(:project => @project, :url => '/tmp/test/darcs') + r = Repository::Darcs.create!( + :project => @project, :url => '/tmp/test/darcs', + :log_encoding => 'UTF-8') assert r c = Changeset.new(:repository => r, :committed_on => Time.now, diff --git a/test/unit/repository_bazaar_test.rb b/test/unit/repository_bazaar_test.rb index 38f2af49..b2515fe3 100644 --- a/test/unit/repository_bazaar_test.rb +++ b/test/unit/repository_bazaar_test.rb @@ -19,14 +19,17 @@ require File.expand_path('../../test_helper', __FILE__) class RepositoryBazaarTest < ActiveSupport::TestCase fixtures :projects - + # No '..' in the repository path REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/bazaar_repository' REPOSITORY_PATH.gsub!(/\/+/, '/') def setup @project = Project.find(3) - assert @repository = Repository::Bazaar.create(:project => @project, :url => "file:///#{REPOSITORY_PATH}") + @repository = Repository::Bazaar.create( + :project => @project, :url => "file:///#{REPOSITORY_PATH}", + :log_encoding => 'UTF-8') + assert @repository end if File.directory?(REPOSITORY_PATH) diff --git a/test/unit/repository_cvs_test.rb b/test/unit/repository_cvs_test.rb index a5da09f5..0fd81615 100644 --- a/test/unit/repository_cvs_test.rb +++ b/test/unit/repository_cvs_test.rb @@ -28,9 +28,11 @@ class RepositoryCvsTest < ActiveSupport::TestCase def setup @project = Project.find(3) - assert @repository = Repository::Cvs.create(:project => @project, - :root_url => REPOSITORY_PATH, - :url => MODULE_NAME) + @repository = Repository::Cvs.create(:project => @project, + :root_url => REPOSITORY_PATH, + :url => MODULE_NAME, + :log_encoding => 'UTF-8') + assert @repository end if File.directory?(REPOSITORY_PATH) diff --git a/test/unit/repository_darcs_test.rb b/test/unit/repository_darcs_test.rb index ef833e93..2e16973c 100644 --- a/test/unit/repository_darcs_test.rb +++ b/test/unit/repository_darcs_test.rb @@ -25,7 +25,9 @@ class RepositoryDarcsTest < ActiveSupport::TestCase def setup @project = Project.find(3) - @repository = Repository::Darcs.create(:project => @project, :url => REPOSITORY_PATH) + @repository = Repository::Darcs.create( + :project => @project, :url => REPOSITORY_PATH, + :log_encoding => 'UTF-8') assert @repository end diff --git a/test/unit/repository_test.rb b/test/unit/repository_test.rb index 252230b2..9bf22df2 100644 --- a/test/unit/repository_test.rb +++ b/test/unit/repository_test.rb @@ -126,16 +126,19 @@ class RepositoryTest < ActiveSupport::TestCase assert_not_equal( comment, changeset.comments ) assert_equal( 'This is a loooooooooooooooooooooooooooong comment', changeset.comments ) end - + def test_for_urls_strip - repository = Repository::Cvs.create(:project => Project.find(4), :url => ' :pserver:login:password@host:/path/to/the/repository', - :root_url => 'foo ') + repository = Repository::Cvs.create( + :project => Project.find(4), + :url => ' :pserver:login:password@host:/path/to/the/repository', + :root_url => 'foo ', + :log_encoding => 'UTF-8') assert repository.save repository.reload assert_equal ':pserver:login:password@host:/path/to/the/repository', repository.url assert_equal 'foo', repository.root_url end - + def test_manual_user_mapping assert_no_difference "Changeset.count(:conditions => 'user_id <> 2')" do c = Changeset.create!(:repository => @repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.') From 1c5e441b65bff3f92347cd53defbffab1443351d Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 10:27:51 +0000 Subject: [PATCH 327/777] scm: remove global repository log encoding setting from view (#1735). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4983 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/settings/_repositories.rhtml | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/views/settings/_repositories.rhtml b/app/views/settings/_repositories.rhtml index 9f2b26d4..7f892c2d 100644 --- a/app/views/settings/_repositories.rhtml +++ b/app/views/settings/_repositories.rhtml @@ -18,8 +18,6 @@

    <%= setting_text_field :repositories_encodings, :size => 60 %>
    <%= l(:text_comma_separated) %>

    -

    <%= setting_select :commit_logs_encoding, Setting::ENCODINGS %>

    -

    <%= setting_text_field :repository_log_display_limit, :size => 6 %>

    From a9a6abe40a98f3ddbcf44fe4882f89dd02cb65e2 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Tue, 1 Mar 2011 15:35:27 +0000 Subject: [PATCH 328/777] scm: code clean up test/unit/changeset_test.rb. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4984 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/changeset_test.rb | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/unit/changeset_test.rb b/test/unit/changeset_test.rb index 767192db..4da43d1c 100644 --- a/test/unit/changeset_test.rb +++ b/test/unit/changeset_test.rb @@ -185,12 +185,12 @@ class ChangesetTest < ActiveSupport::TestCase assert_equal [2], c.issue_ids.sort assert c.issues.first.project != c.project end - + def test_text_tag_revision c = Changeset.new(:revision => '520') assert_equal 'r520', c.text_tag end - + def test_text_tag_hash c = Changeset.new(:scmid => '7234cb2750b63f47bff735edc50a1c0a433c2518', :revision => '7234cb2750b63f47bff735edc50a1c0a433c2518') assert_equal 'commit:7234cb2750b63f47bff735edc50a1c0a433c2518', c.text_tag @@ -236,7 +236,7 @@ class ChangesetTest < ActiveSupport::TestCase assert( c.save ) assert_equal "Texte encodé en ISO-8859-1.", c.comments end - + def test_invalid_utf8_sequences_in_comments_should_be_stripped proj = Project.find(3) str = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") @@ -274,7 +274,6 @@ class ChangesetTest < ActiveSupport::TestCase :project => proj, :url => '/tmp/test/bazaar', :log_encoding => 'ISO-8859-1' ) assert r - assert r c = Changeset.new(:repository => r, :committed_on => Time.now, :revision => '123', From b91649ab41358f2810b47ee66e90f7266654eb8f Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Wed, 2 Mar 2011 05:12:15 +0000 Subject: [PATCH 329/777] scm: code clean up repositories_helper.rb. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4985 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/repositories_helper.rb | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 4bea43d2..b820eadd 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -151,19 +151,31 @@ module RepositoriesHelper def repository_field_tags(form, repository) method = repository.class.name.demodulize.underscore + "_field_tags" - send(method, form, repository) if repository.is_a?(Repository) && respond_to?(method) && method != 'repository_field_tags' + if repository.is_a?(Repository) && + respond_to?(method) && method != 'repository_field_tags' + send(method, form, repository) + end end - + def scm_select_tag(repository) scm_options = [["--- #{l(:actionview_instancetag_blank_option)} ---", '']] Redmine::Scm::Base.all.each do |scm| - scm_options << ["Repository::#{scm}".constantize.scm_name, scm] if Setting.enabled_scm.include?(scm) || (repository && repository.class.name.demodulize == scm) + if Setting.enabled_scm.include?(scm) || + (repository && repository.class.name.demodulize == scm) + scm_options << ["Repository::#{scm}".constantize.scm_name, scm] + end end - select_tag('repository_scm', options_for_select(scm_options, repository.class.name.demodulize), :disabled => (repository && !repository.new_record?), - :onchange => remote_function(:url => { :controller => 'repositories', :action => 'edit', :id => @project }, :method => :get, :with => "Form.serialize(this.form)") + :onchange => remote_function( + :url => { + :controller => 'repositories', + :action => 'edit', + :id => @project + }, + :method => :get, + :with => "Form.serialize(this.form)") ) end From c54cd8a088118cce7f4013ad4d3706b69d1be465 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Wed, 2 Mar 2011 05:12:39 +0000 Subject: [PATCH 330/777] scm: git: add more tests in fetch changesets incremental unit model test (#5357). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4986 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/repository_git_test.rb | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/test/unit/repository_git_test.rb b/test/unit/repository_git_test.rb index baa17641..c6e2d837 100644 --- a/test/unit/repository_git_test.rb +++ b/test/unit/repository_git_test.rb @@ -61,8 +61,18 @@ class RepositoryGitTest < ActiveSupport::TestCase # Remove the 3 latest changesets @repository.changesets.find(:all, :order => 'committed_on DESC', :limit => 3).each(&:destroy) @repository.reload - assert_equal 13, @repository.changesets.count - + cs1 = @repository.changesets + assert_equal 13, cs1.count + + rev_a_commit = @repository.changesets.find(:first, :order => 'committed_on DESC') + assert_equal '4f26664364207fa8b1af9f8722647ab2d4ac5d43', rev_a_commit.revision + # Mon Jul 5 22:34:26 2010 +0200 + rev_a_committed_on = Time.gm(2010, 7, 5, 20, 34, 26) + assert_equal '4f26664364207fa8b1af9f8722647ab2d4ac5d43', rev_a_commit.scmid + assert_equal rev_a_committed_on, rev_a_commit.committed_on + latest_rev = @repository.latest_changeset + assert_equal rev_a_committed_on, latest_rev.committed_on + @repository.fetch_changesets assert_equal 16, @repository.changesets.count end From fb4601221aac6fae724115f29efd0c8e73fcea53 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Wed, 2 Mar 2011 07:10:39 +0000 Subject: [PATCH 331/777] scm: subversion: add changesets order test in unit model test (#5357). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4987 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/repository_subversion_test.rb | 28 +++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/unit/repository_subversion_test.rb b/test/unit/repository_subversion_test.rb index 158f17c5..c111956a 100644 --- a/test/unit/repository_subversion_test.rb +++ b/test/unit/repository_subversion_test.rb @@ -159,6 +159,34 @@ class RepositorySubversionTest < ActiveSupport::TestCase assert_equal s2, c.comments end end + + def test_previous + @repository.fetch_changesets + @repository.reload + changeset = @repository.find_changeset_by_name('3') + assert_equal @repository.find_changeset_by_name('2'), changeset.previous + end + + def test_previous_nil + @repository.fetch_changesets + @repository.reload + changeset = @repository.find_changeset_by_name('1') + assert_nil changeset.previous + end + + def test_next + @repository.fetch_changesets + @repository.reload + changeset = @repository.find_changeset_by_name('2') + assert_equal @repository.find_changeset_by_name('3'), changeset.next + end + + def test_next_nil + @repository.fetch_changesets + @repository.reload + changeset = @repository.find_changeset_by_name('11') + assert_nil changeset.next + end else puts "Subversion test repository NOT FOUND. Skipping unit tests !!!" def test_fake; assert true end From ce16f4a27873fa1c8d12bbe009ad2540fd3fac65 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Wed, 2 Mar 2011 07:11:00 +0000 Subject: [PATCH 332/777] scm: filesystem: add note "Default: UTF-8" in path encoding setting (#2274). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4988 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/repositories_helper.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index b820eadd..23899a88 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -229,7 +229,8 @@ module RepositoriesHelper def filesystem_field_tags(form, repository) content_tag('p', form.text_field(:url, :label => :label_filesystem_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) + content_tag('p', form.select(:path_encoding, [nil] + Setting::ENCODINGS, - :label => 'Path encoding')) + :label => 'Path encoding') + + '
    Default: UTF-8') end end From b00caa6e48c20102690d7efc76ab75a338f910e0 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Wed, 2 Mar 2011 10:17:36 +0000 Subject: [PATCH 333/777] scm: mercurial: wrap revison, tag and branch with URL encoding for entries (#4455, #1981, #7246). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4989 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/scm/adapters/mercurial/redminehelper.py | 2 +- lib/redmine/scm/adapters/mercurial_adapter.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/redmine/scm/adapters/mercurial/redminehelper.py b/lib/redmine/scm/adapters/mercurial/redminehelper.py index 9bca6c9b..e6c9182f 100644 --- a/lib/redmine/scm/adapters/mercurial/redminehelper.py +++ b/lib/redmine/scm/adapters/mercurial/redminehelper.py @@ -140,7 +140,7 @@ def rhmanifest(ui, repo, path='', **opts): ui.write('\n') ui.write('\n' % _u(repo.root)) try: - _manifest(ui, repo, urllib.unquote_plus(path), opts.get('rev')) + _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev'))) finally: ui.write('\n') ui.write('\n') diff --git a/lib/redmine/scm/adapters/mercurial_adapter.rb b/lib/redmine/scm/adapters/mercurial_adapter.rb index 11eb66b6..c60eb99e 100644 --- a/lib/redmine/scm/adapters/mercurial_adapter.rb +++ b/lib/redmine/scm/adapters/mercurial_adapter.rb @@ -130,7 +130,7 @@ module Redmine def entries(path=nil, identifier=nil) p1 = scm_iconv(@path_encoding, 'UTF-8', path) - manifest = hg('rhmanifest', '-r', hgrev(identifier), + manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)), CGI.escape(without_leading_slash(p1.to_s))) do |io| begin ActiveSupport::XmlMini.parse(io.read)['rhmanifest']['repository']['manifest'] From 15abee2ee5dbcf5829bda9e5751cfa940ca5a8d7 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Thu, 3 Mar 2011 03:35:13 +0000 Subject: [PATCH 334/777] scm: mercurial: code clean up unit model test. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4991 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/repository_mercurial_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/repository_mercurial_test.rb b/test/unit/repository_mercurial_test.rb index 5b2c70e6..271ffe43 100644 --- a/test/unit/repository_mercurial_test.rb +++ b/test/unit/repository_mercurial_test.rb @@ -28,7 +28,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase @repository = Repository::Mercurial.create(:project => @project, :url => REPOSITORY_PATH) assert @repository end - + if File.directory?(REPOSITORY_PATH) def test_fetch_changesets_from_scratch @repository.fetch_changesets @@ -38,7 +38,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase assert_equal "Initial import.\nThe repository contains 3 files.", @repository.changesets.find_by_revision('0').comments end - + def test_fetch_changesets_incremental @repository.fetch_changesets # Remove changesets with revision > 2 @@ -49,7 +49,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase @repository.fetch_changesets assert_equal 17, @repository.changesets.count end - + def test_isodatesec # Template keyword 'isodatesec' supported in Mercurial 1.0 and higher if @repository.scm.class.client_version_above?([1, 0]) From ce01f49ca7ba9e854aa1469a65bf29edd14dfb25 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Thu, 3 Mar 2011 05:32:33 +0000 Subject: [PATCH 335/777] scm: fix unit tests fails in Ruby 1.9. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4992 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/scm/adapters/bazaar_adapter.rb | 2 +- lib/redmine/scm/adapters/cvs_adapter.rb | 2 +- lib/redmine/scm/adapters/darcs_adapter.rb | 2 +- lib/redmine/scm/adapters/git_adapter.rb | 2 +- lib/redmine/scm/adapters/mercurial_adapter.rb | 2 +- lib/redmine/scm/adapters/subversion_adapter.rb | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/redmine/scm/adapters/bazaar_adapter.rb b/lib/redmine/scm/adapters/bazaar_adapter.rb index 92a1d693..b39150de 100644 --- a/lib/redmine/scm/adapters/bazaar_adapter.rb +++ b/lib/redmine/scm/adapters/bazaar_adapter.rb @@ -43,7 +43,7 @@ module Redmine end def scm_command_version - scm_version = scm_version_from_command_line + scm_version = scm_version_from_command_line.dup if scm_version.respond_to?(:force_encoding) scm_version.force_encoding('ASCII-8BIT') end diff --git a/lib/redmine/scm/adapters/cvs_adapter.rb b/lib/redmine/scm/adapters/cvs_adapter.rb index 762e5c68..a557199a 100644 --- a/lib/redmine/scm/adapters/cvs_adapter.rb +++ b/lib/redmine/scm/adapters/cvs_adapter.rb @@ -43,7 +43,7 @@ module Redmine end def scm_command_version - scm_version = scm_version_from_command_line + scm_version = scm_version_from_command_line.dup if scm_version.respond_to?(:force_encoding) scm_version.force_encoding('ASCII-8BIT') end diff --git a/lib/redmine/scm/adapters/darcs_adapter.rb b/lib/redmine/scm/adapters/darcs_adapter.rb index 9b79e653..92864388 100644 --- a/lib/redmine/scm/adapters/darcs_adapter.rb +++ b/lib/redmine/scm/adapters/darcs_adapter.rb @@ -43,7 +43,7 @@ module Redmine end def darcs_binary_version - darcsversion = darcs_binary_version_from_command_line + darcsversion = darcs_binary_version_from_command_line.dup if darcsversion.respond_to?(:force_encoding) darcsversion.force_encoding('ASCII-8BIT') end diff --git a/lib/redmine/scm/adapters/git_adapter.rb b/lib/redmine/scm/adapters/git_adapter.rb index 6ad7426c..6d2c34ac 100644 --- a/lib/redmine/scm/adapters/git_adapter.rb +++ b/lib/redmine/scm/adapters/git_adapter.rb @@ -48,7 +48,7 @@ module Redmine end def scm_command_version - scm_version = scm_version_from_command_line + scm_version = scm_version_from_command_line.dup if scm_version.respond_to?(:force_encoding) scm_version.force_encoding('ASCII-8BIT') end diff --git a/lib/redmine/scm/adapters/mercurial_adapter.rb b/lib/redmine/scm/adapters/mercurial_adapter.rb index c60eb99e..a0f1db19 100644 --- a/lib/redmine/scm/adapters/mercurial_adapter.rb +++ b/lib/redmine/scm/adapters/mercurial_adapter.rb @@ -54,7 +54,7 @@ module Redmine # The hg version is expressed either as a # release number (eg 0.9.5 or 1.0) or as a revision # id composed of 12 hexa characters. - theversion = hgversion_from_command_line + theversion = hgversion_from_command_line.dup if theversion.respond_to?(:force_encoding) theversion.force_encoding('ASCII-8BIT') end diff --git a/lib/redmine/scm/adapters/subversion_adapter.rb b/lib/redmine/scm/adapters/subversion_adapter.rb index 9f1ccf7a..1fad6e3f 100644 --- a/lib/redmine/scm/adapters/subversion_adapter.rb +++ b/lib/redmine/scm/adapters/subversion_adapter.rb @@ -44,7 +44,7 @@ module Redmine end def svn_binary_version - scm_version = scm_version_from_command_line + scm_version = scm_version_from_command_line.dup if scm_version.respond_to?(:force_encoding) scm_version.force_encoding('ASCII-8BIT') end From ac227939ade8c6067f8de24182406f31ae14a787 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Thu, 3 Mar 2011 05:51:46 +0000 Subject: [PATCH 336/777] scm: Ruby 1.9 compatibility for XML UTF-8 parsing. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4993 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/scm/adapters/mercurial_adapter.rb | 18 +++++++++++++++--- lib/redmine/scm/adapters/subversion_adapter.rb | 12 ++++++++++++ 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/lib/redmine/scm/adapters/mercurial_adapter.rb b/lib/redmine/scm/adapters/mercurial_adapter.rb index a0f1db19..1f9153fa 100644 --- a/lib/redmine/scm/adapters/mercurial_adapter.rb +++ b/lib/redmine/scm/adapters/mercurial_adapter.rb @@ -120,8 +120,12 @@ module Redmine def summary return @summary if @summary hg 'rhsummary' do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end begin - @summary = ActiveSupport::XmlMini.parse(io.read)['rhsummary'] + @summary = ActiveSupport::XmlMini.parse(output)['rhsummary'] rescue end end @@ -132,8 +136,12 @@ module Redmine p1 = scm_iconv(@path_encoding, 'UTF-8', path) manifest = hg('rhmanifest', '-r', CGI.escape(hgrev(identifier)), CGI.escape(without_leading_slash(p1.to_s))) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end begin - ActiveSupport::XmlMini.parse(io.read)['rhmanifest']['repository']['manifest'] + ActiveSupport::XmlMini.parse(output)['rhmanifest']['repository']['manifest'] rescue end end @@ -175,9 +183,13 @@ module Redmine hg_args << '--limit' << options[:limit] if options[:limit] hg_args << hgtarget(path) unless path.blank? log = hg(*hg_args) do |io| + output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end begin # Mercurial < 1.5 does not support footer template for '' - ActiveSupport::XmlMini.parse("#{io.read}")['log'] + ActiveSupport::XmlMini.parse("#{output}")['log'] rescue end end diff --git a/lib/redmine/scm/adapters/subversion_adapter.rb b/lib/redmine/scm/adapters/subversion_adapter.rb index 1fad6e3f..59f577e6 100644 --- a/lib/redmine/scm/adapters/subversion_adapter.rb +++ b/lib/redmine/scm/adapters/subversion_adapter.rb @@ -65,6 +65,9 @@ module Redmine info = nil shellout(cmd) do |io| output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end begin doc = ActiveSupport::XmlMini.parse(output) #root_url = doc.elements["info/entry/repository/root"].text @@ -94,6 +97,9 @@ module Redmine cmd << credentials_string shellout(cmd) do |io| output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end begin doc = ActiveSupport::XmlMini.parse(output) each_xml_element(doc['lists']['list'], 'entry') do |entry| @@ -134,6 +140,9 @@ module Redmine properties = {} shellout(cmd) do |io| output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end begin doc = ActiveSupport::XmlMini.parse(output) each_xml_element(doc['properties']['target'], 'property') do |property| @@ -158,6 +167,9 @@ module Redmine cmd << ' ' + target(path) shellout(cmd) do |io| output = io.read + if output.respond_to?(:force_encoding) + output.force_encoding('UTF-8') + end begin doc = ActiveSupport::XmlMini.parse(output) each_xml_element(doc['log'], 'logentry') do |logentry| From 51d4785bde22ebc7bbde23dff0a9c5af526c5f94 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Thu, 3 Mar 2011 12:11:23 +0000 Subject: [PATCH 337/777] scm: mercurial: remove localtime from adapter (#4455). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4994 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/scm/adapters/mercurial_adapter.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/redmine/scm/adapters/mercurial_adapter.rb b/lib/redmine/scm/adapters/mercurial_adapter.rb index 1f9153fa..d41ed7a3 100644 --- a/lib/redmine/scm/adapters/mercurial_adapter.rb +++ b/lib/redmine/scm/adapters/mercurial_adapter.rb @@ -210,7 +210,7 @@ module Redmine yield Revision.new(:revision => le['revision'], :scmid => le['node'], :author => (le['author']['__content__'] rescue ''), - :time => Time.parse(le['date']['__content__']).localtime, + :time => Time.parse(le['date']['__content__']), :message => le['msg']['__content__'], :paths => paths) end From bea085c3ba21e660cace018929b3ee3cc818c72e Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Thu, 3 Mar 2011 12:44:14 +0000 Subject: [PATCH 338/777] scm: mercurial: convert copied file path encoding (#2664). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4995 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/scm/adapters/mercurial_adapter.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/redmine/scm/adapters/mercurial_adapter.rb b/lib/redmine/scm/adapters/mercurial_adapter.rb index d41ed7a3..6a2613fc 100644 --- a/lib/redmine/scm/adapters/mercurial_adapter.rb +++ b/lib/redmine/scm/adapters/mercurial_adapter.rb @@ -196,7 +196,9 @@ module Redmine as_ary(log['logentry']).each do |le| cpalist = as_ary(le['paths']['path-copied']).map do |e| - [e['__content__'], e['copyfrom-path']].map { |s| CGI.unescape(s) } + [e['__content__'], e['copyfrom-path']].map do |s| + scm_iconv('UTF-8', @path_encoding, CGI.unescape(s)) + end end cpmap = Hash[*cpalist.flatten] From fe4159fc99d3902155ee5f1dffc9ae09fc308b8c Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Fri, 4 Mar 2011 04:25:48 +0000 Subject: [PATCH 339/777] scm: mercurial: update test repository for path encoding (#2664). Mercurial (and also Git) treats file names as byte string. This mercurial test repository contains Latin-1 encoding path. Be careful on non Latin-1(CP1252) Windows. If your Windows is not Latin-1 Windows, in order to checkout(update) Latin-1 path, You need to use cygwin 1.7 and set LANG=en_US.ISO-8859-1. Please refer. http://mercurial.selenic.com/wiki/EncodingStrategy?action=recall&rev=6 Redmine mercurial adapter do not need to checkout(update) repository. Mercurial does not have "bare" repository such as Git. You can use "hg update null" for equivalent "bare" repository. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4996 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- .../repositories/mercurial_repository.hg | Bin 7104 -> 8902 bytes .../repositories_mercurial_controller_test.rb | 6 ++- .../scm/adapters/mercurial_adapter_test.rb | 37 +++++++++++++----- test/unit/repository_mercurial_test.rb | 14 ++++--- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/test/fixtures/repositories/mercurial_repository.hg b/test/fixtures/repositories/mercurial_repository.hg index c06844d235c3fad69b6e85f0b743f445f01f0cee..2b4eb62410643ae3c466665bab4f63dd0e7978e6 100644 GIT binary patch literal 8902 zcmaiWRa6uV)a}q+1Cj#_Fmw+f9YYSKbazWhN~$w-J3}`^w;-L;F?0(8N=bu+ilXTM z{de8hyY5+Q?{oIk*-!f%xR$t>s+EVVILwmA*z#KA=|2FD;p>0@zuE!6V-Hm`%juaN ztfA85iPzZKMi|gZ5+W1;lu_@t#8o30>rgMm0000b0&noY1|W#ZMCH3Y6BoxAOESAY zuErGe=!83XtQ0TS9xSY2Pn|Up3&z96%f|YW;usHVw<;bIWV+-xX5O;mJTX05eKDRm z9L=dPl7nUZg=j;P4E|#mN0M6f@yd6}kJ0)7=KoeOQ~WRe?*ssN{D=SK{}pQb02pj2>SKeqlKL;|5E#*r-62k=xa8++)j45msh>+3)D%%fV0 z&+y>C&ws;*EdZ9(g@@-oHC_pSvlOmo{9Vyt@e7ohaD~P2gxNz;O7dHAeo37o*UCb; zCtE&Z;jz9Nn2L4o^{%hjq9%ZRa{VQH9(h%EDt~`=CDx(nrt*u@E9DI7bG$+S$zE-Y zWo=l!scp$x9D%P5mkQ8UD$B4zR%h!79>S{)I9Vk`ASbHszjbO|0n z_vgnp#Nn5G@~`YZ93s9LuUqfp7Z5WsIE(ep=Z-#B?qz#+BqncY>msW#zdw6fTpNA~ zvL+-ucA{|JcF}8GqveKP<90p&(YfjRRHWL!s?q1@al7Pb0b%(|*+iy~o9jdch0ar7 ze6|P@Kc9KxNVr?KIsEMS^Ofv4?z7(djl8CiUr_j8^QR}1fvF+vOsh1G1sp>gXL5K@ zNE9h;;YDWnXVU3EhWIbtUD>&*iARx8j1FT@1Zmp|%=~RQ`E|*K2Nw}Bj~Ra?;yT%*($V(Y{OO9gUr|wNq#rRb;C*@QdQC}v zJWFbTikr61@a(@AM~WOIERHC$O(@(XC7oc(fjZ=~IF?v8!NKMbTI)yYSkOLt5E(k! zqVBH5RV;II(L+jdvUhE?*G2Fdf(^qX-fs5Z;5O8v%u%Am_#LaTapHlQnB$uNz4ss& zkIRd~3(qB%2M_8X6Un;7>|qWh;Vl6X%q6FbHMZ5HZ>N2@EMtW&^9_DwaiTE z+58HBe%{H^@-`8IcoO{O)96t}j`S`GPro{$uVbhhy(V+d<^gV*c59rnc$h`nRA@e5 z`f4d=V%dEYe{oN86YhsjkxbH}ahB$*tDAXQe#k$HekT%d@z0{^MlB2I(R}D&=yiKX z3sj<@%>m5{tXPZh$tC)WcI~l{t{40bAQ61H=gJqN4Cca$+jHbU?Yh{eRqQGu@~2Rf zZH}J(r5URAsXSuLIky!AOGx^_-wBj<36y-B-GN)V(O!rhJTZn4or7N$54S+TB@1x5aQi=(n zt{H2zNE&0c@Yno!%m<+5$Za5CP@}?8WDqvvgwX6%%)sf1mZ*Tu3xC3^9_FKp6l70+ zyV5F9)6hE~#O@A3Q^hfOsmD)jl2&pQ?K`uBanM7N##Wd#R;Q$#b-Kvt%f2}Wk-c9u zl)P5Jed>oay4lXJN=6UI#iMV{y{Qf)lwqN-%C48`Xe2emJuWEIB!2j#?Wg3+eRH3R zd=g0WXkvwFxQdQ`nV?b44zwOw{jE>1KEhaiiICH(@o(1J$2ka` zYdtCP*Kvva7HcfwjL88<7>`773a?X`?8w-S}A zt>4vc(myRekIH`XeljcYji29>I5wSp*JshpGW%u`!>6LU^h9;N>x7iY4I!?C#ffs5 z8+cYiuAU>pf0Rzo>K2Cs!^5fLY;DCov{5$d`oy8vB2>MCv1X!FTFjY*V>6RVyhUn> zCgnW~Q*14nYt6&@h7)lnn`f=E<+>#SWrgAY>L!2#QX5Z6kq z!&%l!2qfK_=Q$vCq2sS)O_@y|9p=#RTX0Hoi31@?wR-z9 zcLLDlOmUb@vmUpQ%2qtuXeNn08i~C9aZX3qgpZCdRBPs~yuNSQ>={jdZ!%#mYmQ`z2VLiQhdri=*gt!5L}m#} ztkv)+F22;kk{qoRt3KBQF^Dn#VaI zOK>4~v&9O@Mi2%KyhDnTJ`fyJB{-cSv7SBRFP^lP;40Hp6ITY%zG1X}^6teXa;z^n zqbc7#*getS0)I>9_As!}>37fz0=1P%1$?o7$V(%TKa=n**`1GWiTk zdQo~&YkZWDn}xDO!^AR@itJ+>+~HC1qL@#FUh7pB_9Ff^w(B`j1%&Ezz_v;i85z>`uE&TZb4J3z5FbsWLS9K zIX1ty2JXg<(^V#Bg3!k#i-T{Rv$P3xG6hsyqDWibvCaAIHZa478-FNM9sT+n@JsC_ zdPdu_BPTP0YXpz2PvzFE%x)n;k&$fgDZB?u32>EvZ?n7N9@A+Usgc1jY zOak^B+cS!o22|R4o$gmx+M~#xn0_=W7wfPvy6wG)B7VtsWku;J@Xn6F-Dph&&ch zd>q~|5;iAPB*W)@Z8UsM; zyb26LF~_54&Dp5I3nAq0DF^DL)sAF_-|B9dGN6GVmRd(Dy3njXc@Xz+03Ab{QDzWN zG^CUGqM^4}UJJ6@T;L^^$Kf^QH&ozwLO63qle{e3?yhV)JmR0WT6nu`05l4SYmWN!#pbBE#Zjb9>75oIS3yh9$F;1ofh(ONH?m zwa8PPr0Pgu73P3Z{SaWBnZDXtFFrkp=At!EL&|CJvn+os?a1-;OUybFSuKL4I{kvVo4zg&~qlGAQ*4Kv*|Jq5iva#uikPv@j5;H}Zui5nGh zJf>$&rPa0Z3h2t@qEWPvx&808`O^!t^-5COIb8^TyO!ecf;qNv^-%d-U&W!tF}4kC zCgAj(JXVToOE2o#VnwpGu)zqLI411|B|SR+9f#c{t~G%aOeez99WZDK4`x(YtLYJ2 z7&M$}IZC-$1ZL9z(9AS=Cg!K9prSAd{X4vC-<(GCtL(McnV%4!VEsOryp`di!@WT zccmD*lf{M%RLp{qN>Qrzj6_;W`&dQ6kEK%eozND0TS_w`O1DT?ug*2}3pl#kHi_|D zS$UhY8>%zmP0B#OffC0zuiJ0xE`IM@j!l^d48b890khXJBEvd{6>yCO)sK<%UGg3h z1#(?IBUO0qw0tKPmAYg=tB*HKR4>vRi>WUFDAG3&@?n7s%?v*5(hs$Ec97ags)rqU z++ILO!8V=9n?e8QZB(gegVrx%raF{vC>mM%7TAi$O+M8IQ#0g%-#3S&5WU5V;Y*`z z$l~d^1x4YotqlZn%f{YXqBaS%pgzU1YABcFR4B32%r|VkQ|}PUk-2wpPhN**9X&mG2o15pEow=l61o^vR~1Kv+}~sRIHiqV1Uwmrgb9u|G|+Hzby9qxWk|@1XEdun zdUn-K)5&k4!z4#KkG|nzCa0q?aEZ%myEn&~Jx0l<#2(xUEk)Ri%jRS|4waZ+v{#qE znW%rTTPQm=-#`;~_lF*#}kskG&)S()pcp?!&No9PykpVL0t@_cq;r}-4c zi>$0A%<#gk$O>D03YUia8!GfiMKY3UMg!4ySZtn2Qsu{bi z#oFN=1+oqIXj#`h3&gI+SO+P8|AzCCe{0IkMyB(wa;%I^oDBD=Vn}trpg=;p2QAac z7B#f?k>A71)kCfc>wz9RDErheANI+>G&3M(n=$Qq+6TOo{9!OcG~sobVSGRy4c``f zir+xw$5}#^k&a&ph#)`0Hb{h>E4yCmJmH|3YLpV>FqzYrdaH#!!Jz3!DvRR;ypfU1 zV)(w|Qzmb*Ae+nCmkjkEtxlOxNw55*m4+xLIJ>#KRpbxp%!rk6jdlo@vW%ccxsHDm0y-ehX@x zokq~CEavFyn9zUcH<#fs@8dq)lPxdMglW2^B>GwY5LoQq2l4eD9urkN; zkKogR_7yO>q|76`@2!g!$$ACn;(OYSivOtjnKuHJ>A5IssKJMk}k@m@fe^l|b{ z!7qt3-ty!}nR5-mOe^iOkje_Z*k8^N2@b5;3(Eb~BJJse(;1 zxz&jfdD(a!M(VT{Neqb(&h21n|5-vT&7+W-RKqQ~c8A9uBS%D%g^PO{o2vOECdpp< zoAW}t?jnLy{-^i{z}fo?d>j^W`0mj;q5aumJwvkq!6kZ$Qqv6-nW7fmOPS`sA>ZPA zl1Ok~_#3~7Fxy(2{WoK+(0yX&m`8n#p*FPKKJxweE>jPco7@n1ZY&@-Y15S=Y4 z0C`nFw;sacou{=31V7nJ!WWmX`jzt(RJ6>Uyp@{OKHOdr$1Re^9&^)@48+Gu99%Hx81M4yn$Pe=!yreXT+*0)?- zTA!(=M;_v;*y#%~N}O(ijMn7vV(;htbvWO=r~rd zahXV@GjZ8*LSRVojo?o+l$Obfy>m|en?1H68iGD|z0z^tGTBio2(O z`JKe`6YvJj$f%@I`w`7pE=RfTarjB@FPJ2(s6pJx0~2iC>3uUFHMu8QOk2~Je?c}c z$Q1eqfTnG#7DqII*1{0&Y4y8XX;S;NWW_??Y;g9vWO4oCyvqo@)RJ8Y9rp`WT)qun z=kbBrzBfOLA=`^3&QsTc5tKsJ$Fi*wZE<^W=LWSc5knlNDrlF)ToZUD-9CMEU&_JM zrw^=a?nV~WoV%$ALuDE=>IuxC18;@E0=oUlP!1NdXF0_1)5EbnfOUPral1&wHC&% zFrI2_w&2e5AIum|D5%`*pjbSRY`>f&XBwo$Djgz;4Ro%HbxqAVWE!{=q~*AB19_ot zpxIbtu3HrQvV5)cw4>p))-@Hsgi69bFZ^3B#riaG)&ID3HI+y+%I!12lXbR3w^Q|wGHZM-4G(G1Xgt){Yj#EcwGiPOd z{@H#KS~q{7Zm!%Qbhc%-4J*9UiY8*MVP)OkN8>cl`sE38#FzRRL4cZwy~)3w zj1Sw-)yHzpHP9&yE;#+QYITrPqgMasUW){q0!0(3gJYB_&;T~LJ4J9UP8;Qyo@qdD zap2eTs2=Wv+0*4$2g}?>zPfto&yiv&lS}x_zJu-HT`~`enq|t1Td-vqA9T{3v7`R@ zrR8KqorxPY#U0Ff_zL>H{I76%VJ&SOS+v3uC~f9|O(y-stk<9i+TlPwxRo}~$u6IM zClm5J{7%c8ydPO7SfwM>3~nDvlA2Vf$y9{%f-$!Ei>|XCmRvPyk{l{58(5Hn1}dwu2Upngsb+6lKtmUnPv-?<1IEU@9KnSast@ zML!^o5xFcpo~|WynXTcASSCpvQ16Hrk_d14g1lJ#oIF4_Z6m~MtSN>Gy|0hY#b%GT zM2j8ZG3Tkm&agCukFHEvu7}T|s#!1rFgc>=pu%YsCiCG934wQ_jRVnFeACHrQ$>No z?Bn$&til(U&FJX_LZYlO*<-eNvYD}m?OV61$2mYd%iA|77g3Ks?j;}Kuy-pV(Bd$B zi2Q&IbCKUDi}L;kC}ig}VNrX%y1=X7aJ^s0gV+^)dBebP8le@jH9$OfO}Qd3{0QYl z_4D9QA(A`n!F%NQZnpR-M?7FeOl&;#0JR&F*n%W@O0z{Wo!I3_ye3`sHh>07V1$D* zdBVd4#m#w+7w%5&kSCxPYNUb~?zW_Zd5l^gq7dVN`@LB-?MIkF3HTswmz4>?4PhfY zTSr6mU=(z?8SZok?;aYRuh;{eYuI?g9P6K9r;X$S9j7?qzDJ|7G&gIMS^trVUZ%gr;#fSM znRU4zUL-~dlFJQV?~Cxug1^gxRkHTf^x$J?btT;gg?kYGyMbkUc692x7alc zY{+Bmv^T>Hk|bxuX)g+T_XJB81vUkK2vv?V#xk{@zf>GmBI{;9iayE z@UGn1elD2lc5mUedbu&A+bD)~*h99lR_iWj^AWg^ITYG4@rs!X=+k_&PLe`Fzu$$G*`9zZ3#X z+-uBGzwmA~ybD31sjty%v`x8xvzcGs2)(fr|FcuWMJ!G1zIaVuZHue{@3XbTx+Udq z6Wg1U*&g8SvX)?3t3ZHSxsl6UD}~wI!~%L^+4Q%^pf#6POY-Y(Z*eD?`WM}EsV8C# z6CHr2_JAVDDxnH-59#_r*A|_})_{a`>Ina=&6lxVjX2#g56MuS-9#}rgRh~bGQ5!5 zPLmojiA&Q!eQ2_P%#CN^6ZHepILdI#<5u|UKGyF=sQn7)k4mJDtfLwtzH8#rO4{v; zMfG$3pQP+09-#>)VCQe?i2hN#(r;Y5yJpNv4K7~=g~M(M#$yk+sw5r%SZZMTeT_ETP{d@RkAB=)MI1%|D@?wsf!t4{wiAbY-; zpnx&b6j38sSVAY|7e-H-AJh+@mu@5)=d)Pw%9DVIgeBm;9;xEkj+QkVZ$!7K=byof$K>!3S2KSSdqXu3 z8u%K6?BL9WA%vZ$E%Jm2{wZWn&*Y@Vw3zF-PApt#5U); zjk5ypar`@{bYaHIm784Sx}Iiy`;bGK3DF|)bT*ce+HuXVXg`1DyXL!HU$>nvHs!$A=dskK3+F2(Z7E__G(tYawJ#Wx(ewAuz7hGrKr=x@U#LSI0S2ISI`KRS3lfu&EY2HuaM7Dj?$x8XpC<^#_`#Jo@p#7 zae4?pMoWKT6TebjeaH9lFM<4 zK%%L5=wu*T{uD+lq!&W@SSY1$@N=cbr^W8V8;VrMlFc_d&HNO|iP7D#8VpX8DQFYD zx%YE2xdi(9lD^HOax&-s!d5``W7caem(TitkcUWTNi&|N;RC%Ncp&5a@9~s8;%xgh zuV{F8?O?N^;+?t%=5Ln$Oj18LjqB{)n^}&%|3S=!Va;u?UyaUZa_(|?Rfe)$jb!ME zC@RFOR|dH=KX9WL|R=VDm9c zH|SP{ng{lgaD%+f*Tu;x^q=9PMZ!-dhxb@p?gBR2#9LqE_O^7yDQao{vNb7lw7q|t z_92j*7nJCaoUqGd){Aqb`7E7C|0%6=?R&7gKiwmjOsE3BFDFPp`t&zJym^2J*^X8+ z*+(|6{u(j-x@5I;DhCvET8Z*ga3!|^)=aAT-ojD zduDZ^lg+=eCio{NG!+V^eZK+juP0v)y^uZb#j9|ba6k7RIk+h>dV?J`xZ+8z z`ugS{-h}s#KfyJh)Ax&CH{IvF>b@V%^;}01+VM7bG>5uu%JdGzQ)FIUFuvvPstA=Y z58A8+ugKbQ4~}x}&k}tAkBdbyd5I+s=!UER99!*zz5d)_qq#mGHUFaw{pfZnYrmV=8^5;z9c2wq-IcD)6qsLh6do6tsh#!9cLi}l>tz8%($G>w{-Jt!IYt+jg%){z3KeJG4V+PuYdjz DiQ#Fz literal 7104 zcmaizRa6uXwDpJX9J(ZjhG7^Q6c`vn8l;f{hHj)oX$BZ_=65aQ*N9r%$^qq_TeucFvFr z00#--NB{u9nw81!aS+F?Ru?5rAjGLDP|fz=md+j06rD~paALuK(W+3Do`Gn3Wn1K zK$rqp0x+|%;FJMyDwP2g{}JSW6aOb(En>l>FcZZBN9Ynbp-zc~unZ5TZ{Xqrz~f~3 z&j?m~!8!NDj)|2KgAuf+wxi~Yaw|9g<|QiI|nsi8RF*cA>}!9Rs+8?_yD^Y9H< zeZkt(0{9HZO}Dn{R^y9PZ9NMlL<+j9+YMWR5*3tW-IP>%(p|#dJ<+Bzes{xjtMlI# z8g+#6oH)i`wM~@sXAhKDp}l{nQa{2vYOzj_{5!V)-mos$l=OQk`&o$HzEN5qX#=P+ z`Ak!DZH$im&anSuf4uv9G7_Hv@mN)0ohDqcsEkuJfU0UhR9wiMQzhU?2_-by{f14RyZs1n=>i5;TgZ) zN0df^0q>Xy*x8EWT8P%OgCnbIGe2Cry4DG8h6S#fW$7gL@7p%6lMtf>oU?115LA5+ z*wzUQMubl+PeJ@45^}J4+nw!KetN+woau>n=bs4Z=$v!X^?FF_sbY-E3Sen^N;)Q4 zHwoIQ>gt8%ZSnN@Lx!)J!qMJCLxT20UOz@XA!qH|0Z%{3XY8{G21Rr?oQEWNje1MF zzL|zLL0$OBgRS`-qF*fbcm%Yxb?*CJXwBJu`RYeYVdKp954rEn!p1>iga;upw|H{C zm0JdonxtkOR8`+~#f4CCKF4U0p=b5;2CEWhkS6i?o|)hP(-$BR582dgnd}M0y3qkAQN~a z7i8TH9bY71ABV2O-+JHClL<*(*uM?yuO}TP+x!;a-rZ_68@2TLdfu>f(-!iN&Wl89 z@CTS>@19w)JNqsdGH~FQ;?>JF&$h>=QJUB@vad108_L}Q31lz7lH^!5@azrqdl+*kT#UoB|Nn= z^5ZF5y8r9Yw6nivldtjTVIYJKh_PiMS2|76vEq^C|G@`mehA*`#xqJxDBcA z{2SvH{K{jug85p@-e5rz*P`PW&%t3RG04X?Sn*oXnSt=fUw#Dh^^fuzsqWb1XF-YBPHHg)I$VM4d`{Lh%?`6tEEH!jK<14IXqZ*(UolAt z{^QZ)=5koAY+d{!u86qXK^^J(L!wmL4%dgedBhM>u3K%en0{b+K|Dt!7fZF&^bogK zC)Tr4<>RyM#Pquq@wA~xw`r~zSu7SfjpnE$t?DIMJ>%!_9hnuUkN-!_$}V%|xzEr; zPGAoPs`NvjTUsT@izHr*E z&CB*=R^UbpuM|0^PPjtu^W7GmYi%K1BvabPpuq%6uehN+6q$X_=Ha-``J8{OQbISR zLrdFU3QvNTHwng!-mlXXM@Yy?_%s>Ls|Rp5vUX}xLSA?{*cCEb@9R)Hix+I-r;?!g z%B{#8{kj@B@;Ve-i3IjRdUi>RB--0YZsf>#M%o;WW+@eDnKm19qp>5DRK|=YB!qP; zZFP2R^OFAObu9jB%pDrP^=I>MK6+pB{3}|Sb{X|P{eSW{kzRB}A3&L}d2GH&zGaQf zfHnLPsZdkud~W{fR>!2MORSAb>+RnFm@`6Z6xlr`;-$_}Rl7W)9TIQ|547Q$N+n(h)nfymd0X6q)l2@JNu&H>J92Y@4JtNUm-$mS}67?rNVTYdgBK*L1 zJk*n3WLtSX)&{SBbjauGcKb@<0>l5|POYYS3$2{2C3L{?s@sTt`O46|2iA33Me_Da z_>ax&5lpsa@p`qq&xY5f4jx+;P>9T@HX@IeX?@k+6CG+Pk{jIVu%}jU@)T^JDkq3@ zFRUbn^)a!a?McUy^Qan-S0Kmh1G(CAabnv$yL-8sfMWUHP%`Km%YqaNBqqZb6^==V zcocZqXVIXTu-N!Cx16_bS7hTCNSQU7bnj@N#24lH@vUt}4 z1G4fK^z&jOBTij~1O{V@mKa*N-0L@_X%&9{I3h})wKO-I$PI2MaO}c;DK(LqBiasP zm<8q`VvdR(t?E*qXJBKfVkWa=B_=U)>;?gA`i26ZtEl}}xyePMHhnQI1Ja(A&=h&H z1}j_Uk0;|CmPdUl%`%ghZ>apG)61P5;*~}_vWQ*B@ax(kZqOnN79L|05pe~=Mr#h0 zG|?Hn*_jrYKOr<)&)r!fCv+U~0WA97Dpo~Jkk|4&IUNtbZ{IJIB1M4O9RggElyN8^ z?B1w#hJ25AP|!U#8IMnRV|=qbBCMSKX%W=uqxt^U#@@eHofFk+XwjyAW1`wfG|xo? zT9HtX0Sgg2L?7lkMoDrpVma`^4dfm{;XVv6nKVk%jz+sR-MPLK+d8qJT;55s8SAO* zY{eK3onf*%HriF@&NZ02GpCn-`Q;!0zAlDU^-fV#_7BhG__M=1AZG=3LK z*2F`DdC5^#qb^lX*o2tK1(x;6#}95{RTL|lnD&heH^Tk{xXJ+0IP-<&iYR^%YvWr9 zB~IjD;_|YMS;YMoQ*b=zmA51upHbZ7S)Dfiu@L@lujAL3&1BQblZjYRy9wQ6mmZES zI`fU}Ds^KQk&1PToN-1M%)6~1KaTBV4POReMEZay5#vW0$^$>Wc* zj*%mK#g_Yl)mqU$$yzNzyo5VzA;**9zlaVh?j{Z5cbAx$Xr70B5u;Yi+1a#Lg*P%j zR`SNI%}paNKAwLQ*kpMTxX~huB5X$`@+S;3Qv0JjRyJJ}xddlq%3P`VRoo*7XZ&W@ zw4OC7s`Mbe%lv`D)0KA#ys!+$sDNn79_H=*W}Vg=-#Ld=R8|6`bhSC%oU@k?cRbnXUDPN&Y$MA4>aG2w`gBlgJ5cj6 z3s-y76Ao97T`7#U!~ly+p~ zJ)L^Eo!kB1eaFD_jEj378vm~|8I!l^Vu9^4)i;T}i7yZ~n)WLJQ~2O*m-MlH&Ra#R zSai+nler@S;>tDp^Jtn^JQxX`lJ(65zFV%{@d9D;d&u#aAiM8Gb1AaZLQ{uEBK&i5 z)J5E&ueXjBeyxde_wSL0aLkkIe_xDWi2uq#G5#F-b@AB8|K1i~0n-%s$|a2o@qzQZ z;Yof1T)c;P8>-tq*2gwCHT7cso+D%PAkd7mYGYGz74Z}BvQ6Xw+9F6&Yl|AvNXC29PxO1^3`B3W=l@J3ZTBlVwNA>^)#oNiT!yvD zG2_s=EzSMq(?oJR=FGNm<0`6Ys+Ee}B&N&XDiddg*Rir~)lYxSvwwZcb~nu0x_)Q0KF@qDjUJ8^ zPC8qnNa-05+DoA|;OkG3*XE8{$T3LQ(Pln8zG9X<=ll=?xb&MIy>`09Y23dp$FfmU zGb;wKIQ=X*y9X>f!6r6eiz{^ZFDSjMN|5($5E6ldYHu8l|(eUgC(2*r@ZtiAr#o&p?OcL4C22q7r8K+^z>Mg6)Gmj{%L>j)i?&#FA ziLA_1W@w!+*kcZGKo?#&gamEz3S-x>N0PD)S9w-ZF_Ij#wVx(l$^E9(s=1fAK-<{# zGi)rUV{|#bH1fkK+S=6o^(Ozw2X^Lk(EFe=6T$FN{SZhzrAWEzO3zOVe+ai2gQM(Y z*;E25I5VB~);Dd?HbqH5j2og$7Y?9giWG$dgjX)Pzr5YzjkXxzAx5aRFwFsO#kfVH zh{8VUWkzV}CFg{SiLo(pQz6Rqkn&4=bNLvFsPr+w98H37;IlhyA^u=8#r$%gOr{r9 zNR{*yGhWU#x9Bfl*p+U73D@^=#}!d?mm%z{OEHGAt}^4!dJi1J#Gpw4#2$gBPV`$a zh2tF13Nvm%>}`*fQ*EG@bw7GGOCzjuL4kP80*_3<)ZkCywc>TlG8bmvmQ=z;`#!D* zdlZ!2;}hc)NRZh*=Z!hy#f$X7qnX`<$0b6+dfw|mm17n?9tOVr3}}m?rZ9;}$GiR- zB|#(h!YcGxLH=l=QJh`~D_(^DAKl9`BPkQW zE&We@(gcFxWfk}UGmlED3TbEU!rO|j!|5@^hi-(g`TWQbaqQV=yKyrruf=hM1#9L^ zorFL?_c9qm(R7Mak9s~wxu$%g0uOw-zzGRO1kYswIBuInG#QVDa2@Fc@fp%*fb@`! zYJV~Sy*r6e8CcU;Gr9ugs>PiRL|ZDjEa)`f6s0K;Mb(#AS52Pw6;khwzI#_d1@Bnf z0KE@LI)X}tO@44bNDlz*n+EUO*D|PLx2iy^;r1p-pLTCb?c2KaBAY7Ki!!Si)@e%u zUXdez+1=F%-Lx9o>1tYOX_cs)62U44ywqJXQ<%XjQYH+szBQfG%(5zp7CJE8%M>Tf z#MfXB<*yipqy%wA_7GHxWh5-_FXoYWpXZO5mGTLxQp($W(g ztv5Q7S3A;#8ghqD%vkGbedAw?gmRA|lTB-ZjWJ1pdizPtbP|NQTx`_xL^%;5NC2rb zF-JP;{LRm5sIRFX$Rxo%oC0v3N zc0ou2{3E-UUBD8ZHK#I*ti;Y_o91u+BktO>e$PzEKS4c~lCy za!jSvD7kPwT}k!m7YJ@gSr#Wbj>3$lS`rcS*r;-sS{oSeM}^>dNw&CF=00n{rxNWB z&!{6TAyM{(#|hi_kg1crRaS=B*T#AFHqi&7J=nH_k1-^|lYS!wQNdRpLf3gI=nH1@Jx+c)n>R=qeB19+F%GG>mM6&)I=Y*P?a)gOaelfpMD zRHybMvzjX1Ps6ecg(Jv$VUtYD1*C?l^CoiU3*Udyd-`?OD{h4`WPQ8shk93vTiqXgHlgY?{FI|2yoN6H2l^UXC{c>1<1`UGfDf3- zoziyia){NUl*j5h6uqqsIdA1Sm3=ZK7(_C0xE#l|43_8*_!WA^{(D}AiI!x7f_)kn zL>nYJ__)wY55F^&sRe*V=RX@EH;xu5i{7Az?Amv$8$~+$DR<3cb4`_T2WW&c6P;wKi(Gr%m&-YN0Fo@&Cc2pm^2e6Ca=G3$HaF? zREDYjq8)62hiO`5NioCt$(5s-RxW?_+P!}Io>4jP77^gk<)tKN8)=XU1t#+lS5*sC zcZo!io@&MabX*=z^K*`W9)ms*D2hU7YEW5^Bji_ho$wD)E34_!`rzXm92>#5+Cc&r zeS=LV{|rCY2B~=VPp>8a#znsFNAZ{;BL%Z|*OmBTv64I1?X~3!Y98o$7xNS`X=T#z zOJelzA~|yDKP^pOJc7+bmfV_&IPuteE2(k+aK0ubbMy4mZueAU^GMO*d#1y#Jm2>4 z*)QU=wi^D~k^KC$=bFWh4@fK~Uh!MtPyRXW&#Oz45Wb@XEKH~zO|*f2@JQlHOA5$Ow0Nk z5_VsIV{d7<-lBm*- z74oCmTcRUo3V+JYjzdiaYH*|+6(i2PvN(y@>nm|Jx6bTDu)e}`t4J6?FY_0?ZLyWl z7aJb>M)OF7O4cZ7%Hb?{0WlVo5&Aro9>J+)KE3$EJS!^p&HbOCtGQ$x--Lj_o#Pd2 z%td~Z(@`cMzXZiJgJ$*1qTvqgxG$4;=aG@5ux|a>%LGfktx%%T)j(2;ztwEqs1mB# zX@@h775r~YMwRO4MRFd5%y5tV8 z9S66C3#0yysly+K3lj+jlXPCmmC*c5%G&#QaROd1N^OuUfijs2fQT9K(%xWQK%S6{AXWKu6z9vG(q|v<3f#%Qc2g=MeHiR# z@jcvRV!ch8h{{Hoc&nw*A{Y4%nrR3lnyDUfqO9E5ARiv$HR`-h(+~=61^#Sy$a^Bc z($!Rb=UnyVhiRkOJ_es++m3@bUrXC|sw~tJ76*PpVF`s^hB|>8DOJ z+rKLZI_DVex@&gecPQ@ybsW*|zrf^^tSP&>bwl=d{-0uY#g1|u8C=-S@NKd>U-IBc zU*_s65JERkHQb!IsBabaDX--&J334QBC0&WK{DlkNxvFC?8Yv6hwMh2n4!%WzaDc_ zIQu*s*k@*%>?+t&Y})smit{n8gy*iL_UQ(&*b9kjXeV!qx`=Yi8pRUE?IOs zd5IXqzVv$XZVyJpa45^WcAddYo`>r+w1&Dgs(%K{r|%3QdKFsRCS*z&0_i^n!qgq` zc0aM-F&)X5?5 Project.find(3), :url => REPOSITORY_PATH) + @repository = Repository::Mercurial.create( + :project => Project.find(3), + :url => REPOSITORY_PATH, + :path_encoding => 'ISO-8859-1' + ) assert @repository @diff_c_support = true end diff --git a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb index d275798c..b5629841 100644 --- a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb +++ b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb @@ -10,10 +10,19 @@ begin REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/mercurial_repository' + CHAR_1_HEX = "\xc3\x9c" + if File.directory?(REPOSITORY_PATH) def setup @adapter = Redmine::Scm::Adapters::MercurialAdapter.new(REPOSITORY_PATH) @diff_c_support = true + + @tag_char_1 = "tag-#{CHAR_1_HEX}-00" + @branch_char_1 = "branch-#{CHAR_1_HEX}-00" + if @tag_char_1.respond_to?(:force_encoding) + @tag_char_1.force_encoding('UTF-8') + @branch_char_1.force_encoding('UTF-8') + end end def test_hgversion @@ -49,7 +58,7 @@ begin adp = Redmine::Scm::Adapters::MercurialAdapter.new(repo) repo_path = adp.info.root_url.gsub(/\\/, "/") assert_equal REPOSITORY_PATH, repo_path - assert_equal '16', adp.info.lastrev.revision + assert_equal '24', adp.info.lastrev.revision assert_equal '4cddb4e45f52',adp.info.lastrev.scmid end end @@ -97,7 +106,7 @@ begin def test_diff_made_by_revision if @diff_c_support - [16, '16', '4cddb4e45f52'].each do |r1| + [24, '24', '4cddb4e45f52'].each do |r1| diff1 = @adapter.diff(nil, r1) assert_equal 5, diff1.size buf = diff1[4].gsub(/\r\n|\r|\n/, "") @@ -219,24 +228,32 @@ begin end def test_tags - assert_equal ['tag_test.00', 'tag-init-revision'], @adapter.tags + assert_equal [@tag_char_1, 'tag_test.00', 'tag-init-revision'], @adapter.tags end def test_tagmap - tm = { 'tag_test.00' => '6987191f453a', - 'tag-init-revision' => '0885933ad4f6' } + tm = { + @tag_char_1 => 'adf805632193', + 'tag_test.00' => '6987191f453a', + 'tag-init-revision' => '0885933ad4f6', + } assert_equal tm, @adapter.tagmap end def test_branches - assert_equal ['default', 'branch (1)[2]&,%.-3_4', 'test-branch-00'], - @adapter.branches + assert_equal ['default', @branch_char_1, + 'test_branch.latin-1', 'branch (1)[2]&,%.-3_4', 'test-branch-00'], + @adapter.branches end def test_branchmap - bm = { 'default' => '4cddb4e45f52', - 'branch (1)[2]&,%.-3_4' => '933ca60293d7', - 'test-branch-00' => '3a330eb32958' } + bm = { + 'default' => '4cddb4e45f52', + @branch_char_1 => 'c8d3e4887474', + 'test_branch.latin-1' => 'c2ffe7da686a', + 'branch (1)[2]&,%.-3_4' => '933ca60293d7', + 'test-branch-00' => '3a330eb32958' + } assert_equal bm, @adapter.branchmap end diff --git a/test/unit/repository_mercurial_test.rb b/test/unit/repository_mercurial_test.rb index 271ffe43..9c3032bf 100644 --- a/test/unit/repository_mercurial_test.rb +++ b/test/unit/repository_mercurial_test.rb @@ -25,7 +25,11 @@ class RepositoryMercurialTest < ActiveSupport::TestCase def setup @project = Project.find(3) - @repository = Repository::Mercurial.create(:project => @project, :url => REPOSITORY_PATH) + @repository = Repository::Mercurial.create( + :project => @project, + :url => REPOSITORY_PATH, + :path_encoding => 'ISO-8859-1' + ) assert @repository end @@ -33,8 +37,8 @@ class RepositoryMercurialTest < ActiveSupport::TestCase def test_fetch_changesets_from_scratch @repository.fetch_changesets @repository.reload - assert_equal 17, @repository.changesets.count - assert_equal 25, @repository.changes.count + assert_equal 25, @repository.changesets.count + assert_equal 32, @repository.changes.count assert_equal "Initial import.\nThe repository contains 3 files.", @repository.changesets.find_by_revision('0').comments end @@ -47,7 +51,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase assert_equal 3, @repository.changesets.count @repository.fetch_changesets - assert_equal 17, @repository.changesets.count + assert_equal 25, @repository.changesets.count end def test_isodatesec @@ -170,7 +174,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase @repository.fetch_changesets @repository.reload changesets = @repository.latest_changesets('README', nil) - assert_equal %w|8 6 1 0|, changesets.collect(&:revision) + assert_equal %w|17 8 6 1 0|, changesets.collect(&:revision) path = 'sql_escape/percent%dir/percent%file1.txt' changesets = @repository.latest_changesets(path, nil) From 3fadaf3c855c748c6ba69825a2da66833ac79bad Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Fri, 4 Mar 2011 08:07:53 +0000 Subject: [PATCH 340/777] scm: mercurial: update test repository for path contains space (#2664, #4455). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4997 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- .../repositories/mercurial_repository.hg | Bin 8902 -> 9702 bytes .../scm/adapters/mercurial_adapter_test.rb | 22 +++++++++++------- test/unit/repository_mercurial_test.rb | 8 +++---- 3 files changed, 17 insertions(+), 13 deletions(-) diff --git a/test/fixtures/repositories/mercurial_repository.hg b/test/fixtures/repositories/mercurial_repository.hg index 2b4eb62410643ae3c466665bab4f63dd0e7978e6..ef65dfeee43a710729d86db1b6a655f1a6264e57 100644 GIT binary patch literal 9702 zcmVx$T4*^jL0KkKSy|5Fh5!L+|NsC0|NsC0|NsC0|NsC0|NsC0|NsC0 z|NsC0|NsC0|Nr1533}dD_C35i2Ru3f?rJsT-t^pL zCos~1Y0ezrD5NENwj`^wAy)tZA3y*A2iQqT38p{^rqB_SMuwU+ojQJx8cCdVs`fk?I3z z5M=Z~^#`bE$)+Zm8Vod#Q$P%W4KxN2N+19c6GYHPnwvz?piG(oXdb4T27m#eGy$f7 z(?DndF%1Ji000^Q01Y%ApbUTkpa2a32@w#4$R=tHQ`sk^)XC*A)bT@29)UKAp`$^e zkZFxZOql_RlOrCYX!Q*=0077XL7}EYKxvVtgFs{e00000X(}ToYA_Qfnlx#XO)@ml z(TS!;jTlFvGGK!yL(~DI6A_?bnlu=LO${_)A(KWE5HKc9G-;=((U54yp@_(7fDwWz zAeknOFoRRcG}Q8BgG`>Grk<(do>20hrY6!oO&BS(pQ(gQ8WYrQs%y63f*e7^6C zGl$GW@%lY_f7`F$d6uV$8@G23_~3z@Xf=+j&}Uix0(TUcGmJ+sfBvbaMDNFs5R%m3P$; zYB3j6^_afffm$qUER*+>S&5vB*26}=MnivbQzn&(B)^@zKpgs(gFDIGNnQ)A40Pi# zPRIh(7=R##%9wI)n@cYkce1j3pRsG(9d2dtADr&ZLqETq$O7#c6&Z*tVryeAQ?Ru6 z=iv%xg&Q|9vF7Y|I-S%G=6h}L)e_7avtciicpC%A2k(-Z`a5g0O1|o_fFobQ;p2Lc zJ^a`11l}5;O}w-)eaTDbuB*PJmEenM4Dr}3V|oxAj{OuHO|gwP)8|3xy0|sJ2IEJp z+4@a$xG=t=7gY8%MmK}1+r;h|a*t!P=%&ZwySC>MLf%I|xYGk&eeEd)rX5Rz*O?Da zBFQ?8Wt~CPtlF6`XKZVp;SLx#UythRDLa))sV9sfjz5Atr#+Rsm7{0UjI*xWodFR|28ZKd#b9JpvjRsAjta0Ss@G(1d)d zl`@q_5>$yG;PWDifgvL4(&S(T-x6STqe$DZ+B60Hg9jCn6IU1sB9ugkpwJB)*}oI% z-3B%!3`9Uu5r}~cKnz4gc*H=hfq_?WkcfT{9Sb9gN`pZ;R;HwpHgG(5eJ-(JHxRv{ z(}azg)Jw-c034LZQQu1vFebF^Y$MUFG?9l{9RzKj;tx`fus1K<<)s+dK)5VVY%Q)6 zhQQf__Qj^mr)It;7j447&bd{?Is**yKMFG6RIpD@#R%7p46@2un{kFLyU3>7Kr5wN zIAiM#M~$R@N&z%ulBh#L>SXh|_Thd!Mze7e7TY1JR@{ZG-y?6g_Ie}LD~o}&Jj1Mf zxg41Au9in{^QKZbEw{ur7`Hu*BXu*5dmoZ=bnIhJ%07a5iPPo%mAQPsEp;aKs^@uo zd4;4DYj{7!wko_iDa_tPs;f!NgVp+E+%t>an~uYw9Y#`C#9C6GEtzrd z#z=hf<9{tF-Y?;!YmA6&W+A6dnMJ6f3n?_@9ScAzBsC{A_g!!F+SOo3U+!zl8-gyVz@60)%M)B~QHsqT4qH|B#T=+Vj zl|())U!I8%POPgkLp%QwuTTLSAn0BP$4!x6s5@G+Q?@GY4{_07=Erm$vS1u;#NL)I zYyy~9*^Zg;o`HHY_aF1YwC(}{Ml-lC4rsvf_(HG~gQ@g>W3!e%=NTFOBfK^`fgZa> zFROka43`oxv|3ue`(~T;N(6*r>ovJ8!+n@VrxmGiOh4FQ!#{yBqwOpANFNd1F)>az zfNnHo;o>sX!aVpu4ru@|hw4IU!tU@LbJzObJf%B`Ux(9h_;KQQ+dh1to5Sl~Z6;?X z=?gsHy0mbEot`CnAJ^=qh_w%6Hf##zCqQur($D7A*DSUe>#80Zkj+LuHtQHsVbh>z z^M*my7{<>~t+IE820=lH%peIJ0QeUy8T?s@y;&6D#oh?=WsZ}bJJXRm2gMHo^R4dMFY88kW39o_iBJ_bKLjyU3qAD5R(^k0#{wVYtJE5(T#$ zhnx0$aWZ;!0XI$kyLRrg;Q%C+1-}&sP5y0 zswb8d!E*5#CGVV#Ku~(vdks|X<1p$=NjGd-qRjR;U0$tn6jbIq?PF87&@w(GQtb;B zISI}jI1V3?3Mi^apv`vd#CZKW&cTm^}c5D~eCV-tqE#aO!hBE8}nPE6;NJ#b39emuK zWLmYa`&KQdR0rJ1GIP_F*q##nEjg7vDyOqpv731C_XkRO*M)a@v`VP=mj&j}* zvJ({I1esLAK$w^`O*3fH(0>RT1{+@N^qG`lwf0ZgP0zjV13c?Jju?U=BP8NjvMNqf^ob4ONx#@H%Wb`-lq~dJL=*kjN zZ&ESUJAWh_C(9qZpt$nR=r{kVpbsV$(KF~CKe$22QYlds1jDW~1({3mq<|nzrzcv67#3J7U-UV^)SM_>_V94o+B*&h zFPgbkg&E(*vnc|e*Rv%X!&{b+797^$hT-xIzd(gqC_4+LEE{u4iHbv{NhKV^aS&T= zNv(-u*4$n)twq}{kx^_n&r3|zg9&TiQ9S#FYk9}N9CeSwxO9sZmt5h|Y$Mf3xBJ~lpPStP5BbkY~wNpqlZQ>*I zC64kLrnh-blB29K*=tE=HjC;xR;ZRsv>huCgqvXYWIPk{H-^_Z9yI3DPP2M}7w)L! z=ZOVD+f$PBt?S9|9_ZPG`Ytz8ZxYn6BbBcfy0cWp1EG2dR;H7M3ff5A$e#3uj}3MY z9TEEttmQYeDO*}zK?fT?Qi;uy`Ehz?4QM|tPhk`IfU<3fvbAgI!*GUCjn(1IH(X<+ zX~d+B=rGWi#OVC0%PwH~YLy*}mIw-dw4$$O{X8hUYE!N)Rctt0+=d+$oTJ zFe7Wib&nc7)$~92r2bU&2uq6-Tz|C71nObZgAGKSAk`g< zT4ZoPsu7uJH$7O|th>=W%U+NdX)%#%(cOKZ_Zu{o_z!_d$y}xw`$$y^yK%*SBX6Sf zPTsj%DkjYpbXFYNCnoUScb;2ON?j|o(Z1<{_)_vR6&_lJUJj`;e&mN+tLol_5lmKv^=T3Q^@&5If~O8@XH`WcW7#J zaeDLS+>2kDaN5C)uc!-5%T87z%gt>CbQzcrF+POGp6Cel!(Ax46}k>$Nz#U8u;yPB z!pcZJaA3ywB--YyMiGk;QMQ6o#dBU-_Z*dxJ~<0qT#2PJNQTsg^rrhw&fb`7^I_J8 z4;`CoP**|OFG8jCcV5&IL&ts5-~@TSG4|(EW3Av+&gi{LMxtzT>4J&NsNQ~_n6gf6 z@YpTrsE_F#C>=ApOh=5g$J%pp+gUM;KU0qhG#pYyB+N2;YY5sYN+WAp56x$p5!71t zrEH9AI51`F4Tds#q=q8|jEia6wheNzt!+`6cF$?H&qwVMI{b{r!#@N*c+jYk43q{ z@Q}ttk2g0o;-(@_=Q|&3L)mNFc8K4o7asjBOVgZm!z?x!4_GlYhSt3y)xbHwlEJc3 zF*gl`8BQ3~RHAvkOxHCbhw$N>aBkBFJY-$;Zke6eX*q_lug3cC)E?|?X9hI^jDsAq z6x=SebbE93t?{So!4HA~mun_OaXF$l6kD=%0p!B~b8m4em4mhY7rAu&4+~gvctBly zy}{~E*w8d99_W8N2+%_<>-1l3smFzp8J=*Q4rjf&orvg;L)|chy_Z$c7&=K2}%;|1$twgO7x0 zbZJhHlv~mlv|Ki1F!nYf%SmTD^O%@_yv+{CRJCy5fk+J+b9@8WOioQe^tuUgLvP0Z zU*G$Ca>~DmyWucb8v!&vkPke2VY}xu{8;82=THzl;j;3!TW=z)fGmj$+CDEMBc?29 zmH~10f@u=vQjAvMp;k170y!TH=?-gSNf>ST&Z^pKZEa{=LvDmqIu?)lYt*CWiM*?TC9A?n3mqL}6i`7!?A(G(uIMjqk`61Hn9`jMR6C)w^ z^#Z=_2ZTNIOB6vEgg@jIdE7I|i$&1?vLd0*DzM5J`MZ+{R)1M8%;RJk{6D~Ky9Dh= zRPTB&I|=s3symdN)jtqYFU=a3!;ZlMVverCqJ>;yA__v@D-Ec`d)dSB_ESa{-(dJs zi33!+Xs$}qiIYf-Bp*(6?35lcO6D==`2+5;6%by46E|;JoN79p`&@Vo-u~x7!#p7* zaZl9Ky90LgjV+M{fUsH87{QEV7>}kL=#qgdjXRV@hvS}DkfAWnfgg9~biTyu3+rQK zOlSkY&)lNtT2slk31Tm&NLx3}+9c%?hjg`RsR=V7BE}5)PedoucNml7F9ru|X~%2Q zmMh?lvsyrTC=Xi2EfUptfwbSK%4?akPh6+aq)EgZJVe;m)?+KQD|`j6_)8l)S0a^u zgn+dpT`;MwDH~Re5!U5r4!G-S671c?EEF;ayH&+o@aQKbT?#nUOVXupp|VO@Pc5dL;nd(bL5b`Eq2Uz^&Y2%L)3 zB4R(GG&{`~Cof#tA9$N$L!pNTBRI;N1}r9w+BIj}tcPi?xXM)8@VPcS^|N4wJ1o;P zYQh<03X_x>EOFDWts?3YT120-sn9N18<-Mf`! z&oN+g;RL+sLAMbt81DSRU?6i+$1^b@(NN}oG{rz?2zK3X$EO_}FjIj7(od3L;yn(I zhJj#93<8LOux4olgu-J@uH3>Hn+C+oDWPnc_UoP1*Aq<@8dbR2?JJJLq}-m=3Vl^WINN4D)k#yWei=NqlFl_{N8jA`Npm z4;}}4DFcvOz|`b2WGpNtKs`-ixQm{%R?&s_3X5QF_9uCecwU(Cuui1)MQM> zofieMi9zyXnzDqYwgw@1SvpR~b{vKSL^@SfRaF%inH264)7A!?V{TkxMV~5l63CRF z9vs%_vp%IAEMpSr+YgE`?5C1J7``Vi@+ruW)43Z2Adhgp%Mrv8VFrT3s2W|lo2(Kb zWZRcnEJX1FdB!3h5L3^O)~!nCuw3rRJ@qJuO4o6Y@6IgI&N$KCbn@Xy*8km3BFJV$ z&J!yG-`g{d!6SI9BZB1tnPM4aR~%U?i0yb_^f^c86hNtZsg9 zZx>2vw6fm1rUod2JA`<^;NY)+K?NaNp@*0mt9YO$CjnD510h4sQMA>e!g$LpoII5X zc-#(GK(n-7R8}~PN>NNZ5)y)>El12rzB1LFW?e%pq$z~%lw-)hOu9a)ukb@9iXBmA zYg!?=r)YfC-)bR;g?3de)vlhV%^35B>=@@yQLh<=Hf6CFhgHuVVr@lfEMkL+iJ&_H z>fPwY7^udZA-whtjnNarM-I-+U|;9a_DL`r@G79u*q@=G;078Cxe#6XQ9zv`9kB{T z+Cwu4SPKjFNsz4%d5~~9bo7T8^n&*oIFccVA|XhGG}06$@g&I2U<2I2Fmj|LD1sDc z=r#y+MTDgDX$>Vrjbj5*$nsyuRG=fVVj}NSydwTCX$~mcx%bsGmTQ}k_;*qRU z8BLR7Utxx z-+E+i%I|3JCv4N+kMOg&5o^ZV9;2t-;Wg>1KIn~eweq2+5CMuB42F`DI_}Zx>HWCW z(rp1E7e@Oga&mHE=?&2f#1(St7M!Rs={1Qx;bOh2Zy&jasBOEx<>!ynR%33 z37~^0WOfEh8GAs3WwTmnEJ_k8DJ%@q-2qnQ-X%o?P}bQie8P6;%sRZ&s=;}thKtVn zb9`i!lct)LV9sZK z2w~&GyNF{PFoS4kpqvuG&kLC9K-B?|Z&@!xo)kF6Ku{V%e3H_&WkEr_k`@7)MNFZ9 zQ-BiJoSAJ*4XFdUEssWhLLkXD;WK$c0%OS*#O#J$Bh@dwdlzdc%OYVZ3IWAB#}I^z zSrwg4D|DcUvQEfAt`kkNPq9JzGSzXbGmTSG3c_kZvT`Q-ma;N?mTWc}fqor08WPj- z79MjD){4iSESjQ-GE_1OFoQ>R#~LU}XB&EPH;QSEYERULKn&PK18p(~046jIdjLZm zm`_SFdCkNkn#SYhdIv|OQKo4fsV6SBny=m`cMl?2?fTo!3yGtbp$Iml~4;n@n(pZ!2+N##7Tho1wG!v*Fxpy6fXTD^Vs?H%9R>LrY zLkNWhzjdtVEQ` zB+-fz5AumpV_bzugT~FmAhaezO(aA?!l0Y6g#~F74AGiv^tuBs@8zjV!zm6u3uV_J zRJcIf!6^`wGm;^Kw`S$)&Q@a*Aud8^a5fyE9Fi32Am5H+>k_q@Sqn3N8Hs}(pp6J1 z&QPe546%l#o3bo13{1vaiyBzKJV9eBkYNy|Q(c;yARaq_wgze`WXLNn+j$hFJ^1y( zpOmuopl*igrXX3i$rNss7Jvdnbfe@x4jEUIBy)XNv=9M#}`KTG|E>OJbng zV;~7=$&~P=Vq2iw7r>&U(Y%^m5ho$eJ2DQyBz`|=Yh{})qH&pfS)J_e1mYP>OGtr| z9fB^rX%^?5-K~gVKCygTMTcsgq0xz4vg(O5F_JVeep-V=Ygyh!*da;L=~pa}?8bG> z-}bS%SE#~8e&gxJP-ZZ0h+}T(a)xOaWNHl@voF33>AW<4@yXms3n=@er&`ZaSPpez z{bEWOv|kTk>@e2tZJjAkS3U9Ls!@!+NRc-+!{7E>rjxIoa92gyzAuQQc_0>6rl<*Z zipv368H=zFWYz6i#^x!R>H1YZQ3t()n#+U%QR!19Uv)Kfq%?7pGA3y7*Sz7J^1AbS zRsb+_!Jr)kdo`2Dw=!z!f_la-U5D(No7D&P zC@yJLd$|Q&5E%RO^jG4rfO>(V0s0SOeXEr9)i6l(i(u=hN17yL4N4=q5&bcJ>-o+< z51$(J>JMGT{}wtMbHxgbcV0RwJwx!4mzp(VqGHkg$!EVDt5@Ou`6)1QFIe_v!hx4pm zl))iQdD=dcD7Y9~Bc5ixUsn9pX9cbdT>2-5&Y+gm-PYgr$k`KWLuX=h)MQ1r6mete zF#0wJg%yeE_j#B7&k429-hAcQDNzh6&Eeu8K4JwK3`>7=kRSm zA~YV+A8q4-{@cDhfPvBOl=mw4L)*CG#b!0rdNg_8Fn*|>JwD@;dGZ^$i2**M-qT{iXmqAEx;$a(O_3Rq%%D;xmu z5E2BCr*J5N@mj~Ef*8R}EL>HFTQ~E;xe7})uZFb^^rRB< z-1;(&hqQi&6z_7$XGW*X16P@Eq5fK5vO9;q-+O0L1saE@Aft*TAx(lUwSiaf!t8MfjcXl*d8GS_j5dY$hF@{xRv?mB5u($%} z8W5aTUIl-p78LD+k33((B_hQLhkVt!!aDa+`WOxGYN(bn6Nq;%eP;Y=Uu><5#z zXPb}vO?fqb23;hBIt|C=t(6Hf*l-fOI zR=UIq$$h2vujZK&M&S-gbUCLy3P}@eOm^^WNwWn5h`6!6$K}7`#>Svr7v}>W8?YwI z@yu{jOY6k-)(d1# z-%z-<>ZAG|@!!E!P*$T+^rLKe(cXSX45Kr?OrkFkTdEOo64rD~UOC$+CU(sXY~RGN z41_}=k=Dall}MOaxdnCB_!y&@L^z}LuxzrI(9I)9XWjn@nColux4`rDg`kTK(QbH; z+>pn_3X~h8nTZxTU`fC*;UX+%U_U|u9ty&YxhoPKLGz1X)Q%YMc*SwKA)O$(wA*0o zdfgdp7oM9j{FWBKp+I`cbdl5yhtwaRdA%hP8zLTj;UCz(AT`tn#1@h&=5TqyGyi`l zOefAbO8tnS2gGDY)52~71Fltu6%b!nz*;+xRw4W_Cg*|lenI2BalMXEqEo_$H7#_| zWO{>k*H3h-4pOZiQG|peh0i6ArHo<8(q;vGCQ5<$cbIhB@RDnb4p|G}86<6E!<%Yj z7(tBqW(3ZC@I0_MIJ1^zNS}!_WN+xOm z>hq}^wt{ZmzX^`tT(sI1p{B^%=&5Gat|1T4nex+Jlf#-|>W3}ug5v!i;Zon(7k5DM z(TEdLY%F;{;OCNEkpHlV_DONtebrB9`c+7@LOt~sNE+4-DZ-^ti!pY8BKZ7Gr!T+| o`;m#CV~X{lp(E2Upd$womQ_J?W&^dZGT377NT&)C3pw0Sz?ys(2><{9 literal 8902 zcmaiWRa6uV)a}q+1Cj#_Fmw+f9YYSKbazWhN~$w-J3}`^w;-L;F?0(8N=bu+ilXTM z{de8hyY5+Q?{oIk*-!f%xR$t>s+EVVILwmA*z#KA=|2FD;p>0@zuE!6V-Hm`%juaN ztfA85iPzZKMi|gZ5+W1;lu_@t#8o30>rgMm0000b0&noY1|W#ZMCH3Y6BoxAOESAY zuErGe=!83XtQ0TS9xSY2Pn|Up3&z96%f|YW;usHVw<;bIWV+-xX5O;mJTX05eKDRm z9L=dPl7nUZg=j;P4E|#mN0M6f@yd6}kJ0)7=KoeOQ~WRe?*ssN{D=SK{}pQb02pj2>SKeqlKL;|5E#*r-62k=xa8++)j45msh>+3)D%%fV0 z&+y>C&ws;*EdZ9(g@@-oHC_pSvlOmo{9Vyt@e7ohaD~P2gxNz;O7dHAeo37o*UCb; zCtE&Z;jz9Nn2L4o^{%hjq9%ZRa{VQH9(h%EDt~`=CDx(nrt*u@E9DI7bG$+S$zE-Y zWo=l!scp$x9D%P5mkQ8UD$B4zR%h!79>S{)I9Vk`ASbHszjbO|0n z_vgnp#Nn5G@~`YZ93s9LuUqfp7Z5WsIE(ep=Z-#B?qz#+BqncY>msW#zdw6fTpNA~ zvL+-ucA{|JcF}8GqveKP<90p&(YfjRRHWL!s?q1@al7Pb0b%(|*+iy~o9jdch0ar7 ze6|P@Kc9KxNVr?KIsEMS^Ofv4?z7(djl8CiUr_j8^QR}1fvF+vOsh1G1sp>gXL5K@ zNE9h;;YDWnXVU3EhWIbtUD>&*iARx8j1FT@1Zmp|%=~RQ`E|*K2Nw}Bj~Ra?;yT%*($V(Y{OO9gUr|wNq#rRb;C*@QdQC}v zJWFbTikr61@a(@AM~WOIERHC$O(@(XC7oc(fjZ=~IF?v8!NKMbTI)yYSkOLt5E(k! zqVBH5RV;II(L+jdvUhE?*G2Fdf(^qX-fs5Z;5O8v%u%Am_#LaTapHlQnB$uNz4ss& zkIRd~3(qB%2M_8X6Un;7>|qWh;Vl6X%q6FbHMZ5HZ>N2@EMtW&^9_DwaiTE z+58HBe%{H^@-`8IcoO{O)96t}j`S`GPro{$uVbhhy(V+d<^gV*c59rnc$h`nRA@e5 z`f4d=V%dEYe{oN86YhsjkxbH}ahB$*tDAXQe#k$HekT%d@z0{^MlB2I(R}D&=yiKX z3sj<@%>m5{tXPZh$tC)WcI~l{t{40bAQ61H=gJqN4Cca$+jHbU?Yh{eRqQGu@~2Rf zZH}J(r5URAsXSuLIky!AOGx^_-wBj<36y-B-GN)V(O!rhJTZn4or7N$54S+TB@1x5aQi=(n zt{H2zNE&0c@Yno!%m<+5$Za5CP@}?8WDqvvgwX6%%)sf1mZ*Tu3xC3^9_FKp6l70+ zyV5F9)6hE~#O@A3Q^hfOsmD)jl2&pQ?K`uBanM7N##Wd#R;Q$#b-Kvt%f2}Wk-c9u zl)P5Jed>oay4lXJN=6UI#iMV{y{Qf)lwqN-%C48`Xe2emJuWEIB!2j#?Wg3+eRH3R zd=g0WXkvwFxQdQ`nV?b44zwOw{jE>1KEhaiiICH(@o(1J$2ka` zYdtCP*Kvva7HcfwjL88<7>`773a?X`?8w-S}A zt>4vc(myRekIH`XeljcYji29>I5wSp*JshpGW%u`!>6LU^h9;N>x7iY4I!?C#ffs5 z8+cYiuAU>pf0Rzo>K2Cs!^5fLY;DCov{5$d`oy8vB2>MCv1X!FTFjY*V>6RVyhUn> zCgnW~Q*14nYt6&@h7)lnn`f=E<+>#SWrgAY>L!2#QX5Z6kq z!&%l!2qfK_=Q$vCq2sS)O_@y|9p=#RTX0Hoi31@?wR-z9 zcLLDlOmUb@vmUpQ%2qtuXeNn08i~C9aZX3qgpZCdRBPs~yuNSQ>={jdZ!%#mYmQ`z2VLiQhdri=*gt!5L}m#} ztkv)+F22;kk{qoRt3KBQF^Dn#VaI zOK>4~v&9O@Mi2%KyhDnTJ`fyJB{-cSv7SBRFP^lP;40Hp6ITY%zG1X}^6teXa;z^n zqbc7#*getS0)I>9_As!}>37fz0=1P%1$?o7$V(%TKa=n**`1GWiTk zdQo~&YkZWDn}xDO!^AR@itJ+>+~HC1qL@#FUh7pB_9Ff^w(B`j1%&Ezz_v;i85z>`uE&TZb4J3z5FbsWLS9K zIX1ty2JXg<(^V#Bg3!k#i-T{Rv$P3xG6hsyqDWibvCaAIHZa478-FNM9sT+n@JsC_ zdPdu_BPTP0YXpz2PvzFE%x)n;k&$fgDZB?u32>EvZ?n7N9@A+Usgc1jY zOak^B+cS!o22|R4o$gmx+M~#xn0_=W7wfPvy6wG)B7VtsWku;J@Xn6F-Dph&&ch zd>q~|5;iAPB*W)@Z8UsM; zyb26LF~_54&Dp5I3nAq0DF^DL)sAF_-|B9dGN6GVmRd(Dy3njXc@Xz+03Ab{QDzWN zG^CUGqM^4}UJJ6@T;L^^$Kf^QH&ozwLO63qle{e3?yhV)JmR0WT6nu`05l4SYmWN!#pbBE#Zjb9>75oIS3yh9$F;1ofh(ONH?m zwa8PPr0Pgu73P3Z{SaWBnZDXtFFrkp=At!EL&|CJvn+os?a1-;OUybFSuKL4I{kvVo4zg&~qlGAQ*4Kv*|Jq5iva#uikPv@j5;H}Zui5nGh zJf>$&rPa0Z3h2t@qEWPvx&808`O^!t^-5COIb8^TyO!ecf;qNv^-%d-U&W!tF}4kC zCgAj(JXVToOE2o#VnwpGu)zqLI411|B|SR+9f#c{t~G%aOeez99WZDK4`x(YtLYJ2 z7&M$}IZC-$1ZL9z(9AS=Cg!K9prSAd{X4vC-<(GCtL(McnV%4!VEsOryp`di!@WT zccmD*lf{M%RLp{qN>Qrzj6_;W`&dQ6kEK%eozND0TS_w`O1DT?ug*2}3pl#kHi_|D zS$UhY8>%zmP0B#OffC0zuiJ0xE`IM@j!l^d48b890khXJBEvd{6>yCO)sK<%UGg3h z1#(?IBUO0qw0tKPmAYg=tB*HKR4>vRi>WUFDAG3&@?n7s%?v*5(hs$Ec97ags)rqU z++ILO!8V=9n?e8QZB(gegVrx%raF{vC>mM%7TAi$O+M8IQ#0g%-#3S&5WU5V;Y*`z z$l~d^1x4YotqlZn%f{YXqBaS%pgzU1YABcFR4B32%r|VkQ|}PUk-2wpPhN**9X&mG2o15pEow=l61o^vR~1Kv+}~sRIHiqV1Uwmrgb9u|G|+Hzby9qxWk|@1XEdun zdUn-K)5&k4!z4#KkG|nzCa0q?aEZ%myEn&~Jx0l<#2(xUEk)Ri%jRS|4waZ+v{#qE znW%rTTPQm=-#`;~_lF*#}kskG&)S()pcp?!&No9PykpVL0t@_cq;r}-4c zi>$0A%<#gk$O>D03YUia8!GfiMKY3UMg!4ySZtn2Qsu{bi z#oFN=1+oqIXj#`h3&gI+SO+P8|AzCCe{0IkMyB(wa;%I^oDBD=Vn}trpg=;p2QAac z7B#f?k>A71)kCfc>wz9RDErheANI+>G&3M(n=$Qq+6TOo{9!OcG~sobVSGRy4c``f zir+xw$5}#^k&a&ph#)`0Hb{h>E4yCmJmH|3YLpV>FqzYrdaH#!!Jz3!DvRR;ypfU1 zV)(w|Qzmb*Ae+nCmkjkEtxlOxNw55*m4+xLIJ>#KRpbxp%!rk6jdlo@vW%ccxsHDm0y-ehX@x zokq~CEavFyn9zUcH<#fs@8dq)lPxdMglW2^B>GwY5LoQq2l4eD9urkN; zkKogR_7yO>q|76`@2!g!$$ACn;(OYSivOtjnKuHJ>A5IssKJMk}k@m@fe^l|b{ z!7qt3-ty!}nR5-mOe^iOkje_Z*k8^N2@b5;3(Eb~BJJse(;1 zxz&jfdD(a!M(VT{Neqb(&h21n|5-vT&7+W-RKqQ~c8A9uBS%D%g^PO{o2vOECdpp< zoAW}t?jnLy{-^i{z}fo?d>j^W`0mj;q5aumJwvkq!6kZ$Qqv6-nW7fmOPS`sA>ZPA zl1Ok~_#3~7Fxy(2{WoK+(0yX&m`8n#p*FPKKJxweE>jPco7@n1ZY&@-Y15S=Y4 z0C`nFw;sacou{=31V7nJ!WWmX`jzt(RJ6>Uyp@{OKHOdr$1Re^9&^)@48+Gu99%Hx81M4yn$Pe=!yreXT+*0)?- zTA!(=M;_v;*y#%~N}O(ijMn7vV(;htbvWO=r~rd zahXV@GjZ8*LSRVojo?o+l$Obfy>m|en?1H68iGD|z0z^tGTBio2(O z`JKe`6YvJj$f%@I`w`7pE=RfTarjB@FPJ2(s6pJx0~2iC>3uUFHMu8QOk2~Je?c}c z$Q1eqfTnG#7DqII*1{0&Y4y8XX;S;NWW_??Y;g9vWO4oCyvqo@)RJ8Y9rp`WT)qun z=kbBrzBfOLA=`^3&QsTc5tKsJ$Fi*wZE<^W=LWSc5knlNDrlF)ToZUD-9CMEU&_JM zrw^=a?nV~WoV%$ALuDE=>IuxC18;@E0=oUlP!1NdXF0_1)5EbnfOUPral1&wHC&% zFrI2_w&2e5AIum|D5%`*pjbSRY`>f&XBwo$Djgz;4Ro%HbxqAVWE!{=q~*AB19_ot zpxIbtu3HrQvV5)cw4>p))-@Hsgi69bFZ^3B#riaG)&ID3HI+y+%I!12lXbR3w^Q|wGHZM-4G(G1Xgt){Yj#EcwGiPOd z{@H#KS~q{7Zm!%Qbhc%-4J*9UiY8*MVP)OkN8>cl`sE38#FzRRL4cZwy~)3w zj1Sw-)yHzpHP9&yE;#+QYITrPqgMasUW){q0!0(3gJYB_&;T~LJ4J9UP8;Qyo@qdD zap2eTs2=Wv+0*4$2g}?>zPfto&yiv&lS}x_zJu-HT`~`enq|t1Td-vqA9T{3v7`R@ zrR8KqorxPY#U0Ff_zL>H{I76%VJ&SOS+v3uC~f9|O(y-stk<9i+TlPwxRo}~$u6IM zClm5J{7%c8ydPO7SfwM>3~nDvlA2Vf$y9{%f-$!Ei>|XCmRvPyk{l{58(5Hn1}dwu2Upngsb+6lKtmUnPv-?<1IEU@9KnSast@ zML!^o5xFcpo~|WynXTcASSCpvQ16Hrk_d14g1lJ#oIF4_Z6m~MtSN>Gy|0hY#b%GT zM2j8ZG3Tkm&agCukFHEvu7}T|s#!1rFgc>=pu%YsCiCG934wQ_jRVnFeACHrQ$>No z?Bn$&til(U&FJX_LZYlO*<-eNvYD}m?OV61$2mYd%iA|77g3Ks?j;}Kuy-pV(Bd$B zi2Q&IbCKUDi}L;kC}ig}VNrX%y1=X7aJ^s0gV+^)dBebP8le@jH9$OfO}Qd3{0QYl z_4D9QA(A`n!F%NQZnpR-M?7FeOl&;#0JR&F*n%W@O0z{Wo!I3_ye3`sHh>07V1$D* zdBVd4#m#w+7w%5&kSCxPYNUb~?zW_Zd5l^gq7dVN`@LB-?MIkF3HTswmz4>?4PhfY zTSr6mU=(z?8SZok?;aYRuh;{eYuI?g9P6K9r;X$S9j7?qzDJ|7G&gIMS^trVUZ%gr;#fSM znRU4zUL-~dlFJQV?~Cxug1^gxRkHTf^x$J?btT;gg?kYGyMbkUc692x7alc zY{+Bmv^T>Hk|bxuX)g+T_XJB81vUkK2vv?V#xk{@zf>GmBI{;9iayE z@UGn1elD2lc5mUedbu&A+bD)~*h99lR_iWj^AWg^ITYG4@rs!X=+k_&PLe`Fzu$$G*`9zZ3#X z+-uBGzwmA~ybD31sjty%v`x8xvzcGs2)(fr|FcuWMJ!G1zIaVuZHue{@3XbTx+Udq z6Wg1U*&g8SvX)?3t3ZHSxsl6UD}~wI!~%L^+4Q%^pf#6POY-Y(Z*eD?`WM}EsV8C# z6CHr2_JAVDDxnH-59#_r*A|_})_{a`>Ina=&6lxVjX2#g56MuS-9#}rgRh~bGQ5!5 zPLmojiA&Q!eQ2_P%#CN^6ZHepILdI#<5u|UKGyF=sQn7)k4mJDtfLwtzH8#rO4{v; zMfG$3pQP+09-#>)VCQe?i2hN#(r;Y5yJpNv4K7~=g~M(M#$yk+sw5r%SZZMTeT_ETP{d@RkAB=)MI1%|D@?wsf!t4{wiAbY-; zpnx&b6j38sSVAY|7e-H-AJh+@mu@5)=d)Pw%9DVIgeBm;9;xEkj+QkVZ$!7K=byof$K>!3S2KSSdqXu3 z8u%K6?BL9WA%vZ$E%Jm2{wZWn&*Y@Vw3zF-PApt#5U); zjk5ypar`@{bYaHIm784Sx}Iiy`;bGK3DF|)bT*ce+HuXVXg`1DyXL!HU$>nvHs!$A=dskK3+F2(Z7E__G(tYawJ#Wx(ewAuz7hGrKr=x@U#LSI0S2ISI`KRS3lfu&EY2HuaM7Dj?$x8XpC<^#_`#Jo@p#7 zae4?pMoWKT6TebjeaH9lFM<4 zK%%L5=wu*T{uD+lq!&W@SSY1$@N=cbr^W8V8;VrMlFc_d&HNO|iP7D#8VpX8DQFYD zx%YE2xdi(9lD^HOax&-s!d5``W7caem(TitkcUWTNi&|N;RC%Ncp&5a@9~s8;%xgh zuV{F8?O?N^;+?t%=5Ln$Oj18LjqB{)n^}&%|3S=!Va;u?UyaUZa_(|?Rfe)$jb!ME zC@RFOR|dH=KX9WL|R=VDm9c zH|SP{ng{lgaD%+f*Tu;x^q=9PMZ!-dhxb@p?gBR2#9LqE_O^7yDQao{vNb7lw7q|t z_92j*7nJCaoUqGd){Aqb`7E7C|0%6=?R&7gKiwmjOsE3BFDFPp`t&zJym^2J*^X8+ z*+(|6{u(j-x@5I;DhCvET8Z*ga3!|^)=aAT-ojD zduDZ^lg+=eCio{NG!+V^eZK+juP0v)y^uZb#j9|ba6k7RIk+h>dV?J`xZ+8z z`ugS{-h}s#KfyJh)Ax&CH{IvF>b@V%^;}01+VM7bG>5uu%JdGzQ)FIUFuvvPstA=Y z58A8+ugKbQ4~}x}&k}tAkBdbyd5I+s=!UER99!*zz5d)_qq#mGHUFaw{pfZnYrmV=8^5;z9c2wq-IcD)6qsLh6do6tsh#!9cLi}l>tz8%($G>w{-Jt!IYt+jg%){z3KeJG4V+PuYdjz DiQ#Fz diff --git a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb index b5629841..8e971ec9 100644 --- a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb +++ b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb @@ -58,8 +58,8 @@ begin adp = Redmine::Scm::Adapters::MercurialAdapter.new(repo) repo_path = adp.info.root_url.gsub(/\\/, "/") assert_equal REPOSITORY_PATH, repo_path - assert_equal '24', adp.info.lastrev.revision - assert_equal '4cddb4e45f52',adp.info.lastrev.scmid + assert_equal '26', adp.info.lastrev.revision + assert_equal '3ae45e2d177d',adp.info.lastrev.scmid end end @@ -241,18 +241,22 @@ begin end def test_branches - assert_equal ['default', @branch_char_1, - 'test_branch.latin-1', 'branch (1)[2]&,%.-3_4', 'test-branch-00'], - @adapter.branches + assert_equal [ + 'default', + 'branch (1)[2]&,%.-3_4', + @branch_char_1, + 'test_branch.latin-1', + 'test-branch-00', + ], @adapter.branches end def test_branchmap bm = { - 'default' => '4cddb4e45f52', - @branch_char_1 => 'c8d3e4887474', + 'default' => '3ae45e2d177d', 'test_branch.latin-1' => 'c2ffe7da686a', - 'branch (1)[2]&,%.-3_4' => '933ca60293d7', - 'test-branch-00' => '3a330eb32958' + 'branch (1)[2]&,%.-3_4' => 'afc61e85bde7', + 'test-branch-00' => '3a330eb32958', + @branch_char_1 => 'c8d3e4887474', } assert_equal bm, @adapter.branchmap end diff --git a/test/unit/repository_mercurial_test.rb b/test/unit/repository_mercurial_test.rb index 9c3032bf..d4053e1f 100644 --- a/test/unit/repository_mercurial_test.rb +++ b/test/unit/repository_mercurial_test.rb @@ -37,8 +37,8 @@ class RepositoryMercurialTest < ActiveSupport::TestCase def test_fetch_changesets_from_scratch @repository.fetch_changesets @repository.reload - assert_equal 25, @repository.changesets.count - assert_equal 32, @repository.changes.count + assert_equal 27, @repository.changesets.count + assert_equal 34, @repository.changes.count assert_equal "Initial import.\nThe repository contains 3 files.", @repository.changesets.find_by_revision('0').comments end @@ -51,7 +51,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase assert_equal 3, @repository.changesets.count @repository.fetch_changesets - assert_equal 25, @repository.changesets.count + assert_equal 27, @repository.changesets.count end def test_isodatesec @@ -174,7 +174,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase @repository.fetch_changesets @repository.reload changesets = @repository.latest_changesets('README', nil) - assert_equal %w|17 8 6 1 0|, changesets.collect(&:revision) + assert_equal %w|26 17 8 6 1 0|, changesets.collect(&:revision) path = 'sql_escape/percent%dir/percent%file1.txt' changesets = @repository.latest_changesets(path, nil) From 13d13c426d9d4030043285289c0ffdfd7145c0c0 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Fri, 4 Mar 2011 08:08:13 +0000 Subject: [PATCH 341/777] scm: mercurial: add unit adapter test repository for path contains space (#2664, #4455). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4998 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- .../redmine/scm/adapters/mercurial_adapter_test.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb index 8e971ec9..b89caa5b 100644 --- a/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb +++ b/test/unit/lib/redmine/scm/adapters/mercurial_adapter_test.rb @@ -261,6 +261,18 @@ begin assert_equal bm, @adapter.branchmap end + def test_path_space + p = 'README (1)[2]&,%.-3_4' + [15, '933ca60293d7'].each do |r1| + assert @adapter.diff(p, r1) + assert @adapter.cat(p, r1) + assert_equal 1, @adapter.annotate(p, r1).lines.length + [25, 'afc61e85bde7'].each do |r2| + assert @adapter.diff(p, r1, r2) + end + end + end + private def test_hgversion_for(hgversion, version) From 7006fe1df815372b4cd73992c531362928e5c359 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Fri, 4 Mar 2011 08:08:32 +0000 Subject: [PATCH 342/777] scm: mercurial: additional unit model tests for path encoding (#2664). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4999 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/repository_mercurial_test.rb | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/unit/repository_mercurial_test.rb b/test/unit/repository_mercurial_test.rb index d4053e1f..6d8d7a47 100644 --- a/test/unit/repository_mercurial_test.rb +++ b/test/unit/repository_mercurial_test.rb @@ -23,6 +23,8 @@ class RepositoryMercurialTest < ActiveSupport::TestCase # No '..' in the repository path REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/mercurial_repository' + CHAR_1_HEX = "\xc3\x9c" + def setup @project = Project.find(3) @repository = Repository::Mercurial.create( @@ -31,6 +33,10 @@ class RepositoryMercurialTest < ActiveSupport::TestCase :path_encoding => 'ISO-8859-1' ) assert @repository + @char_1 = CHAR_1_HEX.dup + if @char_1.respond_to?(:force_encoding) + @char_1.force_encoding('UTF-8') + end end if File.directory?(REPOSITORY_PATH) @@ -115,6 +121,13 @@ class RepositoryMercurialTest < ActiveSupport::TestCase assert_equal 'A', c2[0].action assert_equal '/README (1)[2]&,%.-3_4', c2[0].path assert_equal '/README', c2[0].from_path + + cs3 = @repository.changesets.find_by_revision('19') + c3 = cs3.changes + assert_equal 1, c3.size + assert_equal 'A', c3[0].action + assert_equal "/latin-1-dir/test-#{@char_1}-1.txt", c3[0].path + assert_equal "/latin-1-dir/test-#{@char_1}.txt", c3[0].from_path end def test_find_changeset_by_name From cd9cf95d9ab84f7c43d2d1f67f3dd7f1c836076e Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Fri, 4 Mar 2011 11:07:58 +0000 Subject: [PATCH 343/777] scm: mercurial: add path encoding tests in functional test (#2664, #4050). TODO: This test fails in Ruby 1.9 and Encoding.default_external is not UTF-8. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5000 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- .../repositories_mercurial_controller_test.rb | 90 ++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/test/functional/repositories_mercurial_controller_test.rb b/test/functional/repositories_mercurial_controller_test.rb index 3960285f..15c62167 100644 --- a/test/functional/repositories_mercurial_controller_test.rb +++ b/test/functional/repositories_mercurial_controller_test.rb @@ -26,6 +26,9 @@ class RepositoriesMercurialControllerTest < ActionController::TestCase # No '..' in the repository path REPOSITORY_PATH = RAILS_ROOT.gsub(%r{config\/\.\.}, '') + '/tmp/test/mercurial_repository' + CHAR_1_HEX = "\xc3\x9c" + + ruby19_non_utf8_pass = (RUBY_VERSION >= '1.9' && Encoding.default_external.to_s != 'UTF-8') def setup @controller = RepositoriesController.new @@ -39,9 +42,18 @@ class RepositoriesMercurialControllerTest < ActionController::TestCase ) assert @repository @diff_c_support = true + @char_1 = CHAR_1_HEX.dup + if @char_1.respond_to?(:force_encoding) + @char_1.force_encoding('UTF-8') + end end - if File.directory?(REPOSITORY_PATH) + if ruby19_non_utf8_pass + puts "TODO: Mercurial functional test fails in Ruby 1.9 " + + "and Encoding.default_external is not UTF-8. " + + "Current value is '#{Encoding.default_external.to_s}'" + def test_fake; assert true end + elsif File.directory?(REPOSITORY_PATH) def test_show get :show, :id => 3 assert_response :success @@ -99,6 +111,25 @@ class RepositoriesMercurialControllerTest < ActionController::TestCase end end + def test_show_directory_latin_1 + @repository.fetch_changesets + @repository.reload + [21, '21', 'adf805632193'].each do |r1| + get :show, :id => 3, :path => ['latin-1-dir'], :rev => r1 + assert_response :success + assert_template 'show' + + assert_not_nil assigns(:entries) + assert_equal ["make-latin-1-file.rb", + "test-#{@char_1}-1.txt", + "test-#{@char_1}-2.txt", + "test-#{@char_1}.txt"], assigns(:entries).collect(&:name) + changesets = assigns(:changesets) + assert_not_nil changesets + assert_equal %w(21 20 19 18 17), changesets.collect(&:revision) + end + end + def test_changes get :changes, :id => 3, :path => ['images', 'edit.png'] assert_response :success @@ -116,6 +147,18 @@ class RepositoriesMercurialControllerTest < ActionController::TestCase :attributes => { :class => 'line-num' }, :sibling => { :tag => 'td', :content => /WITHOUT ANY WARRANTY/ } end + + def test_entry_show_latin_1 + [21, '21', 'adf805632193'].each do |r1| + get :entry, :id => 3, :path => ['latin-1-dir', "test-#{@char_1}-2.txt"], :rev => r1 + assert_response :success + assert_template 'entry' + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', :content => /Mercurial is a distributed version control system/ } + end + end def test_entry_download get :entry, :id => 3, :path => ['sources', 'watchers_controller.rb'], :format => 'raw' @@ -172,6 +215,19 @@ class RepositoriesMercurialControllerTest < ActionController::TestCase end end + def test_diff_latin_1 + [21, 'adf805632193'].each do |r1| + get :diff, :id => 3, :rev => r1 + assert_response :success + assert_template 'diff' + assert_tag :tag => 'th', + :content => '2', + :sibling => { :tag => 'td', + :attributes => { :class => /diff_in/ }, + :content => /It is written in Python/ } + end + end + def test_annotate get :annotate, :id => 3, :path => ['sources', 'watchers_controller.rb'] assert_response :success @@ -212,6 +268,38 @@ class RepositoriesMercurialControllerTest < ActionController::TestCase end end + def test_annotate_latin_1 + [21, '21', 'adf805632193'].each do |r1| + get :annotate, :id => 3, :path => ['latin-1-dir', "test-#{@char_1}-2.txt"], :rev => r1 + assert_response :success + assert_template 'annotate' + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => + { + :tag => 'td', + :attributes => { :class => 'revision' }, + :child => { :tag => 'a', :content => '20:709858aafd1b' } + } + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => + { + :tag => 'td' , + :content => 'jsmith' , + :attributes => { :class => 'author' }, + + } + assert_tag :tag => 'th', + :content => '1', + :attributes => { :class => 'line-num' }, + :sibling => { :tag => 'td', :content => /Mercurial is a distributed version control system/ } + + end + end + def test_empty_revision @repository.fetch_changesets @repository.reload From ac58816e9fdb18123be0555951473bd6bc3710f4 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Fri, 4 Mar 2011 13:39:00 +0000 Subject: [PATCH 344/777] scm: mercurial: add path encoding select box at setting (#2664). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5001 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/repositories_helper.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 23899a88..c0d5909c 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -205,7 +205,11 @@ module RepositoriesHelper def mercurial_field_tags(form, repository) content_tag('p', form.text_field(:url, :label => :label_mercurial_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) + - '
    local repository (e.g. /hgrepo, c:\hgrepo)' ) + '
    local repository (e.g. /hgrepo, c:\hgrepo)' ) + + content_tag('p', form.select( + :path_encoding, [nil] + Setting::ENCODINGS, + :label => 'Path encoding') + + '
    Default: UTF-8') end def git_field_tags(form, repository) From 2fa11b21681dfb7f5a928db8bcb4fe13ce4e3b60 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Fri, 4 Mar 2011 14:03:19 +0000 Subject: [PATCH 345/777] scm: mercurial: add changesets order test in unit model test (#5357). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5002 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/repository_mercurial_test.rb | 40 ++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/test/unit/repository_mercurial_test.rb b/test/unit/repository_mercurial_test.rb index 6d8d7a47..6e7938f6 100644 --- a/test/unit/repository_mercurial_test.rb +++ b/test/unit/repository_mercurial_test.rb @@ -212,6 +212,46 @@ class RepositoryMercurialTest < ActiveSupport::TestCase changesets = @repository.latest_changesets(path, nil) assert_equal %w|13 12 9|, changesets.collect(&:revision) end + + def test_previous + @repository.fetch_changesets + @repository.reload + %w|26 3ae45e2d177d 3ae4|.each do |r1| + changeset = @repository.find_changeset_by_name(r1) + %w|25 afc61e85bde7 afc6|.each do |r2| + assert_equal @repository.find_changeset_by_name(r2), changeset.previous + end + end + end + + def test_previous_nil + @repository.fetch_changesets + @repository.reload + %w|0 0885933ad4f6 0885|.each do |r1| + changeset = @repository.find_changeset_by_name(r1) + assert_nil changeset.previous + end + end + + def test_next + @repository.fetch_changesets + @repository.reload + %w|25 afc61e85bde7 afc6|.each do |r2| + changeset = @repository.find_changeset_by_name(r2) + %w|26 3ae45e2d177d 3ae4|.each do |r1| + assert_equal @repository.find_changeset_by_name(r1), changeset.next + end + end + end + + def test_next_nil + @repository.fetch_changesets + @repository.reload + %w|26 3ae45e2d177d 3ae4|.each do |r1| + changeset = @repository.find_changeset_by_name(r1) + assert_nil changeset.next + end + end else puts "Mercurial test repository NOT FOUND. Skipping unit tests !!!" def test_fake; assert true end From 6f5707c2b54d5a3ced1f63c31e67f863f1b46a37 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 4 Mar 2011 14:32:58 +0000 Subject: [PATCH 346/777] Adds email notifications support for news comments (#2074). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5003 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/news_controller.rb | 6 +++-- app/models/comment_observer.rb | 24 +++++++++++++++++++ app/models/mailer.rb | 22 +++++++++++++++-- app/models/news.rb | 11 ++++++++- .../mailer/news_comment_added.text.html.rhtml | 5 ++++ .../news_comment_added.text.plain.rhtml | 6 +++++ app/views/news/show.rhtml | 1 + config/environment.rb | 2 +- config/locales/en.yml | 1 + config/locales/fr.yml | 1 + lib/redmine/notifiable.rb | 1 + test/unit/comment_test.rb | 13 ++++++++-- test/unit/lib/redmine/notifiable_test.rb | 8 +++---- test/unit/mailer_test.rb | 14 ++++++++--- 14 files changed, 100 insertions(+), 15 deletions(-) create mode 100644 app/models/comment_observer.rb create mode 100644 app/views/mailer/news_comment_added.text.html.rhtml create mode 100644 app/views/mailer/news_comment_added.text.plain.rhtml diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb index e7c643e9..bc7eabb5 100644 --- a/app/controllers/news_controller.rb +++ b/app/controllers/news_controller.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -25,6 +25,8 @@ class NewsController < ApplicationController before_filter :find_optional_project, :only => :index accept_key_auth :index + helper :watchers + def index case params[:format] when 'xml', 'json' diff --git a/app/models/comment_observer.rb b/app/models/comment_observer.rb new file mode 100644 index 00000000..fc008942 --- /dev/null +++ b/app/models/comment_observer.rb @@ -0,0 +1,24 @@ +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class CommentObserver < ActiveRecord::Observer + def after_create(comment) + if comment.commented.is_a?(News) && Setting.notified_events.include?('news_comment_added') + Mailer.deliver_news_comment_added(comment) + end + end +end diff --git a/app/models/mailer.rb b/app/models/mailer.rb index 8ad2c179..fbda2180 100644 --- a/app/models/mailer.rb +++ b/app/models/mailer.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -154,6 +154,24 @@ class Mailer < ActionMailer::Base :news_url => url_for(:controller => 'news', :action => 'show', :id => news) render_multipart('news_added', body) end + + # Builds a tmail object used to email recipients of a news' project when a news comment is added. + # + # Example: + # news_comment_added(comment) => tmail object + # Mailer.news_comment_added(comment) => sends an email to the news' project recipients + def news_comment_added(comment) + news = comment.commented + redmine_headers 'Project' => news.project.identifier + message_id comment + recipients news.recipients + cc news.watcher_recipients + subject "Re: [#{news.project.name}] #{l(:label_news)}: #{news.title}" + body :news => news, + :comment => comment, + :news_url => url_for(:controller => 'news', :action => 'show', :id => news) + render_multipart('news_comment_added', body) + end # Builds a tmail object used to email the recipients of the specified message that was posted. # diff --git a/app/models/news.rb b/app/models/news.rb index 00729f06..7f8c7310 100644 --- a/app/models/news.rb +++ b/app/models/news.rb @@ -1,5 +1,5 @@ # Redmine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -28,6 +28,9 @@ class News < ActiveRecord::Base acts_as_event :url => Proc.new {|o| {:controller => 'news', :action => 'show', :id => o.id}} acts_as_activity_provider :find_options => {:include => [:project, :author]}, :author_key => :author_id + acts_as_watchable + + after_create :add_author_as_watcher named_scope :visible, lambda {|*args| { :include => :project, @@ -42,4 +45,10 @@ class News < ActiveRecord::Base def self.latest(user = User.current, count = 5) find(:all, :limit => count, :conditions => Project.allowed_to_condition(user, :view_news), :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") end + + private + + def add_author_as_watcher + Watcher.create(:watchable => self, :user => author) + end end diff --git a/app/views/mailer/news_comment_added.text.html.rhtml b/app/views/mailer/news_comment_added.text.html.rhtml new file mode 100644 index 00000000..ef2be0f6 --- /dev/null +++ b/app/views/mailer/news_comment_added.text.html.rhtml @@ -0,0 +1,5 @@ +

    <%= link_to(h(@news.title), @news_url) %>

    + +

    <%= l(:text_user_wrote, :value => h(@comment.author)) %>

    + +<%= textilizable @comment, :comments, :only_path => false %> diff --git a/app/views/mailer/news_comment_added.text.plain.rhtml b/app/views/mailer/news_comment_added.text.plain.rhtml new file mode 100644 index 00000000..aadbc37c --- /dev/null +++ b/app/views/mailer/news_comment_added.text.plain.rhtml @@ -0,0 +1,6 @@ +<%= @news.title %> +<%= @news_url %> + +<%= l(:text_user_wrote, :value => @comment.author) %> + +<%= @comment.comments %> diff --git a/app/views/news/show.rhtml b/app/views/news/show.rhtml index 0dc3fe35..28db44e9 100644 --- a/app/views/news/show.rhtml +++ b/app/views/news/show.rhtml @@ -1,4 +1,5 @@
    +<%= watcher_tag(@news, User.current) %> <%= link_to(l(:button_edit), edit_news_path(@news), :class => 'icon icon-edit', diff --git a/config/environment.rb b/config/environment.rb index 91dfaa42..00e81517 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -36,7 +36,7 @@ Rails::Initializer.run do |config| # Activate observers that should always be running # config.active_record.observers = :cacher, :garbage_collector - config.active_record.observers = :message_observer, :issue_observer, :journal_observer, :news_observer, :document_observer, :wiki_content_observer + config.active_record.observers = :message_observer, :issue_observer, :journal_observer, :news_observer, :document_observer, :wiki_content_observer, :comment_observer # Make Active Record use UTC-base instead of local time # config.active_record.default_timezone = :utc diff --git a/config/locales/en.yml b/config/locales/en.yml index c0fb8fca..3649fe23 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -537,6 +537,7 @@ en: label_news_latest: Latest news label_news_view_all: View all news label_news_added: News added + label_news_comment_added: Comment added to a news label_settings: Settings label_overview: Overview label_version: Version diff --git a/config/locales/fr.yml b/config/locales/fr.yml index b3a60ba7..356f3799 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -539,6 +539,7 @@ fr: label_news_latest: Dernières annonces label_news_view_all: Voir toutes les annonces label_news_added: Annonce ajoutée + label_news_comment_added: Commentaire ajouté à une annonce label_settings: Configuration label_overview: Aperçu label_version: Version diff --git a/lib/redmine/notifiable.rb b/lib/redmine/notifiable.rb index 71d1ba50..37d4a407 100644 --- a/lib/redmine/notifiable.rb +++ b/lib/redmine/notifiable.rb @@ -14,6 +14,7 @@ module Redmine notifications << Notifiable.new('issue_status_updated', 'issue_updated') notifications << Notifiable.new('issue_priority_updated', 'issue_updated') notifications << Notifiable.new('news_added') + notifications << Notifiable.new('news_comment_added') notifications << Notifiable.new('document_added') notifications << Notifiable.new('file_added') notifications << Notifiable.new('message_posted') diff --git a/test/unit/comment_test.rb b/test/unit/comment_test.rb index 43265c47..02be8fc5 100644 --- a/test/unit/comment_test.rb +++ b/test/unit/comment_test.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -31,6 +31,15 @@ class CommentTest < ActiveSupport::TestCase @news.reload assert_equal 2, @news.comments_count end + + def test_create_should_send_notification + Setting.notified_events << 'news_comment_added' + Watcher.create!(:watchable => @news, :user => @jsmith) + + assert_difference 'ActionMailer::Base.deliveries.size' do + Comment.create!(:commented => @news, :author => @jsmith, :comments => "my comment") + end + end def test_validate comment = Comment.new(:commented => @news) diff --git a/test/unit/lib/redmine/notifiable_test.rb b/test/unit/lib/redmine/notifiable_test.rb index fe02fbfc..7ca44920 100644 --- a/test/unit/lib/redmine/notifiable_test.rb +++ b/test/unit/lib/redmine/notifiable_test.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -22,9 +22,9 @@ class Redmine::NotifiableTest < ActiveSupport::TestCase end def test_all - assert_equal 11, Redmine::Notifiable.all.length + assert_equal 12, Redmine::Notifiable.all.length - %w(issue_added issue_updated issue_note_added issue_status_updated issue_priority_updated news_added document_added file_added message_posted wiki_content_added wiki_content_updated).each do |notifiable| + %w(issue_added issue_updated issue_note_added issue_status_updated issue_priority_updated news_added news_comment_added document_added file_added message_posted wiki_content_added wiki_content_updated).each do |notifiable| assert Redmine::Notifiable.all.collect(&:name).include?(notifiable), "missing #{notifiable}" end end diff --git a/test/unit/mailer_test.rb b/test/unit/mailer_test.rb index ae7c06d3..36ed4fe9 100644 --- a/test/unit/mailer_test.rb +++ b/test/unit/mailer_test.rb @@ -1,5 +1,5 @@ -# redMine - project management software -# Copyright (C) 2006-2007 Jean-Philippe Lang +# Redmine - project management software +# Copyright (C) 2006-2011 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License @@ -20,7 +20,7 @@ require File.expand_path('../../test_helper', __FILE__) class MailerTest < ActiveSupport::TestCase include Redmine::I18n include ActionController::Assertions::SelectorAssertions - fixtures :projects, :enabled_modules, :issues, :users, :members, :member_roles, :roles, :documents, :attachments, :news, :tokens, :journals, :journal_details, :changesets, :trackers, :issue_statuses, :enumerations, :messages, :boards, :repositories + fixtures :all def setup ActionMailer::Base.deliveries.clear @@ -295,6 +295,14 @@ class MailerTest < ActiveSupport::TestCase end end + def test_news_comment_added + comment = Comment.find(2) + valid_languages.each do |lang| + Setting.default_language = lang.to_s + assert Mailer.deliver_news_comment_added(comment) + end + end + def test_message_posted message = Message.find(:first) recipients = ([message.root] + message.root.children).collect {|m| m.author.mail if m.author} From dac912b379e12d3eedbe497cb26b0f60b26e6f83 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 4 Mar 2011 14:43:53 +0000 Subject: [PATCH 347/777] Fixed: Email notifications are sent to watchers even if 'No events' setting is chosen (#7763). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5004 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/watcher_test.rb | 10 +++++----- .../plugins/acts_as_watchable/lib/acts_as_watchable.rb | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/test/unit/watcher_test.rb b/test/unit/watcher_test.rb index 48c30313..86d96b2c 100644 --- a/test/unit/watcher_test.rb +++ b/test/unit/watcher_test.rb @@ -60,15 +60,15 @@ class WatcherTest < ActiveSupport::TestCase assert @issue.watcher_recipients.empty? assert @issue.add_watcher(@user) - @user.mail_notification = true - @user.save + @user.mail_notification = 'all' + @user.save! @issue.reload assert @issue.watcher_recipients.include?(@user.mail) - @user.mail_notification = false - @user.save + @user.mail_notification = 'none' + @user.save! @issue.reload - assert @issue.watcher_recipients.include?(@user.mail) + assert !@issue.watcher_recipients.include?(@user.mail) end def test_unwatch diff --git a/vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb b/vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb index e026a6dd..61196d9a 100644 --- a/vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb +++ b/vendor/plugins/acts_as_watchable/lib/acts_as_watchable.rb @@ -58,7 +58,8 @@ module Redmine # Returns an array of watchers' email addresses def watcher_recipients notified = watcher_users.active - + notified.reject! {|user| user.mail_notification == 'none'} + if respond_to?(:visible?) notified.reject! {|user| !visible?(user)} end From 25ce0e6cd2fe9a04e1daf8ca35d365b066ca9c15 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 4 Mar 2011 14:52:47 +0000 Subject: [PATCH 348/777] Extends custom field possible values textarea. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5005 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/custom_fields/_form.rhtml | 1 - public/stylesheets/application.css | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/custom_fields/_form.rhtml b/app/views/custom_fields/_form.rhtml index a71df87a..f2be4292 100644 --- a/app/views/custom_fields/_form.rhtml +++ b/app/views/custom_fields/_form.rhtml @@ -61,7 +61,6 @@ function toggle_custom_field_format() { <%= f.text_field :max_length, :size => 5, :no_label => true %>
    (<%=l(:text_min_max_length_info)%>)

    <%= f.text_field :regexp, :size => 50 %>
    (<%=l(:text_regexp_info)%>)

    <%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), - :cols => 20, :rows => 15 %>
    <%= l(:text_custom_field_possible_values_info) %>

    <%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %>

    diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index d44ae546..bad96fc7 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -370,6 +370,8 @@ ul.properties li span {font-style:italic;} #workflow_copy_form select { width: 200px; } +textarea#custom_field_possible_values {width: 99%} + .pagination {font-size: 90%} p.pagination {margin-top:8px;} From 19083725ff07c5333980f394f8c445fd0b0197d6 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 4 Mar 2011 14:55:33 +0000 Subject: [PATCH 349/777] Removes duplicate DOM id in custom field form. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5006 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/custom_fields/_form.rhtml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/views/custom_fields/_form.rhtml b/app/views/custom_fields/_form.rhtml index f2be4292..d34c756d 100644 --- a/app/views/custom_fields/_form.rhtml +++ b/app/views/custom_fields/_form.rhtml @@ -60,9 +60,10 @@ function toggle_custom_field_format() { <%= f.text_field :min_length, :size => 5, :no_label => true %> - <%= f.text_field :max_length, :size => 5, :no_label => true %>
    (<%=l(:text_min_max_length_info)%>)

    <%= f.text_field :regexp, :size => 50 %>
    (<%=l(:text_regexp_info)%>)

    -

    <%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), - :rows => 15 %> -
    <%= l(:text_custom_field_possible_values_info) %>

    +

    + <%= f.text_area :possible_values, :value => @custom_field.possible_values.to_a.join("\n"), :rows => 15 %> +
    <%= l(:text_custom_field_possible_values_info) %> +

    <%= @custom_field.field_format == 'bool' ? f.check_box(:default_value) : f.text_field(:default_value) %>

    <%= call_hook(:view_custom_fields_form_upper_box, :custom_field => @custom_field, :form => f) %>
    From 52397646b2d79a6a6c42a64a57eec46a754286c9 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 4 Mar 2011 15:14:24 +0000 Subject: [PATCH 350/777] Fixed: Login page should not show projects link and search box if authentication is required (#3715). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5007 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/layouts/base.rhtml | 4 +++- test/integration/layout_test.rb | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/app/views/layouts/base.rhtml b/app/views/layouts/base.rhtml index 5e9d6399..a169116c 100644 --- a/app/views/layouts/base.rhtml +++ b/app/views/layouts/base.rhtml @@ -29,10 +29,11 @@ <%= render_menu :account_menu -%>
    <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}", :id => 'loggedas') if User.current.logged? %> - <%= render_menu :top_menu -%> + <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%>
    -<% users = User.active.find(:all, :limit => 100) - @group.users %> +<% users = User.active.not_in_group(@group).all(:limit => 100) %> <% if users.any? %> <% remote_form_for(:group, @group, :url => {:controller => 'groups', :action => 'add_users', :id => @group}, :method => :post) do |f| %>
    <%=l(:label_user_new)%> diff --git a/test/functional/groups_controller_test.rb b/test/functional/groups_controller_test.rb index a1a164b0..f45dfc45 100644 --- a/test/functional/groups_controller_test.rb +++ b/test/functional/groups_controller_test.rb @@ -104,4 +104,13 @@ class GroupsControllerTest < ActionController::TestCase post :destroy_membership, :id => 10, :membership_id => 6 end end + + def test_autocomplete_for_user + get :autocomplete_for_user, :id => 10, :q => 'mis' + assert_response :success + users = assigns(:users) + assert_not_nil users + assert users.any? + assert !users.include?(Group.find(10).users.first) + end end From cfbe69ab598a56c87420f9d7a70bfc37b172ab9d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 1 Apr 2011 18:42:41 +0000 Subject: [PATCH 603/777] Fixed: deleting a parent issue may lead to a stale object error (#7920). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5285 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- test/unit/issue_nested_set_test.rb | 10 ++++++++++ .../awesome_nested_set/lib/awesome_nested_set.rb | 3 +++ 2 files changed, 13 insertions(+) diff --git a/test/unit/issue_nested_set_test.rb b/test/unit/issue_nested_set_test.rb index cf61cfde..46f4dc4d 100644 --- a/test/unit/issue_nested_set_test.rb +++ b/test/unit/issue_nested_set_test.rb @@ -223,6 +223,16 @@ class IssueNestedSetTest < ActiveSupport::TestCase assert_equal [issue1.id, 2, 3], [issue4.root_id, issue4.lft, issue4.rgt] end + def test_destroy_parent_issue_updated_during_children_destroy + parent = create_issue! + create_issue!(:start_date => Date.today, :parent_issue_id => parent.id) + create_issue!(:start_date => 2.days.from_now, :parent_issue_id => parent.id) + + assert_difference 'Issue.count', -3 do + Issue.find(parent.id).destroy + end + end + def test_destroy_child_issue_with_children root = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'root') child = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => root.id) diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb index fc5278d6..b2ebd669 100644 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb @@ -466,6 +466,9 @@ module CollectiveIdea #:nodoc: ["#{quoted_right_column_name} >= ?", right] ) end + + # Reload is needed because children may have updated their parent (self) during deletion. + reload end # reload left, right, and parent From e6659501de3ce6fc2df095fbcd8b752b2102b7d9 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 1 Apr 2011 18:58:29 +0000 Subject: [PATCH 604/777] Limits nested set overhead when destroying an issue without children. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5286 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb index b2ebd669..b1e5ae1e 100644 --- a/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb +++ b/vendor/plugins/awesome_nested_set/lib/awesome_nested_set.rb @@ -444,11 +444,12 @@ module CollectiveIdea #:nodoc: # Prunes a branch off of the tree, shifting all of the elements on the right # back to the left so the counts still work. def prune_from_tree - return if right.nil? || left.nil? || !self.class.exists?(id) + return if right.nil? || left.nil? || leaf? || !self.class.exists?(id) delete_method = acts_as_nested_set_options[:dependent] == :destroy ? :destroy_all : :delete_all + # TODO: should destroy children (not descendants) when deleted_method is :destroy_all self.class.base_class.transaction do reload_nested_set nested_set_scope.send(delete_method, From 2431d830b10650bc6b30ab23602fe24a25ac8871 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 1 Apr 2011 19:04:26 +0000 Subject: [PATCH 605/777] No PUT request to get previous/next month. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5287 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/calendars_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/calendars_helper.rb b/app/helpers/calendars_helper.rb index 08e665dc..6953968c 100644 --- a/app/helpers/calendars_helper.rb +++ b/app/helpers/calendars_helper.rb @@ -37,7 +37,7 @@ module CalendarsHelper link_target = calendar_path(:year => year, :month => month, :project_id => project_id) link_to_remote(link_name, - {:update => "content", :url => link_target, :method => :put}, + {:update => "content", :url => link_target, :method => :get}, {:href => link_target}) end From ed867c4a7f970b982d46510145f5383303f53810 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Fri, 1 Apr 2011 19:32:07 +0000 Subject: [PATCH 606/777] Adds an index on users.type for faster retrieval of groups. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5288 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- db/migrate/20110401192910_add_index_to_users_type.rb | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 db/migrate/20110401192910_add_index_to_users_type.rb diff --git a/db/migrate/20110401192910_add_index_to_users_type.rb b/db/migrate/20110401192910_add_index_to_users_type.rb new file mode 100644 index 00000000..b9f50112 --- /dev/null +++ b/db/migrate/20110401192910_add_index_to_users_type.rb @@ -0,0 +1,9 @@ +class AddIndexToUsersType < ActiveRecord::Migration + def self.up + add_index :users, :type + end + + def self.down + remove_index :users, :type + end +end From 6485f15bb912986fad13b09d102948f1a65324f8 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Sat, 2 Apr 2011 08:01:29 +0000 Subject: [PATCH 607/777] PDF: fix the problem that TCPDF built-in font breaks in the Windows (#61). This problem occurs because the EOF character string is included in the built-in font. Contributed by Jun NAITOH. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5290 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- vendor/plugins/rfpdf/lib/tcpdf.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/plugins/rfpdf/lib/tcpdf.rb b/vendor/plugins/rfpdf/lib/tcpdf.rb index da7d556f..1e444305 100755 --- a/vendor/plugins/rfpdf/lib/tcpdf.rb +++ b/vendor/plugins/rfpdf/lib/tcpdf.rb @@ -3063,7 +3063,7 @@ class TCPDF out('/Filter /FlateDecode'); end out('>>'); - open(ctgfile) do |f| + open(ctgfile, "rb") do |f| putstream(f.read()) end out('endobj'); From 7f0a29f7c2948cfc651bb3782c39a217650868f4 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Sat, 2 Apr 2011 08:01:47 +0000 Subject: [PATCH 608/777] PDF: set enable to use TCPDF UTF-8 on Windows except CJK and Thai (#61). Contributed by Jun NAITOH. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5291 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/export/pdf.rb | 6 ++---- lib/redmine/helpers/gantt.rb | 3 +-- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb index d6f247ec..ccfd3421 100644 --- a/lib/redmine/export/pdf.rb +++ b/lib/redmine/export/pdf.rb @@ -179,8 +179,7 @@ module Redmine # Returns a PDF string of a list of issues def issues_to_pdf(issues, project, query) - if Redmine::Platform.mswin? || - ( current_language.to_s.downcase == 'ko' || + if ( current_language.to_s.downcase == 'ko' || current_language.to_s.downcase == 'ja' || current_language.to_s.downcase == 'zh' || current_language.to_s.downcase == 'zh-tw' || @@ -259,8 +258,7 @@ module Redmine # Returns a PDF string of a single issue def issue_to_pdf(issue) - if Redmine::Platform.mswin? || - ( current_language.to_s.downcase == 'ko' || + if ( current_language.to_s.downcase == 'ko' || current_language.to_s.downcase == 'ja' || current_language.to_s.downcase == 'zh' || current_language.to_s.downcase == 'zh-tw' || diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb index bc0fafe4..6b891999 100644 --- a/lib/redmine/helpers/gantt.rb +++ b/lib/redmine/helpers/gantt.rb @@ -511,8 +511,7 @@ module Redmine end if Object.const_defined?(:Magick) def to_pdf - if Redmine::Platform.mswin? || - ( current_language.to_s.downcase == 'ko' || + if ( current_language.to_s.downcase == 'ko' || current_language.to_s.downcase == 'ja' || current_language.to_s.downcase == 'zh' || current_language.to_s.downcase == 'zh-tw' || From 3374130e608e15a89dfd031d3cfbfee79110604d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sat, 2 Apr 2011 10:18:05 +0000 Subject: [PATCH 609/777] Skip a few count(*) SQL queries on the issue list. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5292 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/query.rb | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/app/models/query.rb b/app/models/query.rb index 0ef56c69..2249c37e 100644 --- a/app/models/query.rb +++ b/app/models/query.rb @@ -216,14 +216,19 @@ class Query < ActiveRecord::Base if project # project specific filters - unless @project.issue_categories.empty? - @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => @project.issue_categories.collect{|s| [s.name, s.id.to_s] } } + categories = @project.issue_categories.all + unless categories.empty? + @available_filters["category_id"] = { :type => :list_optional, :order => 6, :values => categories.collect{|s| [s.name, s.id.to_s] } } end - unless @project.shared_versions.empty? - @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => @project.shared_versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } + versions = @project.shared_versions.all + unless versions.empty? + @available_filters["fixed_version_id"] = { :type => :list_optional, :order => 7, :values => versions.sort.collect{|s| ["#{s.project.name} - #{s.name}", s.id.to_s] } } end - unless @project.descendants.active.empty? - @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => @project.descendants.visible.collect{|s| [s.name, s.id.to_s] } } + unless @project.leaf? + subprojects = @project.descendants.visible.all + unless subprojects.empty? + @available_filters["subproject_id"] = { :type => :list_subprojects, :order => 13, :values => subprojects.collect{|s| [s.name, s.id.to_s] } } + end end add_custom_fields_filters(@project.all_issue_custom_fields) else From 1d0b4dcdcc8906855288b6283d79316bbb9247e8 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sat, 2 Apr 2011 11:31:33 +0000 Subject: [PATCH 610/777] Do not load projects association in #rolled_up_trackers. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5293 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/models/project.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/project.rb b/app/models/project.rb index 9a7d8722..33078dd7 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -353,7 +353,7 @@ class Project < ActiveRecord::Base # Returns an array of the trackers used by the project and its active sub projects def rolled_up_trackers @rolled_up_trackers ||= - Tracker.find(:all, :include => :projects, + Tracker.find(:all, :joins => :projects, :select => "DISTINCT #{Tracker.table_name}.*", :conditions => ["#{Project.table_name}.lft >= ? AND #{Project.table_name}.rgt <= ? AND #{Project.table_name}.status = #{STATUS_ACTIVE}", lft, rgt], :order => "#{Tracker.table_name}.position") From 1cab1bd51e0ddca225dec68b5c2b34f163ee4dd9 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sat, 2 Apr 2011 11:46:20 +0000 Subject: [PATCH 611/777] Skip a count(*) SQL query. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5294 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/projects_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index f80cbbf2..ea2ddd13 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -143,7 +143,7 @@ class ProjectsController < ApplicationController end @users_by_role = @project.users_by_role - @subprojects = @project.children.visible + @subprojects = @project.children.visible.all @news = @project.news.find(:all, :limit => 5, :include => [ :author, :project ], :order => "#{News.table_name}.created_on DESC") @trackers = @project.rolled_up_trackers From 73c5191196a2ce86e305dc0977e0bd6552526632 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Sun, 3 Apr 2011 02:12:09 +0000 Subject: [PATCH 612/777] PDF: fix width calculation of multi byte character in Simplified and Traditional Chinese (#61). Contributed by Jun NAITOH. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5295 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- vendor/plugins/rfpdf/lib/fpdf/chinese.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vendor/plugins/rfpdf/lib/fpdf/chinese.rb b/vendor/plugins/rfpdf/lib/fpdf/chinese.rb index e072e515..94f8ee49 100644 --- a/vendor/plugins/rfpdf/lib/fpdf/chinese.rb +++ b/vendor/plugins/rfpdf/lib/fpdf/chinese.rb @@ -210,7 +210,7 @@ module PDF_Chinese #Automatic line break if(sep==-1 or i==j) if(i==j) - i+=ascii ? 1 : 3 + i+=ascii ? 1 : 2 end Cell(w,h,s[j,i-j],b,2,align,fill) else @@ -225,7 +225,7 @@ module PDF_Chinese b=b2 end else - i+=ascii ? 1 : 3 + i+=ascii ? 1 : 2 end end #Last chunk @@ -294,7 +294,7 @@ module PDF_Chinese next end if(i==j) - i+=ascii ? 1 : 3 + i+=ascii ? 1 : 2 end Cell(w,h,s[j,i-j],0,2,'',0,link) else @@ -311,7 +311,7 @@ module PDF_Chinese end nl+=1 else - i+=ascii ? 1 : 3 + i+=ascii ? 1 : 2 end end #Last chunk From 966a7a9c3462f8b0d5e7126a37b5fb9276da7bc6 Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Sun, 3 Apr 2011 02:47:06 +0000 Subject: [PATCH 613/777] PDF: code clean up lib/redmine/export/pdf.rb. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5296 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine/export/pdf.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/redmine/export/pdf.rb b/lib/redmine/export/pdf.rb index ccfd3421..baf553ca 100644 --- a/lib/redmine/export/pdf.rb +++ b/lib/redmine/export/pdf.rb @@ -132,7 +132,7 @@ module Redmine end || '' super(txt) end - + def textstring(s) # Format a text string if s =~ /^ Date: Sun, 3 Apr 2011 11:55:24 +0000 Subject: [PATCH 614/777] Changed timelogs filters to use non-AJAX requests (#1965). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5297 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/time_entry_reports/report.rhtml | 9 +++----- app/views/timelog/_date_range.rhtml | 10 +++------ app/views/timelog/index.html.erb | 6 +---- config/routes.rb | 7 +++--- .../time_entry_reports_controller_test.rb | 10 +++++++-- test/functional/timelog_controller_test.rb | 22 +++++++++++++++---- 6 files changed, 37 insertions(+), 27 deletions(-) diff --git a/app/views/time_entry_reports/report.rhtml b/app/views/time_entry_reports/report.rhtml index 5ae9d655..18e782cc 100644 --- a/app/views/time_entry_reports/report.rhtml +++ b/app/views/time_entry_reports/report.rhtml @@ -6,7 +6,7 @@

    <%= l(:label_spent_time) %>

    -<% form_remote_tag(:url => {}, :html => {:method => :get, :id => 'query_form'}, :method => :get, :update => 'content') do %> +<% form_tag({:controller => 'time_entry_reports', :action => 'report', :project_id => @project, :issue_id => @issue}, :method => :get, :id => 'query_form') do %> <% @criterias.each do |criteria| %> <%= hidden_field_tag 'criterias[]', criteria, :id => nil %> <% end %> @@ -22,14 +22,11 @@ :onchange => "this.form.onsubmit();" %> <%= l(:button_add) %>: <%= select_tag('criterias[]', options_for_select([[]] + (@available_criterias.keys - @criterias).collect{|k| [l_or_humanize(@available_criterias[k][:label]), k]}), - :onchange => "this.form.onsubmit();", + :onchange => "this.form.submit();", :style => 'width: 200px', :id => nil, :disabled => (@criterias.length >= 3)) %> - <%= link_to_remote l(:button_clear), {:url => {:project_id => @project, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns}, - :method => :get, - :update => 'content' - }, :class => 'icon icon-reload' %>

    + <%= link_to l(:button_clear), {:project_id => @project, :issue_id => @issue, :period_type => params[:period_type], :period => params[:period], :from => @from, :to => @to, :columns => @columns}, :class => 'icon icon-reload' %>

    <% end %> <% unless @criterias.empty? %> diff --git a/app/views/timelog/_date_range.rhtml b/app/views/timelog/_date_range.rhtml index 727de25e..42ea53b7 100644 --- a/app/views/timelog/_date_range.rhtml +++ b/app/views/timelog/_date_range.rhtml @@ -4,7 +4,7 @@

    <%= radio_button_tag 'period_type', '1', !@free_period %> <%= select_tag 'period', options_for_period_select(params[:period]), - :onchange => 'this.form.onsubmit();', + :onchange => 'this.form.submit();', :onfocus => '$("period_type_1").checked = true;' %>

    @@ -17,12 +17,8 @@

    - <%= link_to_remote l(:button_apply), - { :url => { }, - :update => "content", - :with => "Form.serialize('query_form')", - :method => :get - }, :class => 'icon icon-checked' %> + <%= link_to_function l(:button_apply), '$("query_form").submit()', :class => 'icon icon-checked' %> + <%= link_to l(:button_clear), {:controller => controller_name, :action => action_name, :project_id => @project, :issue_id => @issue}, :class => 'icon icon-reload' %>

    diff --git a/app/views/timelog/index.html.erb b/app/views/timelog/index.html.erb index 737476f3..d943d430 100644 --- a/app/views/timelog/index.html.erb +++ b/app/views/timelog/index.html.erb @@ -6,11 +6,7 @@

    <%= l(:label_spent_time) %>

    -<% form_remote_tag( :url => {}, :html => {:method => :get, :id => 'query_form'}, :method => :get, :update => 'content' ) do %> -<%# TOOD: remove the project_id and issue_id hidden fields, that information is -already in the URI %> -<%= hidden_field_tag('project_id', params[:project_id]) if @project %> -<%= hidden_field_tag 'issue_id', params[:issue_id] if @issue %> +<% form_tag({:controller => 'timelog', :action => 'index', :project_id => @project, :issue_id => @issue}, :method => :get, :id => 'query_form') do %> <%= render :partial => 'date_range' %> <% end %> diff --git a/config/routes.rb b/config/routes.rb index 3b37b515..378fdb0b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,14 +14,15 @@ ActionController::Routing::Routes.draw do |map| map.connect 'roles/workflow/:id/:role_id/:tracker_id', :controller => 'roles', :action => 'workflow' map.connect 'help/:ctrl/:page', :controller => 'help' - map.connect 'projects/:project_id/time_entries/report', :controller => 'time_entry_reports', :action => 'report' map.with_options :controller => 'time_entry_reports', :action => 'report',:conditions => {:method => :get} do |time_report| + time_report.connect 'projects/:project_id/issues/:issue_id/time_entries/report' + time_report.connect 'projects/:project_id/issues/:issue_id/time_entries/report.:format' + time_report.connect 'projects/:project_id/time_entries/report' + time_report.connect 'projects/:project_id/time_entries/report.:format' time_report.connect 'time_entries/report' time_report.connect 'time_entries/report.:format' - time_report.connect 'projects/:project_id/time_entries/report.:format' end - # TODO: wasteful since this is also nested under issues, projects, and projects/issues map.resources :time_entries, :controller => 'timelog' map.connect 'projects/:id/wiki', :controller => 'wikis', :action => 'edit', :conditions => {:method => :post} diff --git a/test/functional/time_entry_reports_controller_test.rb b/test/functional/time_entry_reports_controller_test.rb index 70a3d1c7..b53eebd7 100644 --- a/test/functional/time_entry_reports_controller_test.rb +++ b/test/functional/time_entry_reports_controller_test.rb @@ -4,16 +4,20 @@ require File.expand_path('../../test_helper', __FILE__) class TimeEntryReportsControllerTest < ActionController::TestCase fixtures :projects, :enabled_modules, :roles, :members, :member_roles, :issues, :time_entries, :users, :trackers, :enumerations, :issue_statuses, :custom_fields, :custom_values - def test_report_no_criteria - get :report, :project_id => 1 + def test_report_at_project_level + get :report, :project_id => 'ecookbook' assert_response :success assert_template 'report' + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries/report", :id => 'query_form'} end def test_report_all_projects get :report assert_response :success assert_template 'report' + assert_tag :form, + :attributes => {:action => "/time_entries/report", :id => 'query_form'} end def test_report_all_projects_denied @@ -80,6 +84,8 @@ class TimeEntryReportsControllerTest < ActionController::TestCase assert_template 'report' assert_not_nil assigns(:total_hours) assert_equal "154.25", "%.2f" % assigns(:total_hours) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/issues/1/time_entries/report", :id => 'query_form'} end def test_report_custom_field_criteria diff --git a/test/functional/timelog_controller_test.rb b/test/functional/timelog_controller_test.rb index 634363dd..669014d8 100644 --- a/test/functional/timelog_controller_test.rb +++ b/test/functional/timelog_controller_test.rb @@ -163,10 +163,12 @@ class TimelogControllerTest < ActionController::TestCase assert_template 'index' assert_not_nil assigns(:total_hours) assert_equal "162.90", "%.2f" % assigns(:total_hours) + assert_tag :form, + :attributes => {:action => "/time_entries", :id => 'query_form'} end def test_index_at_project_level - get :index, :project_id => 1 + get :index, :project_id => 'ecookbook' assert_response :success assert_template 'index' assert_not_nil assigns(:entries) @@ -178,10 +180,12 @@ class TimelogControllerTest < ActionController::TestCase # display all time by default assert_equal '2007-03-12'.to_date, assigns(:from) assert_equal '2007-04-22'.to_date, assigns(:to) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} end def test_index_at_project_level_with_date_range - get :index, :project_id => 1, :from => '2007-03-20', :to => '2007-04-30' + get :index, :project_id => 'ecookbook', :from => '2007-03-20', :to => '2007-04-30' assert_response :success assert_template 'index' assert_not_nil assigns(:entries) @@ -190,24 +194,30 @@ class TimelogControllerTest < ActionController::TestCase assert_equal "12.90", "%.2f" % assigns(:total_hours) assert_equal '2007-03-20'.to_date, assigns(:from) assert_equal '2007-04-30'.to_date, assigns(:to) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} end def test_index_at_project_level_with_period - get :index, :project_id => 1, :period => '7_days' + get :index, :project_id => 'ecookbook', :period => '7_days' assert_response :success assert_template 'index' assert_not_nil assigns(:entries) assert_not_nil assigns(:total_hours) assert_equal Date.today - 7, assigns(:from) assert_equal Date.today, assigns(:to) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} end def test_index_one_day - get :index, :project_id => 1, :from => "2007-03-23", :to => "2007-03-23" + get :index, :project_id => 'ecookbook', :from => "2007-03-23", :to => "2007-03-23" assert_response :success assert_template 'index' assert_not_nil assigns(:total_hours) assert_equal "4.25", "%.2f" % assigns(:total_hours) + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/time_entries", :id => 'query_form'} end def test_index_at_issue_level @@ -221,6 +231,10 @@ class TimelogControllerTest < ActionController::TestCase # display all time based on what's been logged assert_equal '2007-03-12'.to_date, assigns(:from) assert_equal '2007-04-22'.to_date, assigns(:to) + # TODO: remove /projects/:project_id/issues/:issue_id/time_entries routes + # to use /issues/:issue_id/time_entries + assert_tag :form, + :attributes => {:action => "/projects/ecookbook/issues/1/time_entries", :id => 'query_form'} end def test_index_atom_feed From 82b638f727eb18c844c3323b8c466698ee15832e Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 3 Apr 2011 12:02:10 +0000 Subject: [PATCH 615/777] Removed hidden project_id and issue_id parameters. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5298 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/time_entry_reports/report.rhtml | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/views/time_entry_reports/report.rhtml b/app/views/time_entry_reports/report.rhtml index 18e782cc..de2d1093 100644 --- a/app/views/time_entry_reports/report.rhtml +++ b/app/views/time_entry_reports/report.rhtml @@ -10,9 +10,6 @@ <% @criterias.each do |criteria| %> <%= hidden_field_tag 'criterias[]', criteria, :id => nil %> <% end %> - <%# TODO: get rid of the project_id field, that should already be in the URL %> - <%= hidden_field_tag('project_id', params[:project_id]) if @project %> - <%= hidden_field_tag('issue_id', params[:issue_id]) if @issue %> <%= render :partial => 'timelog/date_range' %>

    <%= l(:label_details) %>: <%= select_tag 'columns', options_for_select([[l(:label_year), 'year'], From 0c0763ad4b87a1bdd13b7b8522e7313a3a824b4d Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 3 Apr 2011 12:02:56 +0000 Subject: [PATCH 616/777] Disable unused fields when switching the period type. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5299 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/timelog/_date_range.rhtml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/app/views/timelog/_date_range.rhtml b/app/views/timelog/_date_range.rhtml index 42ea53b7..e916bc18 100644 --- a/app/views/timelog/_date_range.rhtml +++ b/app/views/timelog/_date_range.rhtml @@ -2,16 +2,17 @@ <%= l(:label_date_range) %>

    -<%= radio_button_tag 'period_type', '1', !@free_period %> +<%= radio_button_tag 'period_type', '1', !@free_period, :onclick => 'Form.Element.disable("from");Form.Element.disable("to");Form.Element.enable("period");' %> <%= select_tag 'period', options_for_period_select(params[:period]), :onchange => 'this.form.submit();', - :onfocus => '$("period_type_1").checked = true;' %> + :onfocus => '$("period_type_1").checked = true;', + :disabled => @free_period %>

    -<%= radio_button_tag 'period_type', '2', @free_period %> +<%= radio_button_tag 'period_type', '2', @free_period, :onclick => 'Form.Element.enable("from");Form.Element.enable("to");Form.Element.disable("period");' %> -<%= l(:label_date_from_to, :start => (text_field_tag('from', @from, :size => 10) + calendar_for('from')), - :end => (text_field_tag('to', @to, :size => 10) + calendar_for('to'))) %> +<%= l(:label_date_from_to, :start => (text_field_tag('from', @from, :size => 10, :disabled => !@free_period) + calendar_for('from')), + :end => (text_field_tag('to', @to, :size => 10, :disabled => !@free_period) + calendar_for('to'))) %>

    From 844c0d97aad079806577a348aef4898daf9c5b50 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 3 Apr 2011 12:33:27 +0000 Subject: [PATCH 617/777] Removed the changeset-changes class to the commit logs on the issue view (#8038). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5300 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/views/issues/_changesets.rhtml | 2 +- public/stylesheets/rtl.css | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/app/views/issues/_changesets.rhtml b/app/views/issues/_changesets.rhtml index d5a29289..76e9a281 100644 --- a/app/views/issues/_changesets.rhtml +++ b/app/views/issues/_changesets.rhtml @@ -3,7 +3,7 @@

    <%= link_to_revision(changeset, changeset.project, :text => "#{l(:label_revision)} #{changeset.format_identifier}") %>
    <%= authoring(changeset.committed_on, changeset.author) %>

    -
    +
    <%= textilizable(changeset, :comments) %>
    diff --git a/public/stylesheets/rtl.css b/public/stylesheets/rtl.css index 5dfe320b..ea6574bc 100644 --- a/public/stylesheets/rtl.css +++ b/public/stylesheets/rtl.css @@ -56,6 +56,7 @@ table.list td.buttons a { padding-right: 20px; } .changeset-changes { direction: ltr; padding-left: 2em } .changesets { direction: ltr; } div#issue-changesets { float: left; margin-right: 1em; margin-left: 0 } +div#issue-changesets div.wiki { direction: ltr; padding-left: 2em } #activity dt, .journal { clear: right; } .journal-link { float: left; } div.wiki pre { direction: ltr; } From 07cf681d61f89b372eaff6702acfb3738136e78c Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 3 Apr 2011 14:01:32 +0000 Subject: [PATCH 618/777] Makes all pagination-like links use #link_to_content_update (#5138). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5301 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/application_helper.rb | 16 ++++++---------- app/helpers/calendars_helper.rb | 10 +--------- app/helpers/gantt_helper.rb | 14 ++++++-------- app/helpers/sort_helper.rb | 5 +---- app/views/activities/index.html.erb | 14 ++++++-------- app/views/gantts/show.html.erb | 4 ++-- app/views/search/index.rhtml | 12 ++++-------- 7 files changed, 26 insertions(+), 49 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 68291797..90439b7d 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -340,15 +340,15 @@ module ApplicationHelper html = '' if paginator.current.previous - html << link_to_remote_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' ' + html << link_to_content_update('« ' + l(:label_previous), url_param.merge(page_param => paginator.current.previous)) + ' ' end html << (pagination_links_each(paginator, options) do |n| - link_to_remote_content_update(n.to_s, url_param.merge(page_param => n)) + link_to_content_update(n.to_s, url_param.merge(page_param => n)) end || '') if paginator.current.next - html << ' ' + link_to_remote_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next)) + html << ' ' + link_to_content_update((l(:label_next) + ' »'), url_param.merge(page_param => paginator.current.next)) end unless count.nil? @@ -363,10 +363,7 @@ module ApplicationHelper def per_page_links(selected=nil) links = Setting.per_page_options_array.collect do |n| - n == selected ? n : link_to_remote(n, {:update => "content", - :url => params.merge(:per_page => n), - :method => :get}, - {:href => url_for(params.merge(:per_page => n))}) + n == selected ? n : link_to_content_update(n, params.merge(:per_page => n)) end links.size > 1 ? l(:label_display_per_page, links.join(', ')) : nil end @@ -944,11 +941,10 @@ module ApplicationHelper return self end - def link_to_remote_content_update(text, url_params) + def link_to_content_update(text, url_params = {}, html_options = {}) link_to_remote(text, {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(:params => url_params)} + {:href => url_for(:params => url_params)}.merge(html_options) ) end - end diff --git a/app/helpers/calendars_helper.rb b/app/helpers/calendars_helper.rb index 6953968c..82f3905e 100644 --- a/app/helpers/calendars_helper.rb +++ b/app/helpers/calendars_helper.rb @@ -32,14 +32,6 @@ module CalendarsHelper end def link_to_month(link_name, year, month, options={}) - project_id = options[:project].present? ? options[:project].to_param : nil - - link_target = calendar_path(:year => year, :month => month, :project_id => project_id) - - link_to_remote(link_name, - {:update => "content", :url => link_target, :method => :get}, - {:href => link_target}) - + link_to_content_update(link_name, params.merge(:year => year, :month => month)) end - end diff --git a/app/helpers/gantt_helper.rb b/app/helpers/gantt_helper.rb index aa743856..059a6457 100644 --- a/app/helpers/gantt_helper.rb +++ b/app/helpers/gantt_helper.rb @@ -21,20 +21,18 @@ module GanttHelper case in_or_out when :in if gantt.zoom < 4 - link_to_remote(l(:text_zoom_in), - {:url => gantt.params.merge(:zoom => (gantt.zoom+1)), :method => :get, :update => 'content'}, - {:href => url_for(gantt.params.merge(:zoom => (gantt.zoom+1))), - :class => 'icon icon-zoom-in'}) + link_to_content_update l(:text_zoom_in), + params.merge(gantt.params.merge(:zoom => (gantt.zoom+1))), + :class => 'icon icon-zoom-in' else content_tag('span', l(:text_zoom_in), :class => 'icon icon-zoom-in') end when :out if gantt.zoom > 1 - link_to_remote(l(:text_zoom_out), - {:url => gantt.params.merge(:zoom => (gantt.zoom-1)), :method => :get, :update => 'content'}, - {:href => url_for(gantt.params.merge(:zoom => (gantt.zoom-1))), - :class => 'icon icon-zoom-out'}) + link_to_content_update l(:text_zoom_out), + params.merge(gantt.params.merge(:zoom => (gantt.zoom-1))), + :class => 'icon icon-zoom-out' else content_tag('span', l(:text_zoom_out), :class => 'icon icon-zoom-out') end diff --git a/app/helpers/sort_helper.rb b/app/helpers/sort_helper.rb index c1a89db5..2dc24534 100644 --- a/app/helpers/sort_helper.rb +++ b/app/helpers/sort_helper.rb @@ -206,10 +206,7 @@ module SortHelper # Add project_id to url_options url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) - link_to_remote(caption, - {:update => "content", :url => url_options, :method => :get}, - {:href => url_for(url_options), - :class => css}) + link_to_content_update(caption, url_options, :class => css) end # Returns a table header tag with a sort link for the named column diff --git a/app/views/activities/index.html.erb b/app/views/activities/index.html.erb index 03cc8c68..a2748cc9 100644 --- a/app/views/activities/index.html.erb +++ b/app/views/activities/index.html.erb @@ -21,16 +21,14 @@ <%= content_tag('p', l(:label_no_data), :class => 'nodata') if @events_by_day.empty? %>
    -<%= link_to_remote(('« ' + l(:label_previous)), - {:update => "content", :url => params.merge(:from => @date_to - @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(params.merge(:from => @date_to - @days - 1)), - :title => l(:label_date_from_to, :start => format_date(@date_to - 2*@days), :end => format_date(@date_to - @days - 1))}) %> +<%= link_to_content_update('« ' + l(:label_previous), + params.merge(:from => @date_to - @days - 1), + :title => l(:label_date_from_to, :start => format_date(@date_to - 2*@days), :end => format_date(@date_to - @days - 1))) %>
    -<%= link_to_remote((l(:label_next) + ' »'), - {:update => "content", :url => params.merge(:from => @date_to + @days - 1), :method => :get, :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(params.merge(:from => @date_to + @days - 1)), - :title => l(:label_date_from_to, :start => format_date(@date_to), :end => format_date(@date_to + @days - 1))}) unless @date_to >= Date.today %> +<%= link_to_content_update(l(:label_next) + ' »', + params.merge(:from => @date_to + @days - 1), + :title => l(:label_date_from_to, :start => format_date(@date_to), :end => format_date(@date_to + @days - 1))) unless @date_to >= Date.today %>
      <% other_formats_links do |f| %> diff --git a/app/views/gantts/show.html.erb b/app/views/gantts/show.html.erb index 1e38647e..8007bbab 100644 --- a/app/views/gantts/show.html.erb +++ b/app/views/gantts/show.html.erb @@ -178,8 +178,8 @@ if Date.today >= @gantt.date_from and Date.today <= @gantt.date_to %> - - + +
    <%= link_to_remote ('« ' + l(:label_previous)), {:url => @gantt.params_previous, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'}, {:href => url_for(@gantt.params_previous)} %><%= link_to_remote (l(:label_next) + ' »'), {:url => @gantt.params_next, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'}, {:href => url_for(@gantt.params_next)} %><%= link_to_content_update('« ' + l(:label_previous), params.merge(@gantt.params_previous)) %><%= link_to_content_update(l(:label_next) + ' »', params.merge(@gantt.params_next)) %>
    diff --git a/app/views/search/index.rhtml b/app/views/search/index.rhtml index 348421d3..13ec567d 100644 --- a/app/views/search/index.rhtml +++ b/app/views/search/index.rhtml @@ -35,16 +35,12 @@

    <% if @pagination_previous_date %> -<%= link_to_remote ('« ' + l(:label_previous)), - {:update => :content, - :url => params.merge(:previous => 1, :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S")) - }, :href => url_for(params.merge(:previous => 1, :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S"))) %>  +<%= link_to_content_update('« ' + l(:label_previous), + params.merge(:previous => 1, :offset => @pagination_previous_date.strftime("%Y%m%d%H%M%S"))) %>  <% end %> <% if @pagination_next_date %> -<%= link_to_remote (l(:label_next) + ' »'), - {:update => :content, - :url => params.merge(:previous => nil, :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S")) - }, :href => url_for(params.merge(:previous => nil, :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S"))) %> +<%= link_to_content_update(l(:label_next) + ' »', + params.merge(:previous => nil, :offset => @pagination_next_date.strftime("%Y%m%d%H%M%S"))) %> <% end %>

    From 1335548949efcc95f539dd7444664c9eb5269cbc Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 3 Apr 2011 14:06:53 +0000 Subject: [PATCH 619/777] Changes pagination links to non-AJAX requests (#5138). git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5302 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/application_helper.rb | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 90439b7d..69d55f34 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -942,9 +942,6 @@ module ApplicationHelper end def link_to_content_update(text, url_params = {}, html_options = {}) - link_to_remote(text, - {:url => url_params, :method => :get, :update => 'content', :complete => 'window.scrollTo(0,0)'}, - {:href => url_for(:params => url_params)}.merge(html_options) - ) + link_to(text, url_params, html_options) end end From e78149f85cb886c02405b94ccd17c6c0a21ccdcc Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 3 Apr 2011 14:09:22 +0000 Subject: [PATCH 620/777] Keep issue filter params on sort headers. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5303 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/helpers/sort_helper.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/helpers/sort_helper.rb b/app/helpers/sort_helper.rb index 2dc24534..a1808a05 100644 --- a/app/helpers/sort_helper.rb +++ b/app/helpers/sort_helper.rb @@ -200,8 +200,7 @@ module SortHelper caption = column.to_s.humanize unless caption sort_options = { :sort => @sort_criteria.add(column.to_s, order).to_param } - # don't reuse params if filters are present - url_options = params.has_key?(:set_filter) ? sort_options : params.merge(sort_options) + url_options = params.merge(sort_options) # Add project_id to url_options url_options = url_options.merge(:project_id => params[:project_id]) if params.has_key?(:project_id) From 42653cef3257469cdba56c73ca554fc15dcd7644 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sun, 3 Apr 2011 14:31:32 +0000 Subject: [PATCH 621/777] Shorten query[column_names] param name. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@5304 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- app/controllers/queries_controller.rb | 5 ++++- app/helpers/queries_helper.rb | 2 +- app/views/queries/_columns.rhtml | 2 +- test/functional/issues_controller_test.rb | 2 +- test/functional/queries_controller_test.rb | 3 ++- 5 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/controllers/queries_controller.rb b/app/controllers/queries_controller.rb index e54c9bef..60f3b445 100644 --- a/app/controllers/queries_controller.rb +++ b/app/controllers/queries_controller.rb @@ -25,10 +25,11 @@ class QueriesController < ApplicationController @query.project = params[:query_is_for_all] ? nil : @project @query.user = User.current @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? - @query.column_names = nil if params[:default_columns] @query.add_filters(params[:fields] || params[:f], params[:operators] || params[:op], params[:values] || params[:v]) if params[:fields] || params[:f] @query.group_by ||= params[:group_by] + @query.column_names = params[:c] if params[:c] + @query.column_names = nil if params[:default_columns] if request.post? && params[:confirm] && @query.save flash[:notice] = l(:notice_successful_create) @@ -45,6 +46,8 @@ class QueriesController < ApplicationController @query.attributes = params[:query] @query.project = nil if params[:query_is_for_all] @query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin? + @query.group_by ||= params[:group_by] + @query.column_names = params[:c] if params[:c] @query.column_names = nil if params[:default_columns] if @query.save diff --git a/app/helpers/queries_helper.rb b/app/helpers/queries_helper.rb index b6dc697e..61a1846d 100644 --- a/app/helpers/queries_helper.rb +++ b/app/helpers/queries_helper.rb @@ -87,7 +87,7 @@ module QueriesHelper end end @query.group_by = params[:group_by] - @query.column_names = params[:query] && params[:query][:column_names] + @query.column_names = params[:c] || (params[:query] && params[:query][:column_names]) session[:query] = {:project_id => @query.project_id, :filters => @query.filters, :group_by => @query.group_by, :column_names => @query.column_names} else @query = Query.find_by_id(session[:query][:id]) if session[:query][:id] diff --git a/app/views/queries/_columns.rhtml b/app/views/queries/_columns.rhtml index 91ee627b..f96d87b0 100644 --- a/app/views/queries/_columns.rhtml +++ b/app/views/queries/_columns.rhtml @@ -10,7 +10,7 @@ - <%= select_tag 'query[column_names][]', + <%= select_tag 'c[]', options_for_select(query.columns.collect {|column| [column.caption, column.name]}), :id => 'selected_columns', :multiple => true, :size => 10, :style => "width:150px" %> diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index da25ac06..d013b59e 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -248,7 +248,7 @@ class IssuesControllerTest < ActionController::TestCase def test_index_with_columns columns = ['tracker', 'subject', 'assigned_to'] - get :index, :set_filter => 1, :query => { 'column_names' => columns} + get :index, :set_filter => 1, :c => columns assert_response :success # query should use specified columns diff --git a/test/functional/queries_controller_test.rb b/test/functional/queries_controller_test.rb index 3ef897d6..ea3a7ada 100644 --- a/test/functional/queries_controller_test.rb +++ b/test/functional/queries_controller_test.rb @@ -101,7 +101,8 @@ class QueriesControllerTest < ActionController::TestCase :fields => ["status_id", "assigned_to_id"], :operators => {"assigned_to_id" => "=", "status_id" => "o"}, :values => { "assigned_to_id" => ["me"], "status_id" => ["1"]}, - :query => {"name" => "test_new_global_private_query", "is_public" => "1", "column_names" => ["", "tracker", "subject", "priority", "category"]} + :query => {"name" => "test_new_global_private_query", "is_public" => "1"}, + :c => ["", "tracker", "subject", "priority", "category"] q = Query.find_by_name('test_new_global_private_query') assert_redirected_to :controller => 'issues', :action => 'index', :project_id => nil, :query_id => q From f06f846fcedc782637d1c9ec750c8ae34641e23e Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Sat, 16 Apr 2011 16:19:31 -0700 Subject: [PATCH 622/777] Locales update post-merge --- config/locales/bg.yml | 5 +++++ config/locales/bs.yml | 9 +++++++++ config/locales/ca.yml | 9 +++++++++ config/locales/cs.yml | 9 +++++++++ config/locales/da.yml | 9 +++++++++ config/locales/de.yml | 9 +++++++++ config/locales/el.yml | 9 +++++++++ config/locales/en-GB.yml | 2 ++ config/locales/es.yml | 9 +++++++++ config/locales/eu.yml | 9 +++++++++ config/locales/fa.yml | 16 ++++++++++++++++ config/locales/fi.yml | 9 +++++++++ config/locales/fr.yml | 1 + config/locales/gl.yml | 9 +++++++++ config/locales/he.yml | 9 +++++++++ config/locales/hr.yml | 9 +++++++++ config/locales/hu.yml | 9 +++++++++ config/locales/id.yml | 9 +++++++++ config/locales/it.yml | 9 +++++++++ config/locales/ja.yml | 3 +++ config/locales/ko.yml | 9 +++++++++ config/locales/lt.yml | 9 +++++++++ config/locales/lv.yml | 9 +++++++++ config/locales/mk.yml | 9 +++++++++ config/locales/mn.yml | 9 +++++++++ config/locales/nl.yml | 10 ++++++++++ config/locales/no.yml | 9 +++++++++ config/locales/pl.yml | 9 +++++++++ config/locales/pt-BR.yml | 9 +++++++++ config/locales/pt.yml | 9 +++++++++ config/locales/ro.yml | 9 +++++++++ config/locales/ru.yml | 9 +++++++++ config/locales/sk.yml | 9 +++++++++ config/locales/sl.yml | 9 +++++++++ config/locales/sr-YU.yml | 9 +++++++++ config/locales/sr.yml | 9 +++++++++ config/locales/sv.yml | 6 ++++++ config/locales/th.yml | 9 +++++++++ config/locales/tr.yml | 9 +++++++++ config/locales/uk.yml | 9 +++++++++ config/locales/vi.yml | 9 +++++++++ config/locales/zh-TW.yml | 6 ++++++ config/locales/zh.yml | 9 +++++++++ 43 files changed, 364 insertions(+) diff --git a/config/locales/bg.yml b/config/locales/bg.yml index e36d07fc..a836fd71 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -950,3 +950,8 @@ bg: label_cvs_path: CVSROOT label_git_path: Path to .git directory label_mercurial_path: Root directory + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date diff --git a/config/locales/bs.yml b/config/locales/bs.yml index 04d4c99f..ba4ff7e6 100644 --- a/config/locales/bs.yml +++ b/config/locales/bs.yml @@ -960,3 +960,12 @@ bs: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 62e69ace..475a64d7 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -949,3 +949,12 @@ ca: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 0b3110a0..ca50d4a8 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -1170,3 +1170,12 @@ cs: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/da.yml b/config/locales/da.yml index fad0592f..bc86533e 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -962,3 +962,12 @@ da: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/de.yml b/config/locales/de.yml index d62eb2ce..5567b6fe 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -963,3 +963,12 @@ de: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/el.yml b/config/locales/el.yml index 98f7dae3..4b5d6ffa 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -946,3 +946,12 @@ el: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 8255a61a..5d5ca653 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -957,3 +957,5 @@ en-GB: label_cvs_path: CVSROOT label_git_path: Path to .git directory label_mercurial_path: Root directory + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author diff --git a/config/locales/es.yml b/config/locales/es.yml index b6b6ed92..6ad49263 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -983,3 +983,12 @@ es: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 425a6070..3a5085c2 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -950,3 +950,12 @@ eu: notice_gantt_chart_truncated: Grafikoa moztu da bistara daitekeen elementuen kopuru maximoa gainditu delako (%{max}) setting_gantt_items_limit: "Gantt grafikoan bistara daitekeen elementu kopuru maximoa" label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 03186b77..19bcdb78 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -942,3 +942,19 @@ fa: text_tip_issue_end_day: issue ending this day text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. label_my_queries: My custom queries + label_cvs_module: Module + label_filesystem_path: Root directory + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_darcs_path: Root directory + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_news_comment_added: Comment added to a news + label_bazaar_path: Root directory + label_cvs_path: CVSROOT + label_git_path: Path to .git directory + default_role_anonymous: Anonymous + text_powered_by: Powered by %{link} + default_role_non_member: Non member + label_mercurial_path: Root directory diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 948aaae2..d2bf6b3c 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -967,3 +967,12 @@ fi: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/fr.yml b/config/locales/fr.yml index e038fc74..f21fcc2f 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -972,3 +972,4 @@ fr: label_cvs_path: CVSROOT label_git_path: Path to .git directory label_mercurial_path: Root directory + field_effective_date: Due date diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 6e98cb7f..8f6b9bb4 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -958,3 +958,12 @@ gl: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/he.yml b/config/locales/he.yml index 767d4754..e45a7e0a 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -951,3 +951,12 @@ he: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 93ae02af..4e086faa 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -953,3 +953,12 @@ hr: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/hu.yml b/config/locales/hu.yml index 9f124a6d..c951c5da 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -965,3 +965,12 @@ label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/id.yml b/config/locales/id.yml index ba2d27e3..747ced09 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -954,3 +954,12 @@ id: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/it.yml b/config/locales/it.yml index 45e693e9..7d66fa0e 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -947,3 +947,12 @@ it: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 66013b3c..b05c5164 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -974,3 +974,6 @@ ja: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date diff --git a/config/locales/ko.yml b/config/locales/ko.yml index bd6a96cf..3f2401f4 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -998,3 +998,12 @@ ko: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/lt.yml b/config/locales/lt.yml index bea93e63..d310fb7b 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -1006,3 +1006,12 @@ lt: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 51e95ea0..0640637e 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -941,3 +941,12 @@ lv: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/mk.yml b/config/locales/mk.yml index 970608a8..e46c7c88 100644 --- a/config/locales/mk.yml +++ b/config/locales/mk.yml @@ -946,3 +946,12 @@ mk: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/mn.yml b/config/locales/mn.yml index 08dd597e..31004e0c 100644 --- a/config/locales/mn.yml +++ b/config/locales/mn.yml @@ -947,3 +947,12 @@ mn: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/nl.yml b/config/locales/nl.yml index ea7332ec..9f215c3e 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -927,3 +927,13 @@ nl: button_collapse_all: Collapse all label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_cvs_module: Module + label_filesystem_path: Root directory + label_darcs_path: Root directory + text_journal_changed_no_detail: "%{label} updated" + field_effective_date: Due date + label_bazaar_path: Root directory + label_cvs_path: CVSROOT + label_git_path: Path to .git directory + text_powered_by: Powered by %{link} + label_mercurial_path: Root directory diff --git a/config/locales/no.yml b/config/locales/no.yml index 79a2a609..73c42c61 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -933,3 +933,12 @@ label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 66f35161..31724818 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -963,3 +963,12 @@ pl: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index d11f3cd0..aa438e75 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -969,3 +969,12 @@ pt-BR: button_collapse_all: Collapse all label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + label_cvs_module: Module + label_filesystem_path: Root directory + label_darcs_path: Root directory + field_effective_date: Due date + label_bazaar_path: Root directory + label_cvs_path: CVSROOT + label_git_path: Path to .git directory + text_powered_by: Powered by %{link} + label_mercurial_path: Root directory diff --git a/config/locales/pt.yml b/config/locales/pt.yml index fbc0c365..787a3a94 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -950,3 +950,12 @@ pt: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/ro.yml b/config/locales/ro.yml index 343d8c1d..874e4e30 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -939,3 +939,12 @@ ro: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 63bcb4e2..46f75303 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -1059,3 +1059,12 @@ ru: label_git_path: Путь к каталогу .git label_mercurial_path: Каталог label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/sk.yml b/config/locales/sk.yml index a7430f76..f50585d3 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -941,3 +941,12 @@ sk: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 9ab3c8c2..7003abef 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -942,3 +942,12 @@ sl: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/sr-YU.yml b/config/locales/sr-YU.yml index 1f4674ab..b0e13450 100644 --- a/config/locales/sr-YU.yml +++ b/config/locales/sr-YU.yml @@ -946,3 +946,12 @@ sr-YU: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 1118f3a1..14dbfaef 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -947,3 +947,12 @@ sr: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 26f0b892..a65a54e3 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -991,3 +991,9 @@ sv: label_git_path: Path to .git directory label_mercurial_path: Root directory + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news diff --git a/config/locales/th.yml b/config/locales/th.yml index 78ed93a6..2362f715 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -943,3 +943,12 @@ th: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/tr.yml b/config/locales/tr.yml index b066ff20..a56bc229 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -965,3 +965,12 @@ tr: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/uk.yml b/config/locales/uk.yml index ed100385..83e0e2d9 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -942,3 +942,12 @@ uk: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 48be079c..354ea263 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -997,3 +997,12 @@ vi: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 10f910ed..664db7ea 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -1031,3 +1031,9 @@ label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 2473eac1..4b2b4004 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -960,3 +960,12 @@ zh: label_git_path: Path to .git directory label_mercurial_path: Root directory label_my_queries: My custom queries + label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee + text_journal_changed_no_detail: "%{label} updated" + button_expand_all: Expand all + button_collapse_all: Collapse all + label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + field_effective_date: Due date + label_news_comment_added: Comment added to a news + field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text + text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. From ff431e8ed46b760aa3cd8e1c6bafb42fd9cad990 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Wed, 20 Apr 2011 23:49:21 +0200 Subject: [PATCH 623/777] Force changeset journal creation. --- test/unit/repository_git_test.rb | 2 +- test/unit/repository_mercurial_test.rb | 2 +- test/unit/repository_subversion_test.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/repository_git_test.rb b/test/unit/repository_git_test.rb index f6f3f6ed..87c0ac6e 100644 --- a/test/unit/repository_git_test.rb +++ b/test/unit/repository_git_test.rb @@ -95,7 +95,7 @@ class RepositoryGitTest < ActiveSupport::TestCase end def test_activities - c = Changeset.new(:repository => @repository, + c = Changeset.create(:repository => @repository, :committed_on => Time.now, :revision => 'abc7234cb2750b63f47bff735edc50a1c0a433c2', :scmid => 'abc7234cb2750b63f47bff735edc50a1c0a433c2', diff --git a/test/unit/repository_mercurial_test.rb b/test/unit/repository_mercurial_test.rb index 7523cfe9..e842e7d6 100644 --- a/test/unit/repository_mercurial_test.rb +++ b/test/unit/repository_mercurial_test.rb @@ -163,7 +163,7 @@ class RepositoryMercurialTest < ActiveSupport::TestCase end def test_activities - c = Changeset.new(:repository => @repository, + c = Changeset.create(:repository => @repository, :committed_on => Time.now, :revision => '123', :scmid => 'abc400bb8672', diff --git a/test/unit/repository_subversion_test.rb b/test/unit/repository_subversion_test.rb index fd761823..35247f3a 100644 --- a/test/unit/repository_subversion_test.rb +++ b/test/unit/repository_subversion_test.rb @@ -124,14 +124,14 @@ class RepositorySubversionTest < ActiveSupport::TestCase end def test_activities - c = Changeset.new(:repository => @repository, :committed_on => Time.now, + c = Changeset.create(:repository => @repository, :committed_on => Time.now, :revision => '1', :comments => 'test') assert c.event_title.include?('1:') assert_equal '1', c.event_url[:rev] end def test_activities_nine_digit - c = Changeset.new(:repository => @repository, :committed_on => Time.now, + c = Changeset.create(:repository => @repository, :committed_on => Time.now, :revision => '123456789', :comments => 'test') assert c.event_title.include?('123456789:') assert_equal '123456789', c.event_url[:rev] From 43ee27715a58700f47757a2a927722bed394fc54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Scha=CC=88fer?= Date: Wed, 20 Apr 2011 23:49:44 +0200 Subject: [PATCH 624/777] JournalDetails don't exist anymore. --- test/unit/issue_nested_set_test.rb | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/test/unit/issue_nested_set_test.rb b/test/unit/issue_nested_set_test.rb index cf61cfde..b2206404 100644 --- a/test/unit/issue_nested_set_test.rb +++ b/test/unit/issue_nested_set_test.rb @@ -208,10 +208,8 @@ class IssueNestedSetTest < ActiveSupport::TestCase issue3.save! assert_difference 'Issue.count', -2 do - assert_difference 'Journal.count', -1 do - assert_difference 'JournalDetail.count', -1 do - Issue.find(issue2.id).destroy - end + assert_difference 'Journal.count', -3 do + Issue.find(issue2.id).destroy end end @@ -232,10 +230,8 @@ class IssueNestedSetTest < ActiveSupport::TestCase leaf.save! assert_difference 'Issue.count', -2 do - assert_difference 'Journal.count', -1 do - assert_difference 'JournalDetail.count', -1 do - Issue.find(child.id).destroy - end + assert_difference 'Journal.count', -3 do + Issue.find(child.id).destroy end end From 1eee7312f60267b0f8e575cc96302812f2dc38a8 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 20 Apr 2011 16:08:00 -0700 Subject: [PATCH 625/777] [#289] Remove single helpers in favor of :all in ApplicationController --- app/controllers/account_controller.rb | 1 - app/controllers/admin_controller.rb | 1 - app/controllers/application_controller.rb | 1 + app/controllers/boards_controller.rb | 3 --- app/controllers/calendars_controller.rb | 4 ---- app/controllers/context_menus_controller.rb | 1 - app/controllers/documents_controller.rb | 1 - app/controllers/enumerations_controller.rb | 1 - app/controllers/files_controller.rb | 1 - app/controllers/gantts_controller.rb | 5 ----- app/controllers/groups_controller.rb | 1 - app/controllers/issues_controller.rb | 11 ----------- app/controllers/journals_controller.rb | 5 ----- app/controllers/messages_controller.rb | 2 -- app/controllers/my_controller.rb | 3 --- app/controllers/news_controller.rb | 1 - app/controllers/projects_controller.rb | 5 ----- app/controllers/search_controller.rb | 1 - app/controllers/time_entry_reports_controller.rb | 4 ---- app/controllers/timelog_controller.rb | 3 --- app/controllers/users_controller.rb | 2 -- app/controllers/versions_controller.rb | 2 -- app/controllers/wiki_controller.rb | 2 -- 23 files changed, 1 insertion(+), 60 deletions(-) diff --git a/app/controllers/account_controller.rb b/app/controllers/account_controller.rb index 5d6f890f..024f7534 100644 --- a/app/controllers/account_controller.rb +++ b/app/controllers/account_controller.rb @@ -16,7 +16,6 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class AccountController < ApplicationController - helper :custom_fields include CustomFieldsHelper # prevents login action to be filtered by check_if_login_required application scope filter diff --git a/app/controllers/admin_controller.rb b/app/controllers/admin_controller.rb index 2dc3ab1c..7d97a1bd 100644 --- a/app/controllers/admin_controller.rb +++ b/app/controllers/admin_controller.rb @@ -20,7 +20,6 @@ class AdminController < ApplicationController before_filter :require_admin - helper :sort include SortHelper def index diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 10c7b653..139d7cf8 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -19,6 +19,7 @@ require 'uri' require 'cgi' class ApplicationController < ActionController::Base + helper :all protected diff --git a/app/controllers/boards_controller.rb b/app/controllers/boards_controller.rb index ebad847d..98497a59 100644 --- a/app/controllers/boards_controller.rb +++ b/app/controllers/boards_controller.rb @@ -20,11 +20,8 @@ class BoardsController < ApplicationController before_filter :find_project, :find_board_if_available, :authorize accept_key_auth :index, :show - helper :messages include MessagesHelper - helper :sort include SortHelper - helper :watchers include WatchersHelper def index diff --git a/app/controllers/calendars_controller.rb b/app/controllers/calendars_controller.rb index 4544b339..c228099c 100644 --- a/app/controllers/calendars_controller.rb +++ b/app/controllers/calendars_controller.rb @@ -4,11 +4,7 @@ class CalendarsController < ApplicationController rescue_from Query::StatementInvalid, :with => :query_statement_invalid - helper :issues - helper :projects - helper :queries include QueriesHelper - helper :sort include SortHelper def show diff --git a/app/controllers/context_menus_controller.rb b/app/controllers/context_menus_controller.rb index 373938ab..5cdf2b0a 100644 --- a/app/controllers/context_menus_controller.rb +++ b/app/controllers/context_menus_controller.rb @@ -1,5 +1,4 @@ class ContextMenusController < ApplicationController - helper :watchers def issues @issues = Issue.visible.all(:conditions => {:id => params[:ids]}, :include => :project) diff --git a/app/controllers/documents_controller.rb b/app/controllers/documents_controller.rb index 118a7d99..1db5d756 100644 --- a/app/controllers/documents_controller.rb +++ b/app/controllers/documents_controller.rb @@ -23,7 +23,6 @@ class DocumentsController < ApplicationController before_filter :find_project_from_association, :except => [:index, :new] before_filter :authorize - helper :attachments def index @sort_by = %w(category date title author).include?(params[:sort_by]) ? params[:sort_by] : 'category' diff --git a/app/controllers/enumerations_controller.rb b/app/controllers/enumerations_controller.rb index e5b50c87..2b9be4c4 100644 --- a/app/controllers/enumerations_controller.rb +++ b/app/controllers/enumerations_controller.rb @@ -20,7 +20,6 @@ class EnumerationsController < ApplicationController before_filter :require_admin - helper :custom_fields include CustomFieldsHelper def index diff --git a/app/controllers/files_controller.rb b/app/controllers/files_controller.rb index d7234985..39bc9be5 100644 --- a/app/controllers/files_controller.rb +++ b/app/controllers/files_controller.rb @@ -4,7 +4,6 @@ class FilesController < ApplicationController before_filter :find_project_by_project_id before_filter :authorize - helper :sort include SortHelper def index diff --git a/app/controllers/gantts_controller.rb b/app/controllers/gantts_controller.rb index 50fd8c13..c33f89f7 100644 --- a/app/controllers/gantts_controller.rb +++ b/app/controllers/gantts_controller.rb @@ -4,12 +4,7 @@ class GanttsController < ApplicationController rescue_from Query::StatementInvalid, :with => :query_statement_invalid - helper :gantt - helper :issues - helper :projects - helper :queries include QueriesHelper - helper :sort include SortHelper include Redmine::Export::PDF diff --git a/app/controllers/groups_controller.rb b/app/controllers/groups_controller.rb index db56eff9..4667dc9c 100644 --- a/app/controllers/groups_controller.rb +++ b/app/controllers/groups_controller.rb @@ -20,7 +20,6 @@ class GroupsController < ApplicationController before_filter :require_admin - helper :custom_fields # GET /groups # GET /groups.xml diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index fdce296c..adbf0c36 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -31,26 +31,15 @@ class IssuesController < ApplicationController rescue_from Query::StatementInvalid, :with => :query_statement_invalid - helper :journals - helper :projects include ProjectsHelper - helper :custom_fields include CustomFieldsHelper - helper :issue_relations include IssueRelationsHelper - helper :watchers include WatchersHelper - helper :attachments include AttachmentsHelper - helper :queries include QueriesHelper - helper :repositories include RepositoriesHelper - helper :sort include SortHelper include IssuesHelper - helper :timelog - helper :gantt include Redmine::Export::PDF verify :method => [:post, :delete], diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb index ac3cbb67..00e5e240 100644 --- a/app/controllers/journals_controller.rb +++ b/app/controllers/journals_controller.rb @@ -23,13 +23,8 @@ class JournalsController < ApplicationController accept_key_auth :index menu_item :issues - helper :issues - helper :custom_fields - helper :queries include QueriesHelper - helper :sort include SortHelper - helper :custom_fields def index retrieve_query diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb index 5ad8ea58..56c99ebf 100644 --- a/app/controllers/messages_controller.rb +++ b/app/controllers/messages_controller.rb @@ -25,8 +25,6 @@ class MessagesController < ApplicationController verify :method => :post, :only => [ :reply, :destroy ], :redirect_to => { :action => :show } verify :xhr => true, :only => :quote - helper :watchers - helper :attachments include AttachmentsHelper REPLIES_PER_PAGE = 25 unless const_defined?(:REPLIES_PER_PAGE) diff --git a/app/controllers/my_controller.rb b/app/controllers/my_controller.rb index b381fbc8..07570c13 100644 --- a/app/controllers/my_controller.rb +++ b/app/controllers/my_controller.rb @@ -18,9 +18,6 @@ class MyController < ApplicationController before_filter :require_login - helper :issues - helper :users - helper :custom_fields BLOCKS = { 'issuesassignedtome' => :label_assigned_to_me_issues, 'issuesreportedbyme' => :label_reported_issues, diff --git a/app/controllers/news_controller.rb b/app/controllers/news_controller.rb index bc7eabb5..87965a7d 100644 --- a/app/controllers/news_controller.rb +++ b/app/controllers/news_controller.rb @@ -25,7 +25,6 @@ class NewsController < ApplicationController before_filter :find_optional_project, :only => :index accept_key_auth :index - helper :watchers def index case params[:format] diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index ea2ddd13..bedb1ac3 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -32,14 +32,9 @@ class ProjectsController < ApplicationController end end - helper :sort include SortHelper - helper :custom_fields include CustomFieldsHelper - helper :issues - helper :queries include QueriesHelper - helper :repositories include RepositoriesHelper include ProjectsHelper diff --git a/app/controllers/search_controller.rb b/app/controllers/search_controller.rb index f2e146b2..409a430d 100644 --- a/app/controllers/search_controller.rb +++ b/app/controllers/search_controller.rb @@ -18,7 +18,6 @@ class SearchController < ApplicationController before_filter :find_optional_project - helper :messages include MessagesHelper def index diff --git a/app/controllers/time_entry_reports_controller.rb b/app/controllers/time_entry_reports_controller.rb index dd02ff8f..a44254bd 100644 --- a/app/controllers/time_entry_reports_controller.rb +++ b/app/controllers/time_entry_reports_controller.rb @@ -3,12 +3,8 @@ class TimeEntryReportsController < ApplicationController before_filter :find_optional_project before_filter :load_available_criterias - helper :sort include SortHelper - helper :issues - helper :timelog include TimelogHelper - helper :custom_fields include CustomFieldsHelper def report diff --git a/app/controllers/timelog_controller.rb b/app/controllers/timelog_controller.rb index 604a8f24..50c68929 100644 --- a/app/controllers/timelog_controller.rb +++ b/app/controllers/timelog_controller.rb @@ -23,11 +23,8 @@ class TimelogController < ApplicationController before_filter :find_optional_project, :only => [:index] accept_key_auth :index, :show, :create, :update, :destroy - helper :sort include SortHelper - helper :issues include TimelogHelper - helper :custom_fields include CustomFieldsHelper def index diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index c0ab99a3..c3955166 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -22,9 +22,7 @@ class UsersController < ApplicationController before_filter :find_user, :only => [:show, :edit, :update, :edit_membership, :destroy_membership] accept_key_auth :index, :show, :create, :update - helper :sort include SortHelper - helper :custom_fields include CustomFieldsHelper def index diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb index 03af71b9..97e73296 100644 --- a/app/controllers/versions_controller.rb +++ b/app/controllers/versions_controller.rb @@ -23,8 +23,6 @@ class VersionsController < ApplicationController before_filter :find_project, :only => [:index, :new, :create, :close_completed] before_filter :authorize - helper :custom_fields - helper :projects def index @trackers = @project.trackers.find(:all, :order => 'position') diff --git a/app/controllers/wiki_controller.rb b/app/controllers/wiki_controller.rb index 5b87f902..6ad8639f 100644 --- a/app/controllers/wiki_controller.rb +++ b/app/controllers/wiki_controller.rb @@ -38,9 +38,7 @@ class WikiController < ApplicationController verify :method => :post, :only => [:protect], :redirect_to => { :action => :show } - helper :attachments include AttachmentsHelper - helper :watchers # List of pages, sorted alphabetically and by parent (hierarchy) def index From 9ca203beaef16189ee949c3b9a4a0b2958e53194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Thu, 21 Apr 2011 11:44:16 +0200 Subject: [PATCH 626/777] Update to latest version of acts_as_journalized. --- vendor/plugins/acts_as_journalized | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/plugins/acts_as_journalized b/vendor/plugins/acts_as_journalized index 6683304d..0b242548 160000 --- a/vendor/plugins/acts_as_journalized +++ b/vendor/plugins/acts_as_journalized @@ -1 +1 @@ -Subproject commit 6683304d3cca187795b344f0b831edbc7cf709c0 +Subproject commit 0b242548a3b45b6ef5b26ab225bf23b7b7f8e490 From d4adcae569cf44c085ef68f8d98ac4b0fbfd5838 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Thu, 21 Apr 2011 11:44:55 +0200 Subject: [PATCH 627/777] Update the Issue#show.api to new journals type --- app/views/issues/show.api.rsb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/views/issues/show.api.rsb b/app/views/issues/show.api.rsb index 170aeb37..40de41fb 100644 --- a/app/views/issues/show.api.rsb +++ b/app/views/issues/show.api.rsb @@ -49,9 +49,9 @@ api.issue do api.created_on journal.created_on api.array :details do journal.details.each do |detail| - api.detail :property => detail.property, :name => detail.prop_key do - api.old_value detail.old_value - api.new_value detail.value + api.detail :property => journal.property(detail), :name => journal.prop_key(detail) do + api.old_value journal.old_value(detail) + api.new_value journal.value(detail) end end end From ef8141a2c1ee6af562c3c727bd0f5378227acd2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Thu, 21 Apr 2011 11:45:31 +0200 Subject: [PATCH 628/777] Remove deprecated journals tests and controller. --- app/controllers/journals_controller.rb | 98 --------------------- test/functional/journals_controller_test.rb | 27 ------ 2 files changed, 125 deletions(-) delete mode 100644 app/controllers/journals_controller.rb diff --git a/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb deleted file mode 100644 index 1f65dc82..00000000 --- a/app/controllers/journals_controller.rb +++ /dev/null @@ -1,98 +0,0 @@ -# redMine - project management software -# Copyright (C) 2006-2008 Jean-Philippe Lang -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -class JournalsController < ApplicationController - before_filter :find_journal, :only => [:edit] - before_filter :find_issue, :only => [:new] - before_filter :find_optional_project, :only => [:index] - before_filter :authorize, :only => [:new, :edit] - accept_key_auth :index - - helper :issues - helper :queries - include QueriesHelper - helper :sort - include SortHelper - helper :custom_fields - - def index - retrieve_query - sort_init 'id', 'desc' - sort_update(@query.sortable_columns) - - if @query.valid? - @journals = @query.journals(:order => "#{Journal.table_name}.created_on DESC", - :limit => 25) - end - @title = (@project ? @project.name : Setting.app_title) + ": " + (@query.new_record? ? l(:label_changes_details) : @query.name) - render :layout => false, :content_type => 'application/atom+xml' - rescue ActiveRecord::RecordNotFound - render_404 - end - - def new - journal = Journal.find(params[:journal_id]) if params[:journal_id] - if journal - user = journal.user - text = journal.notes - else - user = @issue.author - text = @issue.description - end - # Replaces pre blocks with [...] - text = text.to_s.strip.gsub(%r{
    ((.|\s)*?)
    }m, '[...]') - content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " - content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" - - render(:update) { |page| - page.<< "$('notes').value = \"#{escape_javascript content}\";" - page.show 'update' - page << "Form.Element.focus('notes');" - page << "Element.scrollTo('update');" - page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" - } - end - - def edit - if request.post? - @journal.update_attributes(:notes => params[:notes]) if params[:notes] - @journal.destroy if @journal.details.empty? && @journal.notes.blank? - call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params}) - respond_to do |format| - format.html { redirect_to :controller => 'issues', :action => 'show', :id => @journal.journalized_id } - format.js { render :action => 'update' } - end - end - end - -private - def find_journal - @journal = Journal.find(params[:id]) - (render_403; return false) unless @journal.editable_by?(User.current) - @project = @journal.journalized.project - rescue ActiveRecord::RecordNotFound - render_404 - end - - # TODO: duplicated in IssuesController - def find_issue - @issue = Issue.find(params[:id], :include => [:project, :tracker, :status, :author, :priority, :category]) - @project = @issue.project - rescue ActiveRecord::RecordNotFound - render_404 - end -end diff --git a/test/functional/journals_controller_test.rb b/test/functional/journals_controller_test.rb index 52aa8f9e..cc61c80a 100644 --- a/test/functional/journals_controller_test.rb +++ b/test/functional/journals_controller_test.rb @@ -31,33 +31,6 @@ class JournalsControllerTest < ActionController::TestCase User.current = nil end - def test_index - get :index, :project_id => 1 - assert_response :success - assert_not_nil assigns(:journals) - assert_equal 'application/atom+xml', @response.content_type - end - - def test_reply_to_issue - @request.session[:user_id] = 2 - get :new, :id => 6 - assert_response :success - assert_select_rjs :show, "update" - end - - def test_reply_to_issue_without_permission - @request.session[:user_id] = 7 - get :new, :id => 6 - assert_response 403 - end - - def test_reply_to_note - @request.session[:user_id] = 2 - get :new, :id => 6, :journal_id => 4 - assert_response :success - assert_select_rjs :show, "update" - end - def test_get_edit @request.session[:user_id] = 1 xhr :get, :edit, :id => 2 From 61f0e67c0d976c98d8750fa476977b377315d4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Sch=C3=A4fer?= Date: Thu, 21 Apr 2011 11:46:00 +0200 Subject: [PATCH 629/777] Upgrade tests to new journals type. --- test/functional/wiki_controller_test.rb | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/test/functional/wiki_controller_test.rb b/test/functional/wiki_controller_test.rb index 9bacd6e0..976f402b 100644 --- a/test/functional/wiki_controller_test.rb +++ b/test/functional/wiki_controller_test.rb @@ -112,13 +112,13 @@ class WikiControllerTest < ActionController::TestCase @request.session[:user_id] = 2 assert_no_difference 'WikiPage.count' do assert_no_difference 'WikiContent.count' do - assert_difference 'WikiContent::Version.count' do + assert_difference 'WikiContentJournal.count' do put :update, :project_id => 1, :id => 'Another_page', :content => { :comments => "my comments", :text => "edited", - :version => 1 + :lock_version => 1 } end end @@ -135,13 +135,13 @@ class WikiControllerTest < ActionController::TestCase @request.session[:user_id] = 2 assert_no_difference 'WikiPage.count' do assert_no_difference 'WikiContent.count' do - assert_no_difference 'WikiContent::Version.count' do + assert_no_difference 'WikiContentJournal.count' do put :update, :project_id => 1, :id => 'Another_page', :content => { :comments => 'a' * 300, # failure here, comment is too long :text => 'edited', - :version => 1 + :lock_version => 1 } end end @@ -151,7 +151,7 @@ class WikiControllerTest < ActionController::TestCase assert_error_tag :descendant => {:content => /Comment is too long/} assert_tag :tag => 'textarea', :attributes => {:id => 'content_text'}, :content => 'edited' - assert_tag :tag => 'input', :attributes => {:id => 'content_version', :value => '1'} + assert_tag :tag => 'input', :attributes => {:id => 'content_lock_version', :value => '1'} end def test_preview @@ -159,7 +159,7 @@ class WikiControllerTest < ActionController::TestCase xhr :post, :preview, :project_id => 1, :id => 'CookBook_documentation', :content => { :comments => '', :text => 'this is a *previewed text*', - :version => 3 } + :lock_version => 3 } assert_response :success assert_template 'common/_preview' assert_tag :tag => 'strong', :content => /previewed text/ @@ -170,7 +170,7 @@ class WikiControllerTest < ActionController::TestCase xhr :post, :preview, :project_id => 1, :id => 'New page', :content => { :text => 'h1. New page', :comments => '', - :version => 0 } + :lock_version => 0 } assert_response :success assert_template 'common/_preview' assert_tag :tag => 'h1', :content => /New page/ From 3b7ea67a9963034fa23613f7f84c681e281e6c98 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Thu, 21 Apr 2011 11:47:32 +0200 Subject: [PATCH 630/777] [#346] changing i18n files to use valid yaml syntax that may be parsed by psych --- config/locales/bg.yml | 5 ++++- config/locales/bs.yml | 5 ++++- config/locales/ca.yml | 5 ++++- config/locales/cs.yml | 5 ++++- config/locales/da.yml | 5 ++++- config/locales/de.yml | 5 ++++- config/locales/el.yml | 5 ++++- config/locales/en-GB.yml | 5 ++++- config/locales/en.yml | 5 ++++- config/locales/es.yml | 5 ++++- config/locales/eu.yml | 5 ++++- config/locales/fa.yml | 5 ++++- config/locales/fi.yml | 5 ++++- config/locales/fr.yml | 5 ++++- config/locales/gl.yml | 5 ++++- config/locales/he.yml | 5 ++++- config/locales/hr.yml | 5 ++++- config/locales/hu.yml | 5 ++++- config/locales/id.yml | 5 ++++- config/locales/it.yml | 5 ++++- config/locales/ja.yml | 5 ++++- config/locales/ko.yml | 5 ++++- config/locales/lt.yml | 5 ++++- config/locales/lv.yml | 5 ++++- config/locales/mk.yml | 5 ++++- config/locales/mn.yml | 5 ++++- config/locales/nl.yml | 5 ++++- config/locales/no.yml | 5 ++++- config/locales/pl.yml | 5 ++++- config/locales/pt-BR.yml | 5 ++++- config/locales/pt.yml | 5 ++++- config/locales/ro.yml | 5 ++++- config/locales/ru.yml | 5 ++++- config/locales/sk.yml | 5 ++++- config/locales/sl.yml | 5 ++++- config/locales/sr-YU.yml | 5 ++++- config/locales/sr.yml | 5 ++++- config/locales/sv.yml | 5 ++++- config/locales/th.yml | 5 ++++- config/locales/tr.yml | 5 ++++- config/locales/uk.yml | 5 ++++- config/locales/vi.yml | 5 ++++- config/locales/zh-TW.yml | 5 ++++- config/locales/zh.yml | 5 ++++- 44 files changed, 176 insertions(+), 44 deletions(-) diff --git a/config/locales/bg.yml b/config/locales/bg.yml index a836fd71..28c690c1 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -17,7 +17,10 @@ bg: month_names: [~, Януари, Февруари, Март, Април, Май, Юни, Юли, Август, Септември, Октомври, Ноември, Декември] abbr_month_names: [~, Яну, Фев, Мар, Апр, Май, Юни, Юли, Авг, Сеп, Окт, Ное, Дек] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/bs.yml b/config/locales/bs.yml index ba4ff7e6..8c1c5a85 100644 --- a/config/locales/bs.yml +++ b/config/locales/bs.yml @@ -15,7 +15,10 @@ bs: month_names: [~, Januar, Februar, Mart, April, Maj, Jun, Jul, Avgust, Septembar, Oktobar, Novembar, Decembar] abbr_month_names: [~, Jan, Feb, Mar, Apr, Maj, Jun, Jul, Avg, Sep, Okt, Nov, Dec] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 475a64d7..160d934e 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -20,7 +20,10 @@ ca: month_names: [~, Gener, Febrer, Març, Abril, Maig, Juny, Juliol, Agost, Setembre, Octubre, Novembre, Desembre] abbr_month_names: [~, Gen, Feb, Mar, Abr, Mai, Jun, Jul, Ago, Set, Oct, Nov, Des] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/cs.yml b/config/locales/cs.yml index ca50d4a8..4a7df4d5 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -21,7 +21,10 @@ cs: month_names: [~, Leden, Únor, Březen, Duben, Květen, Červen, Červenec, Srpen, Září, Říjen, Listopad, Prosinec] abbr_month_names: [~, Led, Úno, Bře, Dub, Kvě, Čer, Čec, Srp, Zář, Říj, Lis, Pro] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/da.yml b/config/locales/da.yml index bc86533e..e3918fb6 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -14,7 +14,10 @@ da: abbr_day_names: [sø, ma, ti, 'on', to, fr, lø] month_names: [~, januar, februar, marts, april, maj, juni, juli, august, september, oktober, november, december] abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, aug, sep, okt, nov, dec] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/de.yml b/config/locales/de.yml index 5567b6fe..d27cfcb9 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -19,7 +19,10 @@ de: month_names: [~, Januar, Februar, März, April, Mai, Juni, Juli, August, September, Oktober, November, Dezember] abbr_month_names: [~, Jan, Feb, Mär, Apr, Mai, Jun, Jul, Aug, Sep, Okt, Nov, Dez] # Used in date_select and datime_select. - order: [:day, :month, :year] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/el.yml b/config/locales/el.yml index 4b5d6ffa..d6bbc514 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -19,7 +19,10 @@ el: month_names: [~, Ιανουάριος, Φεβρουάριος, Μάρτιος, Απρίλιος, Μάϊος, Ιούνιος, Ιούλιος, Αύγουστος, Σεπτέμβριος, Οκτώβριος, Νοέμβριος, Δεκέμβριος] abbr_month_names: [~, Ιαν, Φεβ, Μαρ, Απρ, Μαϊ, Ιον, Ιολ, Αυγ, Σεπ, Οκτ, Νοε, Δεκ] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 5d5ca653..624ee1ea 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -16,7 +16,10 @@ en-GB: month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/en.yml b/config/locales/en.yml index 5ddc0b71..2249b380 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -17,7 +17,10 @@ en: month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/es.yml b/config/locales/es.yml index 6ad49263..11dfccef 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -159,7 +159,10 @@ es: month_names: [~, Enero, Febrero, Marzo, Abril, Mayo, Junio, Julio, Agosto, Setiembre, Octubre, Noviembre, Diciembre] abbr_month_names: [~, Ene, Feb, Mar, Abr, May, Jun, Jul, Ago, Set, Oct, Nov, Dic] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/eu.yml b/config/locales/eu.yml index 3a5085c2..c16e6e19 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -20,7 +20,10 @@ eu: month_names: [~, Urtarrila, Otsaila, Martxoa, Apirila, Maiatza, Ekaina, Uztaila, Abuztua, Iraila, Urria, Azaroa, Abendua] abbr_month_names: [~, Urt, Ots, Mar, Api, Mai, Eka, Uzt, Abu, Ira, Urr, Aza, Abe] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/fa.yml b/config/locales/fa.yml index 19bcdb78..a8e8a37c 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -17,7 +17,10 @@ fa: month_names: [~, ژانویه, فوریه, مارس, آوریل, مه, ژوئن, ژوئیه, اوت, سپتامبر, اکتبر, نوامبر, دسامبر] abbr_month_names: [~, ژان, فور, مار, آور, مه, ژوئن, ژوئیه, اوت, سپت, اکت, نوا, دسا] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/fi.yml b/config/locales/fi.yml index d2bf6b3c..5536cfcc 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -13,7 +13,10 @@ fi: abbr_day_names: [Su, Ma, Ti, Ke, To, Pe, La] month_names: [~, Tammikuu, Helmikuu, Maaliskuu, Huhtikuu, Toukokuu, Kesäkuu, Heinäkuu, Elokuu, Syyskuu, Lokakuu, Marraskuu, Joulukuu] abbr_month_names: [~, Tammi, Helmi, Maalis, Huhti, Touko, Kesä, Heinä, Elo, Syys, Loka, Marras, Joulu] - order: [:day, :month, :year] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index f21fcc2f..00db9885 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -17,7 +17,10 @@ fr: abbr_day_names: [dim, lun, mar, mer, jeu, ven, sam] month_names: [~, janvier, février, mars, avril, mai, juin, juillet, août, septembre, octobre, novembre, décembre] abbr_month_names: [~, jan., fév., mar., avr., mai, juin, juil., août, sept., oct., nov., déc.] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 8f6b9bb4..6df570ef 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -55,7 +55,10 @@ gl: abbr_day_names: [Dom, Lun, Mar, Mer, Xov, Ven, Sab] month_names: [~, Xaneiro, Febreiro, Marzo, Abril, Maio, Xunio, Xullo, Agosto, Setembro, Outubro, Novembro, Decembro] abbr_month_names: [~, Xan, Feb, Maz, Abr, Mai, Xun, Xul, Ago, Set, Out, Nov, Dec] - order: [:day, :month, :year] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/he.yml b/config/locales/he.yml index e45a7e0a..59af736a 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -15,7 +15,10 @@ he: abbr_day_names: ["א'", "ב'", "ג'", "ד'", "ה'", "ו'", "ש'"] month_names: [~, ינואר, פברואר, מרץ, אפריל, מאי, יוני, יולי, אוגוסט, ספטמבר, אוקטובר, נובמבר, דצמבר] abbr_month_names: [~, יאנ, פבר, מרץ, אפר, מאי, יונ, יול, אוג, ספט, אוק, נוב, דצמ] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 4e086faa..11152dce 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -19,7 +19,10 @@ hr: month_names: [~, Sijecanj, Veljaca, Ožujak, Travanj, Svibanj, Lipanj, Srpanj, Kolovoz, Rujan, Listopad, Studeni, Prosinac] abbr_month_names: [~, Sij, Velj, Ožu, Tra, Svi, Lip, Srp, Kol, Ruj, List, Stu, Pro] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/hu.yml b/config/locales/hu.yml index c951c5da..c522d39d 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -16,7 +16,10 @@ abbr_day_names: [v., h., k., sze., cs., p., szo.] month_names: [~, január, február, március, április, május, június, július, augusztus, szeptember, október, november, december] abbr_month_names: [~, jan., febr., márc., ápr., máj., jún., júl., aug., szept., okt., nov., dec.] - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/id.yml b/config/locales/id.yml index 747ced09..8e958201 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -14,7 +14,10 @@ id: month_names: [~, Januari, Februari, Maret, April, Mei, Juni, Juli, Agustus, September, Oktober, November, Desember] abbr_month_names: [~, Jan, Feb, Mar, Apr, Mei, Jun, Jul, Agu, Sep, Okt, Nov, Des] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/it.yml b/config/locales/it.yml index 7d66fa0e..46cab52b 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -16,7 +16,10 @@ it: abbr_day_names: [Dom, Lun, Mar, Mer, Gio, Ven, Sab] month_names: [~, Gennaio, Febbraio, Marzo, Aprile, Maggio, Giugno, Luglio, Agosto, Settembre, Ottobre, Novembre, Dicembre] abbr_month_names: [~, Gen, Feb, Mar, Apr, Mag, Giu, Lug, Ago, Set, Ott, Nov, Dic] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/ja.yml b/config/locales/ja.yml index b05c5164..199789fc 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -20,7 +20,10 @@ ja: month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/ko.yml b/config/locales/ko.yml index 3f2401f4..e6e11380 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -21,7 +21,10 @@ ko: month_names: [~, 1월, 2월, 3월, 4월, 5월, 6월, 7월, 8월, 9월, 10월, 11월, 12월] abbr_month_names: [~, 1월, 2월, 3월, 4월, 5월, 6월, 7월, 8월, 9월, 10월, 11월, 12월] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/lt.yml b/config/locales/lt.yml index d310fb7b..5fc1653c 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -22,7 +22,10 @@ lt: month_names: [~, sausio, vasario, kovo, balandžio, gegužės, birželio, liepos, rugpjūčio, rugsėjo, spalio, lapkričio, gruodžio] abbr_month_names: [~, Sau, Vas, Kov, Bal, Geg, Bir, Lie, Rgp, Rgs, Spa, Lap, Grd] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 0640637e..4e11f164 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -13,7 +13,10 @@ lv: month_names: [~, Janvāris, Februāris, Marts, Aprīlis , Maijs, Jūnijs, Jūlijs, Augusts, Septembris, Oktobris, Novembris, Decembris] abbr_month_names: [~, Jan, Feb, Mar, Apr, Mai, Jūn, Jūl, Aug, Sep, Okt, Nov, Dec] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/mk.yml b/config/locales/mk.yml index e46c7c88..16e8756f 100644 --- a/config/locales/mk.yml +++ b/config/locales/mk.yml @@ -17,7 +17,10 @@ mk: month_names: [~, јануари, февруари, март, април, мај, јуни, јули, август, септември, октомври, ноември, декември] abbr_month_names: [~, јан, фев, мар, апр, мај, јун, јул, авг, сеп, окт, ное, дек] # Used in date_select and datime_select. - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/mn.yml b/config/locales/mn.yml index 31004e0c..e2482811 100644 --- a/config/locales/mn.yml +++ b/config/locales/mn.yml @@ -16,7 +16,10 @@ mn: month_names: [~, 1-р сар, 2-р сар, 3-р сар, 4-р сар, 5-р сар, 6-р сар, 7-р сар, 8-р сар, 9-р сар, 10-р сар, 11-р сар, 12-р сар] abbr_month_names: [~, 1сар, 2сар, 3сар, 4сар, 5сар, 6сар, 7сар, 8сар, 9сар, 10сар, 11сар, 12сар] # Used in date_select and datime_select. - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 9f215c3e..27495711 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -16,7 +16,10 @@ nl: month_names: [~, januari, februari, maart, april, mei, juni, juli, augustus, september, oktober, november, december] abbr_month_names: [~, jan, feb, mar, apr, mei, jun, jul, aug, sep, okt, nov, dec] # Used in date_select and datime_select. - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/no.yml b/config/locales/no.yml index 73c42c61..776057eb 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -13,7 +13,10 @@ abbr_day_names: [søn, man, tir, ons, tor, fre, lør] month_names: [~, januar, februar, mars, april, mai, juni, juli, august, september, oktober, november, desember] abbr_month_names: [~, jan, feb, mar, apr, mai, jun, jul, aug, sep, okt, nov, des] - order: [:day, :month, :year] + order: + - :day + - :month + - :year time: formats: default: "%A, %e. %B %Y, %H:%M" diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 31724818..cbf950b2 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -45,7 +45,10 @@ pl: month_names: [~, Styczeń, Luty, Marzec, Kwiecień, Maj, Czerwiec, Lipiec, Sierpień, Wrzesień, Październik, Listopad, Grudzień] abbr_month_names: [~, sty, lut, mar, kwi, maj, cze, lip, sie, wrz, paź, lis, gru] - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index aa438e75..81fd09b0 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -12,7 +12,10 @@ pt-BR: abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] - order: [:day,:month,:year] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 787a3a94..42f17bbd 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -17,7 +17,10 @@ pt: abbr_day_names: [Dom, Seg, Ter, Qua, Qui, Sex, Sáb] month_names: [~, Janeiro, Fevereiro, Março, Abril, Maio, Junho, Julho, Agosto, Setembro, Outubro, Novembro, Dezembro] abbr_month_names: [~, Jan, Fev, Mar, Abr, Mai, Jun, Jul, Ago, Set, Out, Nov, Dez] - order: [:day, :month, :year] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/ro.yml b/config/locales/ro.yml index 874e4e30..0e60e1da 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -14,7 +14,10 @@ ro: month_names: [~, Ianuarie, Februarie, Martie, Aprilie, Mai, Iunie, Iulie, August, Septembrie, Octombrie, Noiembrie, Decembrie] abbr_month_names: [~, Ian, Feb, Mar, Apr, Mai, Iun, Iul, Aug, Sep, Oct, Noi, Dec] # Used in date_select and datime_select. - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/ru.yml b/config/locales/ru.yml index 46f75303..a44f602e 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -28,7 +28,10 @@ ru: abbr_month_names: [~, янв., февр., марта, апр., мая, июня, июля, авг., сент., окт., нояб., дек.] standalone_abbr_month_names: [~, янв., февр., март, апр., май, июнь, июль, авг., сент., окт., нояб., дек.] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/sk.yml b/config/locales/sk.yml index f50585d3..8238c9cd 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -16,7 +16,10 @@ sk: month_names: [~, Január, Február, Marec, Apríl, Máj, Jún, Júl, August, September, Október, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, Máj, Jún, Júl, Aug, Sep, Okt, Nov, Dec] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/sl.yml b/config/locales/sl.yml index 7003abef..f133bc7f 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -16,7 +16,10 @@ sl: month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/sr-YU.yml b/config/locales/sr-YU.yml index b0e13450..1c6433ba 100644 --- a/config/locales/sr-YU.yml +++ b/config/locales/sr-YU.yml @@ -18,7 +18,10 @@ sr-YU: month_names: [~, januar, februar, mart, april, maj, jun, jul, avgust, septembar, oktobar, novembar, decembar] abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, avg, sep, okt, nov, dec] # Used in date_select and datime_select. - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 14dbfaef..7e13090b 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -18,7 +18,10 @@ sr: month_names: [~, јануар, фебруар, март, април, мај, јун, јул, август, септембар, октобар, новембар, децембар] abbr_month_names: [~, јан, феб, мар, апр, мај, јун, јул, авг, сеп, окт, нов, дец] # Used in date_select and datime_select. - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/sv.yml b/config/locales/sv.yml index a65a54e3..22176954 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -149,7 +149,10 @@ sv: month_names: [~, januari, februari, mars, april, maj, juni, juli, augusti, september, oktober, november, december] abbr_month_names: [~, jan, feb, mar, apr, maj, jun, jul, aug, sep, okt, nov, dec] # Used in date_select and datime_select. - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/th.yml b/config/locales/th.yml index 2362f715..25aac5e4 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -16,7 +16,10 @@ th: month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/tr.yml b/config/locales/tr.yml index a56bc229..42883e6f 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -18,7 +18,10 @@ tr: abbr_day_names: [Pzr, Pzt, Sal, Çrş, Prş, Cum, Cts] month_names: [~, Ocak, Şubat, Mart, Nisan, Mayıs, Haziran, Temmuz, Ağustos, Eylül, Ekim, Kasım, Aralık] abbr_month_names: [~, Oca, Şub, Mar, Nis, May, Haz, Tem, Ağu, Eyl, Eki, Kas, Ara] - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 83e0e2d9..d40605ec 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -16,7 +16,10 @@ uk: month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December] abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] # Used in date_select and datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 354ea263..33da5de5 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -158,7 +158,10 @@ vi: month_names: [~, "Tháng một", "Tháng hai", "Tháng ba", "Tháng tư", "Tháng năm", "Tháng sáu", "Tháng bảy", "Tháng tám", "Tháng chín", "Tháng mười", "Tháng mười một", "Tháng mười hai"] abbr_month_names: [~, "Tháng một", "Tháng hai", "Tháng ba", "Tháng tư", "Tháng năm", "Tháng sáu", "Tháng bảy", "Tháng tám", "Tháng chín", "Tháng mười", "Tháng mười một", "Tháng mười hai"] # Used in date_select and datime_select. - order: [ :day, :month, :year ] + order: + - :day + - :month + - :year time: formats: diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 664db7ea..44969f84 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -20,7 +20,10 @@ month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月] abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] # 使用於 date_select 與 datime_select. - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 4b2b4004..8d41e689 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -12,7 +12,10 @@ zh: abbr_day_names: [日, 一, 二, 三, 四, 五, 六] month_names: [~, 一月, 二月, 三月, 四月, 五月, 六月, 七月, 八月, 九月, 十月, 十一月, 十二月] abbr_month_names: [~, 1月, 2月, 3月, 4月, 5月, 6月, 7月, 8月, 9月, 10月, 11月, 12月] - order: [ :year, :month, :day ] + order: + - :year + - :month + - :day time: formats: From 50faef3712c2cf3b7948dd35a1a1cb019cf864f1 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Thu, 21 Apr 2011 12:04:04 +0200 Subject: [PATCH 631/777] [#346] also fixing errornous string starting with % --- config/locales/bg.yml | 2 +- config/locales/bs.yml | 2 +- config/locales/ca.yml | 2 +- config/locales/cs.yml | 2 +- config/locales/da.yml | 2 +- config/locales/de.yml | 2 +- config/locales/el.yml | 2 +- config/locales/en-GB.yml | 2 +- config/locales/en.yml | 2 +- config/locales/es.yml | 2 +- config/locales/fi.yml | 2 +- config/locales/fr.yml | 2 +- config/locales/gl.yml | 2 +- config/locales/he.yml | 2 +- config/locales/hr.yml | 2 +- config/locales/id.yml | 2 +- config/locales/it.yml | 2 +- config/locales/lt.yml | 2 +- config/locales/lv.yml | 2 +- config/locales/mk.yml | 2 +- config/locales/mn.yml | 2 +- config/locales/nl.yml | 2 +- config/locales/no.yml | 2 +- config/locales/pl.yml | 2 +- config/locales/pt-BR.yml | 2 +- config/locales/pt.yml | 2 +- config/locales/sk.yml | 2 +- config/locales/sl.yml | 2 +- config/locales/sr-YU.yml | 2 +- config/locales/sr.yml | 2 +- config/locales/sv.yml | 2 +- config/locales/th.yml | 2 +- config/locales/tr.yml | 2 +- config/locales/uk.yml | 2 +- 34 files changed, 34 insertions(+), 34 deletions(-) diff --git a/config/locales/bg.yml b/config/locales/bg.yml index 28c690c1..f7ff09e1 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -270,7 +270,7 @@ bg: field_attr_mail: Атрибут Email field_onthefly: Динамично създаване на потребител field_start_date: Начална дата - field_done_ratio: % Прогрес + field_done_ratio: "% Прогрес" field_auth_source: Начин на оторизация field_hide_mail: Скрий e-mail адреса ми field_comments: Коментар diff --git a/config/locales/bs.yml b/config/locales/bs.yml index 8c1c5a85..9dcef1b4 100644 --- a/config/locales/bs.yml +++ b/config/locales/bs.yml @@ -259,7 +259,7 @@ bs: field_attr_mail: Atribut za email field_onthefly: 'Kreiranje korisnika "On-the-fly"' field_start_date: Početak - field_done_ratio: % Realizovano + field_done_ratio: "% Realizovano" field_auth_source: Mod za authentifikaciju field_hide_mail: Sakrij moju email adresu field_comments: Komentar diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 160d934e..5a9ec46e 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -271,7 +271,7 @@ ca: field_attr_mail: Atribut del correu electrònic field_onthefly: "Creació de l'usuari «al vol»" field_start_date: Inici - field_done_ratio: % realitzat + field_done_ratio: "% realitzat" field_auth_source: "Mode d'autenticació" field_hide_mail: "Oculta l'adreça de correu electrònic" field_comments: Comentari diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 4a7df4d5..617e1d60 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -274,7 +274,7 @@ cs: field_attr_mail: Email (atribut) field_onthefly: Automatické vytváření uživatelů field_start_date: Začátek - field_done_ratio: % Hotovo + field_done_ratio: "% Hotovo" field_auth_source: Autentifikační mód field_hide_mail: Nezobrazovat můj email field_comments: Komentář diff --git a/config/locales/da.yml b/config/locales/da.yml index e3918fb6..ffbb982a 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -257,7 +257,7 @@ da: field_attr_mail: Email attribut field_onthefly: løbende brugeroprettelse field_start_date: Start date - field_done_ratio: % Færdig + field_done_ratio: "% Færdig" field_auth_source: Sikkerhedsmetode field_hide_mail: Skjul min email field_comments: Kommentar diff --git a/config/locales/de.yml b/config/locales/de.yml index d27cfcb9..f93206a4 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -285,7 +285,7 @@ de: field_attr_mail: E-Mail-Attribut field_onthefly: On-the-fly-Benutzererstellung field_start_date: Beginn - field_done_ratio: % erledigt + field_done_ratio: "% erledigt" field_auth_source: Authentifizierungs-Modus field_hide_mail: E-Mail-Adresse nicht anzeigen field_comments: Kommentar diff --git a/config/locales/el.yml b/config/locales/el.yml index d6bbc514..5816a4c8 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -254,7 +254,7 @@ el: field_attr_mail: Ιδιότητα email field_onthefly: Άμεση δημιουργία χρήστη field_start_date: Εκκίνηση - field_done_ratio: % επιτεύχθη + field_done_ratio: "% επιτεύχθη" field_auth_source: Τρόπος πιστοποίησης field_hide_mail: Απόκρυψη διεύθυνσης email field_comments: Σχόλιο diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 624ee1ea..3f16e789 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -275,7 +275,7 @@ en-GB: field_attr_mail: Email attribute field_onthefly: On-the-fly user creation field_start_date: Start date - field_done_ratio: % Done + field_done_ratio: "% Done" field_auth_source: Authentication mode field_hide_mail: Hide my email address field_comments: Comment diff --git a/config/locales/en.yml b/config/locales/en.yml index 2249b380..6d415aac 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -271,7 +271,7 @@ en: field_attr_mail: Email attribute field_onthefly: On-the-fly user creation field_start_date: Start date - field_done_ratio: % Done + field_done_ratio: "% Done" field_auth_source: Authentication mode field_hide_mail: Hide my email address field_comments: Comment diff --git a/config/locales/es.yml b/config/locales/es.yml index 11dfccef..f220a13d 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -269,7 +269,7 @@ es: field_default_value: Estado por defecto field_delay: Retraso field_description: Descripción - field_done_ratio: % Realizado + field_done_ratio: "% Realizado" field_downloads: Descargas field_due_date: Fecha fin field_estimated_hours: Tiempo estimado diff --git a/config/locales/fi.yml b/config/locales/fi.yml index 5536cfcc..e5539296 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -265,7 +265,7 @@ fi: field_attr_mail: Sähköpostinmääre field_onthefly: Automaattinen käyttäjien luonti field_start_date: Alku - field_done_ratio: % Tehty + field_done_ratio: "% Tehty" field_auth_source: Varmennusmuoto field_hide_mail: Piiloita sähköpostiosoitteeni field_comments: Kommentti diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 00db9885..6df8aa3b 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -277,7 +277,7 @@ fr: field_attr_mail: Attribut Email field_onthefly: Création des utilisateurs à la volée field_start_date: Début - field_done_ratio: % réalisé + field_done_ratio: "% réalisé" field_auth_source: Mode d'authentification field_hide_mail: Cacher mon adresse mail field_comments: Commentaire diff --git a/config/locales/gl.yml b/config/locales/gl.yml index 6df570ef..dd4aaef2 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -246,7 +246,7 @@ gl: field_default_value: Estado por defecto field_delay: Retraso field_description: Descrición - field_done_ratio: % Realizado + field_done_ratio: "% Realizado" field_downloads: Descargas field_due_date: Data fin field_estimated_hours: Tempo estimado diff --git a/config/locales/he.yml b/config/locales/he.yml index 59af736a..f8c96f6c 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -273,7 +273,7 @@ he: field_attr_mail: תכונת דוא"ל field_onthefly: יצירת משתמשים זריזה field_start_date: תאריך התחלה - field_done_ratio: % גמור + field_done_ratio: "% גמור" field_auth_source: מקור הזדהות field_hide_mail: החבא את כתובת הדוא"ל שלי field_comments: הערות diff --git a/config/locales/hr.yml b/config/locales/hr.yml index 11152dce..a835dd49 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -260,7 +260,7 @@ hr: field_attr_mail: Atribut e-pošte field_onthefly: "Izrada korisnika \"u hodu\"" field_start_date: Pocetak - field_done_ratio: % Učinjeno + field_done_ratio: "% Učinjeno" field_auth_source: Vrsta prijavljivanja field_hide_mail: Sakrij moju adresu e-pošte field_comments: Komentar diff --git a/config/locales/id.yml b/config/locales/id.yml index 8e958201..f3bd87e9 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -258,7 +258,7 @@ id: field_attr_mail: Atribut email field_onthefly: Pembuatan pengguna seketika field_start_date: Mulai - field_done_ratio: % Selesai + field_done_ratio: "% Selesai" field_auth_source: Mode otentikasi field_hide_mail: Sembunyikan email saya field_comments: Komentar diff --git a/config/locales/it.yml b/config/locales/it.yml index 46cab52b..04294568 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -236,7 +236,7 @@ it: field_attr_mail: Attributo email field_onthefly: Creazione utente "al volo" field_start_date: Inizio - field_done_ratio: % completato + field_done_ratio: "% completato" field_auth_source: Modalità di autenticazione field_hide_mail: Nascondi il mio indirizzo email field_comments: Commento diff --git a/config/locales/lt.yml b/config/locales/lt.yml index 5fc1653c..f2bfb60e 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -313,7 +313,7 @@ lt: field_attr_mail: Elektroninio pašto požymis field_onthefly: Automatinis vartotojų registravimas field_start_date: Pradėti - field_done_ratio: % atlikta + field_done_ratio: "% atlikta" field_auth_source: Autentiškumo nustatymo būdas field_hide_mail: Paslėpkite mano elektroninio pašto adresą field_comments: Komentaras diff --git a/config/locales/lv.yml b/config/locales/lv.yml index 4e11f164..dbea18ee 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -255,7 +255,7 @@ lv: field_attr_mail: "E-pasta atribūts" field_onthefly: "Lietotāja izveidošana on-the-fly" field_start_date: Sākuma datums - field_done_ratio: % padarīti + field_done_ratio: "% padarīti" field_auth_source: Pilnvarošanas režīms field_hide_mail: "Paslēpt manu e-pasta adresi" field_comments: Komentārs diff --git a/config/locales/mk.yml b/config/locales/mk.yml index 16e8756f..5ee6efee 100644 --- a/config/locales/mk.yml +++ b/config/locales/mk.yml @@ -268,7 +268,7 @@ mk: field_attr_mail: Email attribute field_onthefly: Моментално (On-the-fly) креирање на корисници field_start_date: Почеток - field_done_ratio: % Завршено + field_done_ratio: "% Завршено" field_auth_source: Режим на автентикација field_hide_mail: Криј ја мојата адреса на е-пошта field_comments: Коментар diff --git a/config/locales/mn.yml b/config/locales/mn.yml index e2482811..d4fcd8b2 100644 --- a/config/locales/mn.yml +++ b/config/locales/mn.yml @@ -259,7 +259,7 @@ mn: field_attr_mail: Имэйл аттрибут field_onthefly: Хүссэн үедээ хэрэглэгч үүсгэх field_start_date: Эхлэл - field_done_ratio: %% Гүйцэтгэсэн + field_done_ratio: "%% Гүйцэтгэсэн" field_auth_source: Нэвтрэх арга field_hide_mail: Миний имэйл хаягийг нуу field_comments: Тайлбар diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 27495711..8c813d9b 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -216,7 +216,7 @@ nl: field_default_value: Standaardwaarde field_delay: Vertraging field_description: Beschrijving - field_done_ratio: % Gereed + field_done_ratio: "% Gereed" field_downloads: Downloads field_due_date: Verwachte datum gereed field_estimated_hours: Geschatte tijd diff --git a/config/locales/no.yml b/config/locales/no.yml index 776057eb..37685001 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -234,7 +234,7 @@ field_attr_mail: E-post-attributt field_onthefly: On-the-fly brukeropprettelse field_start_date: Start - field_done_ratio: % Ferdig + field_done_ratio: "% Ferdig" field_auth_source: Autentifikasjonsmodus field_hide_mail: Skjul min e-post-adresse field_comments: Kommentarer diff --git a/config/locales/pl.yml b/config/locales/pl.yml index cbf950b2..d765079e 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -233,7 +233,7 @@ pl: field_default_value: Domyślny field_delay: Opóźnienie field_description: Opis - field_done_ratio: % Wykonane + field_done_ratio: "% Wykonane" field_downloads: Pobrań field_due_date: Data oddania field_estimated_hours: Szacowany czas diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 81fd09b0..51a8d8f7 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -267,7 +267,7 @@ pt-BR: field_attr_mail: Atributo para e-mail field_onthefly: Criar usuários dinamicamente ("on-the-fly") field_start_date: Início - field_done_ratio: % Terminado + field_done_ratio: "% Terminado" field_auth_source: Modo de autenticação field_hide_mail: Ocultar meu e-mail field_comments: Comentário diff --git a/config/locales/pt.yml b/config/locales/pt.yml index 42f17bbd..a78ddca8 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -252,7 +252,7 @@ pt: field_attr_mail: Atributo e-mail field_onthefly: Criação de utilizadores na hora field_start_date: Início - field_done_ratio: % Completo + field_done_ratio: "% Completo" field_auth_source: Modo de autenticação field_hide_mail: Esconder endereço de e-mail field_comments: Comentário diff --git a/config/locales/sk.yml b/config/locales/sk.yml index 8238c9cd..d4006cb4 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -238,7 +238,7 @@ sk: field_attr_mail: Email (atribut) field_onthefly: Automatické vytváranie užívateľov field_start_date: Začiatok - field_done_ratio: % hotovo + field_done_ratio: "% hotovo" field_auth_source: Autentifikačný mód field_hide_mail: Nezobrazovať môj email field_comments: Komentár diff --git a/config/locales/sl.yml b/config/locales/sl.yml index f133bc7f..bfd951ca 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -243,7 +243,7 @@ sl: field_attr_mail: Oznaka za e-naslov field_onthefly: Sprotna izdelava uporabnikov field_start_date: Začetek - field_done_ratio: % Narejeno + field_done_ratio: "% Narejeno" field_auth_source: Način overovljanja field_hide_mail: Skrij moj e-naslov field_comments: Komentar diff --git a/config/locales/sr-YU.yml b/config/locales/sr-YU.yml index 1c6433ba..5797a921 100644 --- a/config/locales/sr-YU.yml +++ b/config/locales/sr-YU.yml @@ -268,7 +268,7 @@ sr-YU: field_attr_mail: Atribut e-adrese field_onthefly: Kreiranje korisnika u toku rada field_start_date: Početak - field_done_ratio: % urađeno + field_done_ratio: "% urađeno" field_auth_source: Režim potvrde identiteta field_hide_mail: Sakrij moju e-adresu field_comments: Komentar diff --git a/config/locales/sr.yml b/config/locales/sr.yml index 7e13090b..cd617572 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -268,7 +268,7 @@ sr: field_attr_mail: Атрибут е-адресе field_onthefly: Креирање корисника у току рада field_start_date: Почетак - field_done_ratio: % урађено + field_done_ratio: "% урађено" field_auth_source: Режим потврде идентитета field_hide_mail: Сакриј моју е-адресу field_comments: Коментар diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 22176954..2272025e 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -312,7 +312,7 @@ sv: field_attr_mail: Mailattribut field_onthefly: Skapa användare on-the-fly field_start_date: Startdatum - field_done_ratio: % Klart + field_done_ratio: "% Klart" field_auth_source: Autentiseringsläge field_hide_mail: Dölj min mailadress field_comments: Kommentar diff --git a/config/locales/th.yml b/config/locales/th.yml index 25aac5e4..55d24d0e 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -240,7 +240,7 @@ th: field_attr_mail: อีเมล์ attribute field_onthefly: สร้างผู้ใช้ทันที field_start_date: เริ่ม - field_done_ratio: % สำเร็จ + field_done_ratio: "% สำเร็จ" field_auth_source: วิธีการยืนยันตัวตน field_hide_mail: ซ่อนอีเมล์ของฉัน field_comments: ความเห็น diff --git a/config/locales/tr.yml b/config/locales/tr.yml index 42883e6f..cd91c292 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -263,7 +263,7 @@ tr: field_attr_mail: E-Posta Niteliği field_onthefly: Anında kullanıcı oluşturma field_start_date: Başlangıç - field_done_ratio: % tamamlandı + field_done_ratio: "% tamamlandı " field_auth_source: Kimlik Denetim Modu field_hide_mail: E-posta adresimi gizle field_comments: Açıklama diff --git a/config/locales/uk.yml b/config/locales/uk.yml index d40605ec..506c9a87 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -234,7 +234,7 @@ uk: field_attr_mail: Атрибут Email field_onthefly: Створення користувача на льоту field_start_date: Початок - field_done_ratio: % зроблено + field_done_ratio: "% зроблено" field_auth_source: Режим аутентифікації field_hide_mail: Приховувати мій email field_comments: Коментар From 31d292ce95eecdf514ead787f3e8d794cd576fe3 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Thu, 21 Apr 2011 13:20:00 +0200 Subject: [PATCH 632/777] [#346] Fixing hebrew translations to work with psyc --- config/locales/he.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/he.yml b/config/locales/he.yml index f8c96f6c..47f92f4a 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -166,7 +166,7 @@ he: notice_email_error: "ארעה שגיאה בעת שליחת הדואל (%{value})" notice_feeds_access_key_reseted: מפתח ה־RSS שלך אופס. notice_api_access_key_reseted: מפתח הגישה שלך ל־API אופס. - notice_failed_to_save_issues: "נכשרת בשמירת %{count} נושא\ים ב %{total} נבחרו: %{ids}." + notice_failed_to_save_issues: "נכשרת בשמירת %{count} נושאים ב %{total} נבחרו: %{ids}." notice_failed_to_save_members: "כשלון בשמירת חבר(ים): %{errors}." notice_no_issue_selected: "לא נבחר אף נושא! בחר בבקשה את הנושאים שברצונך לערוך." notice_account_pending: "החשבון שלך נוצר ועתה מחכה לאישור מנהל המערכת." @@ -848,7 +848,7 @@ he: text_regexp_info: כגון. ^[A-Z0-9]+$ text_min_max_length_info: 0 משמעו ללא הגבלות text_project_destroy_confirmation: האם אתה בטוח שברצונך למחוק את הפרויקט ואת כל המידע הקשור אליו? - text_subprojects_destroy_warning: "תת־הפרויקט\ים: %{value} ימחקו גם כן." + text_subprojects_destroy_warning: "תת־הפרויקטים: %{value} ימחקו גם כן." text_workflow_edit: בחר תפקיד וסיווג כדי לערוך את זרימת העבודה text_are_you_sure: האם אתה בטוח? text_are_you_sure_with_children: האם למחוק את הנושא ואת כל בניו? @@ -878,7 +878,7 @@ he: text_no_configuration_data: "לא הוגדרה תצורה עבור תפקידים, סיווגים, מצבי נושא וזרימת עבודה.\nמומלץ מאד לטעון את תצורת ברירת המחדל. תוכל לשנותה מאוחר יותר." text_load_default_configuration: טען את אפשרויות ברירת המחדל text_status_changed_by_changeset: "הוחל בסדרת השינויים %{value}." - text_issues_destroy_confirmation: 'האם אתה בטוח שברצונך למחוק את הנושא\ים?' + text_issues_destroy_confirmation: 'האם אתה בטוח שברצונך למחוק את הנושאים?' text_select_project_modules: 'בחר מודולים להחיל על פרויקט זה:' text_default_administrator_account_changed: מנהל המערכת ברירת המחדל שונה text_file_repository_writable: מאגר הקבצים ניתן לכתיבה From 90987ca34e9cd10181ed7952a08c42ba0327f9bf Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Thu, 21 Apr 2011 13:24:49 +0200 Subject: [PATCH 633/777] [#346] Fixing polish and swedish translations to work with psych --- config/locales/pl.yml | 4 ++-- config/locales/sv.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/config/locales/pl.yml b/config/locales/pl.yml index d765079e..4d5b38f2 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -868,7 +868,7 @@ pl: button_show: Pokaż error_can_not_archive_project: Ten projekt nie może zostać zarchiwizowany error_can_not_reopen_issue_on_closed_version: Zagadnienie przydzielone do zakończonej wersji nie może zostać ponownie otwarte - error_issue_done_ratios_not_updated: % wykonania zagadnienia nie został uaktualniony. + error_issue_done_ratios_not_updated: "% wykonania zagadnienia nie został uaktualniony." error_workflow_copy_source: Proszę wybrać źródłowy typ zagadnienia lub rolę error_workflow_copy_target: Proszę wybrać docelowe typ(y) zagadnień i rolę(e) field_sharing: Współdzielenie @@ -899,7 +899,7 @@ pl: setting_default_projects_modules: Domyślnie włączone moduły dla nowo tworzonych projektów setting_gravatar_default: Domyślny obraz Gravatar setting_issue_done_ratio: Obliczaj postęp realizacji zagadnień za pomocą - setting_issue_done_ratio_issue_field: % Wykonania zagadnienia + setting_issue_done_ratio_issue_field: "% Wykonania zagadnienia" setting_issue_done_ratio_issue_status: Statusu zagadnienia setting_mail_handler_body_delimiters: Przycinaj e-maile po jednej z tych linii setting_rest_api_enabled: Uaktywnij usługę sieciową REST diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 2272025e..7f08d80b 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -210,7 +210,7 @@ sv: notice_default_data_loaded: Standardkonfiguration inläst. notice_unable_delete_version: Denna version var inte möjlig att ta bort. notice_unable_delete_time_entry: Tidloggning kunde inte tas bort. - notice_issue_done_ratios_updated: % klart uppdaterade. + notice_issue_done_ratios_updated: "% klart uppdaterade." notice_gantt_chart_truncated: "Schemat förminskades eftersom det överskrider det maximala antalet aktiviteter som får visas (%{max})" error_can_t_load_default_data: "Standardkonfiguration gick inte att läsa in: %{value}" From bfacd827a85a6cfdde7d3166fdb78ef591e1a043 Mon Sep 17 00:00:00 2001 From: Simon COURTOIS Date: Thu, 28 Apr 2011 16:42:07 +0200 Subject: [PATCH 634/777] Removig english strings from RepositoriesHelper --- app/helpers/repositories_helper.rb | 25 ++++++++++++------------- config/locales/bg.yml | 5 +++++ config/locales/bs.yml | 5 +++++ config/locales/ca.yml | 5 +++++ config/locales/cs.yml | 5 +++++ config/locales/da.yml | 5 +++++ config/locales/de.yml | 5 +++++ config/locales/el.yml | 5 +++++ config/locales/en-GB.yml | 5 +++++ config/locales/en.yml | 4 ++++ config/locales/es.yml | 5 +++++ config/locales/eu.yml | 5 +++++ config/locales/fa.yml | 5 +++++ config/locales/fi.yml | 5 +++++ config/locales/fr.yml | 5 +++++ config/locales/gl.yml | 5 +++++ config/locales/he.yml | 5 +++++ config/locales/hr.yml | 5 +++++ config/locales/hu.yml | 5 +++++ config/locales/id.yml | 5 +++++ config/locales/it.yml | 5 +++++ config/locales/ja.yml | 5 +++++ config/locales/ko.yml | 5 +++++ config/locales/lt.yml | 5 +++++ config/locales/lv.yml | 5 +++++ config/locales/mk.yml | 5 +++++ config/locales/mn.yml | 5 +++++ config/locales/nl.yml | 5 +++++ config/locales/no.yml | 5 +++++ config/locales/pl.yml | 5 +++++ config/locales/pt-BR.yml | 5 +++++ config/locales/pt.yml | 5 +++++ config/locales/ro.yml | 5 +++++ config/locales/ru.yml | 5 +++++ config/locales/sk.yml | 5 +++++ config/locales/sl.yml | 5 +++++ config/locales/sr-YU.yml | 5 +++++ config/locales/sr.yml | 5 +++++ config/locales/sv.yml | 5 +++++ config/locales/th.yml | 5 +++++ config/locales/tr.yml | 5 +++++ config/locales/uk.yml | 5 +++++ config/locales/vi.yml | 5 +++++ config/locales/zh-TW.yml | 5 +++++ config/locales/zh.yml | 5 +++++ 45 files changed, 231 insertions(+), 13 deletions(-) diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index 8e79101c..c8f6e8bf 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -217,45 +217,44 @@ module RepositoriesHelper def darcs_field_tags(form, repository) content_tag('p', form.text_field(:url, :label => :label_darcs_path, :size => 60, :required => true, :disabled => (repository && !repository.new_record?))) + content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS, - :label => 'Commit messages encoding', :required => true)) + :label => l(:setting_commit_logs_encoding), :required => true)) end def mercurial_field_tags(form, repository) content_tag('p', form.text_field(:url, :label => :label_mercurial_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) + - '
    local repository (e.g. /hgrepo, c:\hgrepo)' ) + - content_tag('p', form.select( - :path_encoding, [nil] + Setting::ENCODINGS, - :label => 'Path encoding') + - '
    Default: UTF-8') + '
    ' + l(:text_mercurial_repo_example)) + + content_tag('p', form.select(:path_encoding, [nil] + Setting::ENCODINGS, + :label => l(:label_path_encoding)) + + '
    ' + l(:text_default_encoding)) end def git_field_tags(form, repository) content_tag('p', form.text_field(:url, :label => :label_git_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?)) + - '
    a bare and local repository (e.g. /gitrepo, c:\gitrepo)') + + '
    ' + l(:text_git_repo_example)) + content_tag('p', form.select( :path_encoding, [nil] + Setting::ENCODINGS, - :label => 'Path encoding') + - '
    Default: UTF-8') + :label => l(:label_path_encoding)) + + '
    ' + l(:text_default_encoding)) end def cvs_field_tags(form, repository) content_tag('p', form.text_field(:root_url, :label => :label_cvs_path, :size => 60, :required => true, :disabled => !repository.new_record?)) + content_tag('p', form.text_field(:url, :label => :label_cvs_module, :size => 30, :required => true, :disabled => !repository.new_record?)) + content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS, - :label => 'Commit messages encoding', :required => true)) + :label => l(:setting_commit_logs_encoding), :required => true)) end def bazaar_field_tags(form, repository) content_tag('p', form.text_field(:url, :label => :label_bazaar_path, :size => 60, :required => true, :disabled => (repository && !repository.new_record?))) + content_tag('p', form.select(:log_encoding, [nil] + Setting::ENCODINGS, - :label => 'Commit messages encoding', :required => true)) + :label => l(:setting_commit_logs_encoding), :required => true)) end def filesystem_field_tags(form, repository) content_tag('p', form.text_field(:url, :label => :label_filesystem_path, :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) + content_tag('p', form.select(:path_encoding, [nil] + Setting::ENCODINGS, - :label => 'Path encoding') + - '
    Default: UTF-8') + :label => l(:label_path_encoding)) + + '
    ' + l(:text_default_encoding)) end end diff --git a/config/locales/bg.yml b/config/locales/bg.yml index f7ff09e1..e5e32151 100644 --- a/config/locales/bg.yml +++ b/config/locales/bg.yml @@ -958,3 +958,8 @@ bg: button_collapse_all: Collapse all label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author field_effective_date: Due date + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/bs.yml b/config/locales/bs.yml index 9dcef1b4..2a18d88c 100644 --- a/config/locales/bs.yml +++ b/config/locales/bs.yml @@ -972,3 +972,8 @@ bs: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/ca.yml b/config/locales/ca.yml index 5a9ec46e..1f9384b6 100644 --- a/config/locales/ca.yml +++ b/config/locales/ca.yml @@ -961,3 +961,8 @@ ca: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/cs.yml b/config/locales/cs.yml index 617e1d60..225c25bf 100644 --- a/config/locales/cs.yml +++ b/config/locales/cs.yml @@ -1182,3 +1182,8 @@ cs: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/da.yml b/config/locales/da.yml index ffbb982a..ffdf8863 100644 --- a/config/locales/da.yml +++ b/config/locales/da.yml @@ -974,3 +974,8 @@ da: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/de.yml b/config/locales/de.yml index f93206a4..1e7b5f9b 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -975,3 +975,8 @@ de: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/el.yml b/config/locales/el.yml index 5816a4c8..e4d012b8 100644 --- a/config/locales/el.yml +++ b/config/locales/el.yml @@ -958,3 +958,8 @@ el: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml index 3f16e789..2170e042 100644 --- a/config/locales/en-GB.yml +++ b/config/locales/en-GB.yml @@ -962,3 +962,8 @@ en-GB: label_mercurial_path: Root directory label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/en.yml b/config/locales/en.yml index e4477b53..fd6e2c98 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -809,6 +809,7 @@ en: label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding button_login: Login button_submit: Submit @@ -929,6 +930,9 @@ en: text_zoom_out: Zoom out text_powered_by: "Powered by %{link}" text_warn_on_leaving_unsaved: "The current page contains unsaved text that will be lost if you leave this page." + text_default_encoding: "Default: UTF-8" + text_mercurial_repo_example: "local repository (e.g. /hgrepo, c:\hgrepo)" + text_git_repo_example: "a bare and local repository (e.g. /gitrepo, c:\gitrepo)" default_role_manager: Manager default_role_developer: Developer diff --git a/config/locales/es.yml b/config/locales/es.yml index f220a13d..f8aad096 100644 --- a/config/locales/es.yml +++ b/config/locales/es.yml @@ -995,3 +995,8 @@ es: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/eu.yml b/config/locales/eu.yml index c16e6e19..21c6c44a 100644 --- a/config/locales/eu.yml +++ b/config/locales/eu.yml @@ -962,3 +962,8 @@ eu: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/fa.yml b/config/locales/fa.yml index a8e8a37c..4fa0a109 100644 --- a/config/locales/fa.yml +++ b/config/locales/fa.yml @@ -961,3 +961,8 @@ fa: text_powered_by: Powered by %{link} default_role_non_member: Non member label_mercurial_path: Root directory + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/fi.yml b/config/locales/fi.yml index e5539296..10620c26 100644 --- a/config/locales/fi.yml +++ b/config/locales/fi.yml @@ -979,3 +979,8 @@ fi: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 6df8aa3b..7d0382e3 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -976,3 +976,8 @@ fr: label_git_path: Path to .git directory label_mercurial_path: Root directory field_effective_date: Due date + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/gl.yml b/config/locales/gl.yml index dd4aaef2..1f24b694 100644 --- a/config/locales/gl.yml +++ b/config/locales/gl.yml @@ -970,3 +970,8 @@ gl: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/he.yml b/config/locales/he.yml index 47f92f4a..17ef662a 100644 --- a/config/locales/he.yml +++ b/config/locales/he.yml @@ -963,3 +963,8 @@ he: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/hr.yml b/config/locales/hr.yml index a835dd49..837d1cc6 100644 --- a/config/locales/hr.yml +++ b/config/locales/hr.yml @@ -965,3 +965,8 @@ hr: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/hu.yml b/config/locales/hu.yml index c522d39d..58e2e7bc 100644 --- a/config/locales/hu.yml +++ b/config/locales/hu.yml @@ -977,3 +977,8 @@ label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/id.yml b/config/locales/id.yml index f3bd87e9..c543ff45 100644 --- a/config/locales/id.yml +++ b/config/locales/id.yml @@ -966,3 +966,8 @@ id: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/it.yml b/config/locales/it.yml index 04294568..a5290802 100644 --- a/config/locales/it.yml +++ b/config/locales/it.yml @@ -959,3 +959,8 @@ it: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/ja.yml b/config/locales/ja.yml index 199789fc..37d56f4c 100644 --- a/config/locales/ja.yml +++ b/config/locales/ja.yml @@ -980,3 +980,8 @@ ja: label_additional_workflow_transitions_for_assignee: Additional transitions allowed when the user is the assignee label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author field_effective_date: Due date + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/ko.yml b/config/locales/ko.yml index e6e11380..fd0c078c 100644 --- a/config/locales/ko.yml +++ b/config/locales/ko.yml @@ -1010,3 +1010,8 @@ ko: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/lt.yml b/config/locales/lt.yml index f2bfb60e..ada822a0 100644 --- a/config/locales/lt.yml +++ b/config/locales/lt.yml @@ -1018,3 +1018,8 @@ lt: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/lv.yml b/config/locales/lv.yml index dbea18ee..87a11053 100644 --- a/config/locales/lv.yml +++ b/config/locales/lv.yml @@ -953,3 +953,8 @@ lv: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/mk.yml b/config/locales/mk.yml index 5ee6efee..c35f48df 100644 --- a/config/locales/mk.yml +++ b/config/locales/mk.yml @@ -958,3 +958,8 @@ mk: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/mn.yml b/config/locales/mn.yml index d4fcd8b2..6277ffc7 100644 --- a/config/locales/mn.yml +++ b/config/locales/mn.yml @@ -959,3 +959,8 @@ mn: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/nl.yml b/config/locales/nl.yml index 8c813d9b..8854a14c 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -940,3 +940,8 @@ nl: label_git_path: Path to .git directory text_powered_by: Powered by %{link} label_mercurial_path: Root directory + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/no.yml b/config/locales/no.yml index 37685001..d1f3042c 100644 --- a/config/locales/no.yml +++ b/config/locales/no.yml @@ -945,3 +945,8 @@ label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/pl.yml b/config/locales/pl.yml index 4d5b38f2..8f459418 100644 --- a/config/locales/pl.yml +++ b/config/locales/pl.yml @@ -975,3 +975,8 @@ pl: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/pt-BR.yml b/config/locales/pt-BR.yml index 51a8d8f7..db89bd87 100644 --- a/config/locales/pt-BR.yml +++ b/config/locales/pt-BR.yml @@ -981,3 +981,8 @@ pt-BR: label_git_path: Path to .git directory text_powered_by: Powered by %{link} label_mercurial_path: Root directory + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/pt.yml b/config/locales/pt.yml index a78ddca8..d9ec309a 100644 --- a/config/locales/pt.yml +++ b/config/locales/pt.yml @@ -962,3 +962,8 @@ pt: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/ro.yml b/config/locales/ro.yml index 0e60e1da..c0a41e76 100644 --- a/config/locales/ro.yml +++ b/config/locales/ro.yml @@ -951,3 +951,8 @@ ro: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/ru.yml b/config/locales/ru.yml index a44f602e..382f0bbf 100644 --- a/config/locales/ru.yml +++ b/config/locales/ru.yml @@ -1071,3 +1071,8 @@ ru: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/sk.yml b/config/locales/sk.yml index d4006cb4..c7c28ecd 100644 --- a/config/locales/sk.yml +++ b/config/locales/sk.yml @@ -953,3 +953,8 @@ sk: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/sl.yml b/config/locales/sl.yml index bfd951ca..6a928928 100644 --- a/config/locales/sl.yml +++ b/config/locales/sl.yml @@ -954,3 +954,8 @@ sl: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/sr-YU.yml b/config/locales/sr-YU.yml index 5797a921..6e43db73 100644 --- a/config/locales/sr-YU.yml +++ b/config/locales/sr-YU.yml @@ -958,3 +958,8 @@ sr-YU: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/sr.yml b/config/locales/sr.yml index cd617572..a53b4840 100644 --- a/config/locales/sr.yml +++ b/config/locales/sr.yml @@ -959,3 +959,8 @@ sr: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/sv.yml b/config/locales/sv.yml index 7f08d80b..3d9a0122 100644 --- a/config/locales/sv.yml +++ b/config/locales/sv.yml @@ -1000,3 +1000,8 @@ sv: label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author field_effective_date: Due date label_news_comment_added: Comment added to a news + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/th.yml b/config/locales/th.yml index 55d24d0e..febda7c3 100644 --- a/config/locales/th.yml +++ b/config/locales/th.yml @@ -955,3 +955,8 @@ th: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/tr.yml b/config/locales/tr.yml index cd91c292..02d0cff6 100644 --- a/config/locales/tr.yml +++ b/config/locales/tr.yml @@ -977,3 +977,8 @@ tr: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/uk.yml b/config/locales/uk.yml index 506c9a87..ac8afd0a 100644 --- a/config/locales/uk.yml +++ b/config/locales/uk.yml @@ -954,3 +954,8 @@ uk: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/vi.yml b/config/locales/vi.yml index 33da5de5..df038cd5 100644 --- a/config/locales/vi.yml +++ b/config/locales/vi.yml @@ -1009,3 +1009,8 @@ vi: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/zh-TW.yml b/config/locales/zh-TW.yml index 44969f84..4ef2277b 100644 --- a/config/locales/zh-TW.yml +++ b/config/locales/zh-TW.yml @@ -1040,3 +1040,8 @@ label_additional_workflow_transitions_for_author: Additional transitions allowed when the user is the author field_effective_date: Due date label_news_comment_added: Comment added to a news + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) diff --git a/config/locales/zh.yml b/config/locales/zh.yml index 8d41e689..6c42072e 100644 --- a/config/locales/zh.yml +++ b/config/locales/zh.yml @@ -972,3 +972,8 @@ zh: label_news_comment_added: Comment added to a news field_warn_on_leaving_unsaved: Warn me when leaving a page with unsaved text text_warn_on_leaving_unsaved: The current page contains unsaved text that will be lost if you leave this page. + text_default_encoding: "Default: UTF-8" + text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo) + label_notify_member_plural: Email issue updates + label_path_encoding: Path encoding + text_mercurial_repo_example: local repository (e.g. /hgrepo, c:\hgrepo) From 1f8828838eb4931f02112291645f81dc44459b03 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 6 May 2011 14:08:39 -0700 Subject: [PATCH 635/777] [#123] Attachment changes need to be prefixed --- app/models/issue.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/issue.rb b/app/models/issue.rb index fdde178d..90fdacbd 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -353,7 +353,7 @@ class Issue < ActiveRecord::Base def attachment_removed(obj) init_journal(User.current) create_journal - last_journal.update_attribute(:changes, {obj.id => [obj.filename, nil]}.to_yaml) + last_journal.update_attribute(:changes, {"attachments_" + obj.id.to_s => [obj.filename, nil]}.to_yaml) end # Return true if the issue is closed, otherwise false From 65953cdc04482230f8aa987b399bc23d2a7f84ed Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 6 May 2011 14:27:29 -0700 Subject: [PATCH 636/777] [#123] Fix AttachmentsController test from 1f88288 --- test/functional/attachments_controller_test.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/attachments_controller_test.rb b/test/functional/attachments_controller_test.rb index 223cc0bb..2a482464 100644 --- a/test/functional/attachments_controller_test.rb +++ b/test/functional/attachments_controller_test.rb @@ -121,8 +121,8 @@ class AttachmentsControllerTest < ActionController::TestCase assert_redirected_to '/projects/ecookbook' assert_nil Attachment.find_by_id(1) j = issue.journals.find(:first, :order => 'created_at DESC') - assert_equal [1], j.details.keys - assert_equal 'error281.txt', j.details[1].first + assert_equal ['attachments_1'], j.details.keys + assert_equal 'error281.txt', j.details['attachments_1'].first end def test_destroy_wiki_page_attachment From cc0c2165b5f9aec81f0f74e012ed0d86297161d0 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 6 May 2011 14:28:04 -0700 Subject: [PATCH 637/777] [#123] Fix test on postgres, .first isn't based on ORDER --- test/unit/journal_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/journal_test.rb b/test/unit/journal_test.rb index 3058c714..71aec5ad 100644 --- a/test/unit/journal_test.rb +++ b/test/unit/journal_test.rb @@ -21,7 +21,7 @@ class JournalTest < ActiveSupport::TestCase fixtures :issues, :issue_statuses, :journals def setup - @journal = IssueJournal.first + @journal = IssueJournal.find(1) end def test_journalized_is_an_issue From cd73bd714f715d00173aaa1dc39e36bf86ce21fd Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 6 May 2011 14:33:31 -0700 Subject: [PATCH 638/777] [#123] Fix test error due to un-reloaded object daddy objects --- test/unit/issue_nested_set_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/issue_nested_set_test.rb b/test/unit/issue_nested_set_test.rb index 9d1e09b4..3009af45 100644 --- a/test/unit/issue_nested_set_test.rb +++ b/test/unit/issue_nested_set_test.rb @@ -232,13 +232,13 @@ class IssueNestedSetTest < ActiveSupport::TestCase end def test_destroy_child_issue_with_children - root = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'root') - child = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => root.id) - leaf = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'leaf', :parent_issue_id => child.id) + root = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'root').reload + child = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'child', :parent_issue_id => root.id).reload + leaf = Issue.create!(:project_id => 1, :author_id => 2, :tracker_id => 1, :subject => 'leaf', :parent_issue_id => child.id).reload leaf.init_journal(User.find(2)) leaf.subject = 'leaf with journal' leaf.save! - + assert_difference 'Issue.count', -2 do assert_difference 'IssueJournal.count', -3 do Issue.find(child.id).destroy From d29315341dfb679b092a038753bb4432b5443155 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 6 May 2011 15:14:21 -0700 Subject: [PATCH 639/777] [#196 #216 #216] Complete the upgrade to Rails 2.3.11 --- Rakefile | 4 +- config/boot.rb | 63 +++-------------------- config/environments/development.rb | 7 +-- config/initializers/new_rails_defaults.rb | 21 ++++++++ db/seeds.rb | 7 +++ public/422.html | 30 +++++++++++ script/dbconsole | 0 test/performance/browsing_test.rb | 9 ++++ 8 files changed, 79 insertions(+), 62 deletions(-) create mode 100644 config/initializers/new_rails_defaults.rb create mode 100644 db/seeds.rb create mode 100644 public/422.html mode change 100644 => 100755 script/dbconsole create mode 100644 test/performance/browsing_test.rb diff --git a/Rakefile b/Rakefile index cffd19f0..3bb0e859 100644 --- a/Rakefile +++ b/Rakefile @@ -1,5 +1,5 @@ # Add your own tasks in files placed in lib/tasks ending in .rake, -# for example lib/tasks/switchtower.rake, and they will automatically be available to Rake. +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. require(File.join(File.dirname(__FILE__), 'config', 'boot')) @@ -7,4 +7,4 @@ require 'rake' require 'rake/testtask' require 'rake/rdoctask' -require 'tasks/rails' \ No newline at end of file +require 'tasks/rails' diff --git a/config/boot.rb b/config/boot.rb index bb844558..6686664c 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -62,8 +62,12 @@ module Rails gem 'rails' end rescue Gem::LoadError => load_error - $stderr.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) - exit 1 + if load_error.message =~ /Could not find RubyGem rails/ + STDERR.puts %(Missing the Rails #{version} gem. Please `gem install -v=#{version} rails`, update your RAILS_GEM_VERSION setting in config/environment.rb for the Rails version you do have installed, or comment out RAILS_GEM_VERSION to use the latest version installed.) + exit 1 + else + raise + end end class << self @@ -106,60 +110,5 @@ module Rails end end -# TODO: Workaround for #7013 to be removed for 1.2.0 -# Loads i18n 0.4.2 before Rails loads any more recent gem -# 0.5.0 is not compatible with the old interpolation syntax -# Plugins will have to migrate to the new syntax for 1.2.0 -require 'rubygems' -begin - gem 'i18n', '0.4.2' -rescue Gem::LoadError => load_error - $stderr.puts %(Missing the i18n 0.4.2 gem. Please `gem install -v=0.4.2 i18n`) - exit 1 -end - -# TODO: Workaround for rubygems > 1.5 compatibility (#133), to be removed -# for Rails > 2.3.5 -# -# Fixes the deprecation warning about removal of version_requirements for -# rubygems < 1.5 and provide a workaround for rubygems >= 1.5 where that -# method was finally removed. -module Rails - # See lib/gems/1.8/gems/rails-2.3.5/lib/rails/gem_dependency.rb - class GemDependency < Gem::Dependency - def dependencies - return [] if framework_gem? - return [] unless installed? - specification.dependencies.reject do |dependency| - dependency.type == :development - end.map do |dependency| - GemDependency.new(dependency.name, - :requirement => (dependency.respond_to?(:requirement) ? - dependency.requirement : - dependency.version_requirements)) - end - end - - if method_defined?(:requirement) - # rubygem > 1.5 - def requirement - req = super - req unless req == Gem::Requirement.default - end - # bypass passenger error - alias :version_requirements :requirement - else - # rubygem < 1.5 - def requirement - req = version_requirements - req unless req == Gem::Requirement.default - end - end - end -end - -# working around deprecation in RubyGems 1.6 -require 'thread' - # All that for this: Rails.boot! diff --git a/config/environments/development.rb b/config/environments/development.rb index c816f03e..85c9a608 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -3,14 +3,15 @@ # In the development environment your application's code is reloaded on # every request. This slows down response time but is perfect for development # since you don't have to restart the webserver when you make code changes. -config.cache_classes = false +config.cache_classes = false # Log error messages when you accidentally call methods on nil. -config.whiny_nils = true +config.whiny_nils = true # Show full error reports and disable caching config.action_controller.consider_all_requests_local = true +config.action_view.debug_rjs = true config.action_controller.perform_caching = false # Don't care if the mailer can't send -config.action_mailer.raise_delivery_errors = false +config.action_mailer.raise_delivery_errors = false \ No newline at end of file diff --git a/config/initializers/new_rails_defaults.rb b/config/initializers/new_rails_defaults.rb new file mode 100644 index 00000000..0039a3b2 --- /dev/null +++ b/config/initializers/new_rails_defaults.rb @@ -0,0 +1,21 @@ +# Be sure to restart your server when you modify this file. + +# These settings change the behavior of Rails 2 apps and will be defaults +# for Rails 3. You can remove this initializer when Rails 3 is released. + +if defined?(ActiveRecord) + # Include Active Record class name as root for JSON serialized output. + ActiveRecord::Base.include_root_in_json = true + + # Store the full class name (including module namespace) in STI type column. + ActiveRecord::Base.store_full_sti_class = true +end + +ActionController::Routing.generate_best_match = true + +# Use ISO 8601 format for JSON serialized times and dates. +ActiveSupport.use_standard_json_time_format = true + +# Don't escape HTML entities in JSON, leave that for the #json_escape helper. +# if you're including raw json in an HTML page. +ActiveSupport.escape_html_entities_in_json = false diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 00000000..3174d0cb --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,7 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). +# +# Examples: +# +# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }]) +# Major.create(:name => 'Daley', :city => cities.first) diff --git a/public/422.html b/public/422.html new file mode 100644 index 00000000..b54e4a3c --- /dev/null +++ b/public/422.html @@ -0,0 +1,30 @@ + + + + + + + The change you wanted was rejected (422) + + + + + +
    +

    The change you wanted was rejected.

    +

    Maybe you tried to change something you didn't have access to.

    +
    + + \ No newline at end of file diff --git a/script/dbconsole b/script/dbconsole old mode 100644 new mode 100755 diff --git a/test/performance/browsing_test.rb b/test/performance/browsing_test.rb new file mode 100644 index 00000000..4b60558b --- /dev/null +++ b/test/performance/browsing_test.rb @@ -0,0 +1,9 @@ +require 'test_helper' +require 'performance_test_help' + +# Profiling results for each test method are written to tmp/performance. +class BrowsingTest < ActionController::PerformanceTest + def test_homepage + get '/' + end +end From 13de4cc4b0a4b8dff2f6afd99658c0ba2fb75d68 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 6 May 2011 16:38:13 -0700 Subject: [PATCH 640/777] [#383] Fixed failing tests due to a helper method name conflict (to_utf8) Introduced in 1eee7312f60267b0f8e575cc96302812f2dc38a8 --- app/helpers/attachments_helper.rb | 2 +- app/helpers/repositories_helper.rb | 2 +- app/helpers/timelog_helper.rb | 6 ++-- app/views/common/_diff.rhtml | 4 +-- app/views/common/_file.rhtml | 2 +- app/views/repositories/annotate.rhtml | 2 +- test/unit/helpers/repository_helper_test.rb | 34 ++++++++++----------- 7 files changed, 26 insertions(+), 26 deletions(-) diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb index 36797651..0fce8c95 100644 --- a/app/helpers/attachments_helper.rb +++ b/app/helpers/attachments_helper.rb @@ -28,7 +28,7 @@ module AttachmentsHelper end end - def to_utf8(str) + def to_utf8_for_attachments(str) if str.respond_to?(:force_encoding) str.force_encoding('UTF-8') return str if str.valid_encoding? diff --git a/app/helpers/repositories_helper.rb b/app/helpers/repositories_helper.rb index c8f6e8bf..a007def0 100644 --- a/app/helpers/repositories_helper.rb +++ b/app/helpers/repositories_helper.rb @@ -116,7 +116,7 @@ module RepositoriesHelper output end - def to_utf8(str) + def to_utf8_for_repositories(str) return str if str.nil? str = to_utf8_internal(str) if str.respond_to?(:force_encoding) diff --git a/app/helpers/timelog_helper.rb b/app/helpers/timelog_helper.rb index d314a96f..1fad5fe5 100644 --- a/app/helpers/timelog_helper.rb +++ b/app/helpers/timelog_helper.rb @@ -144,7 +144,7 @@ module TimelogHelper headers = criterias.collect {|criteria| l(@available_criterias[criteria][:label]) } headers += periods headers << l(:label_total) - csv << headers.collect {|c| to_utf8(c) } + csv << headers.collect {|c| to_utf8_for_timelogs(c) } # Content report_criteria_to_csv(csv, criterias, periods, hours) # Total row @@ -166,7 +166,7 @@ module TimelogHelper hours_for_value = select_hours(hours, criterias[level], value) next if hours_for_value.empty? row = [''] * level - row << to_utf8(format_criteria_value(criterias[level], value)) + row << to_utf8_for_timelogs(format_criteria_value(criterias[level], value)) row += [''] * (criterias.length - level - 1) total = 0 periods.each do |period| @@ -183,7 +183,7 @@ module TimelogHelper end end - def to_utf8(s) + def to_utf8_for_timelogs(s) @ic ||= Iconv.new(l(:general_csv_encoding), 'UTF-8') begin; @ic.iconv(s.to_s); rescue; s.to_s; end end diff --git a/app/views/common/_diff.rhtml b/app/views/common/_diff.rhtml index 03b06a0c..f7f40fb0 100644 --- a/app/views/common/_diff.rhtml +++ b/app/views/common/_diff.rhtml @@ -31,7 +31,7 @@ <% else -%> - + <% table_file.each_line do |spacing, line| %> @@ -44,7 +44,7 @@ <% end -%> diff --git a/app/views/common/_file.rhtml b/app/views/common/_file.rhtml index 13ad8bbd..6394268c 100644 --- a/app/views/common/_file.rhtml +++ b/app/views/common/_file.rhtml @@ -2,7 +2,7 @@
    <%=to_utf8 table_file.file_name %>
    <%=to_utf8_for_attachments table_file.file_name %>
    <%= line.nb_line_left %> <%= line.nb_line_right %> -
    <%=to_utf8 line.html_line %>
    +
    <%=to_utf8_for_attachments line.html_line %>
    <% line_num = 1 %> -<% syntax_highlight(filename, to_utf8(content)).each_line do |line| %> +<% syntax_highlight(filename, to_utf8_for_attachments(content)).each_line do |line| %> <% line_num += 1 %> <% end %> diff --git a/app/views/repositories/annotate.rhtml b/app/views/repositories/annotate.rhtml index 49850714..4a2244b6 100644 --- a/app/views/repositories/annotate.rhtml +++ b/app/views/repositories/annotate.rhtml @@ -14,7 +14,7 @@
    <%= line_num %>
    <%= line %>
    <% line_num = 1 %> - <% syntax_highlight(@path, to_utf8(@annotate.content)).each_line do |line| %> + <% syntax_highlight(@path, to_utf8_for_repositories(@annotate.content)).each_line do |line| %> <% revision = @annotate.revisions[line_num-1] %> diff --git a/test/unit/helpers/repository_helper_test.rb b/test/unit/helpers/repository_helper_test.rb index 23067ea5..ad8c4706 100644 --- a/test/unit/helpers/repository_helper_test.rb +++ b/test/unit/helpers/repository_helper_test.rb @@ -20,7 +20,7 @@ require File.expand_path('../../../test_helper', __FILE__) class RepositoryHelperTest < HelperTestCase include RepositoriesHelper - def test_from_latin1_to_utf8 + def test_from_latin1_to_utf8_for_repositories with_settings :repositories_encodings => 'UTF-8,ISO-8859-1' do s1 = "Texte encod\xc3\xa9" s2 = "Texte encod\xe9" @@ -30,12 +30,12 @@ class RepositoryHelperTest < HelperTestCase s2.force_encoding("ASCII-8BIT") s3.force_encoding("UTF-8") end - assert_equal s1, to_utf8(s2) - assert_equal s1, to_utf8(s3) + assert_equal s1, to_utf8_for_repositories(s2) + assert_equal s1, to_utf8_for_repositories(s3) end end - def test_from_euc_jp_to_utf8 + def test_from_euc_jp_to_utf8_for_repositories with_settings :repositories_encodings => 'UTF-8,EUC-JP' do s1 = "\xe3\x83\xac\xe3\x83\x83\xe3\x83\x89\xe3\x83\x9e\xe3\x82\xa4\xe3\x83\xb3" s2 = "\xa5\xec\xa5\xc3\xa5\xc9\xa5\xde\xa5\xa4\xa5\xf3" @@ -45,12 +45,12 @@ class RepositoryHelperTest < HelperTestCase s2.force_encoding("ASCII-8BIT") s3.force_encoding("UTF-8") end - assert_equal s1, to_utf8(s2) - assert_equal s1, to_utf8(s3) + assert_equal s1, to_utf8_for_repositories(s2) + assert_equal s1, to_utf8_for_repositories(s3) end end - def test_to_utf8_should_be_converted_all_latin1_to_utf8 + def test_to_utf8_for_repositories_should_be_converted_all_latin1_to_utf8 with_settings :repositories_encodings => 'ISO-8859-1' do s1 = "\xc3\x82\xc2\x80" s2 = "\xC2\x80" @@ -60,25 +60,25 @@ class RepositoryHelperTest < HelperTestCase s2.force_encoding("ASCII-8BIT") s3.force_encoding("UTF-8") end - assert_equal s1, to_utf8(s2) - assert_equal s1, to_utf8(s3) + assert_equal s1, to_utf8_for_repositories(s2) + assert_equal s1, to_utf8_for_repositories(s3) end end - def test_to_utf8_blank_string - assert_equal "", to_utf8("") - assert_equal nil, to_utf8(nil) + def test_to_utf8_for_repositories_blank_string + assert_equal "", to_utf8_for_repositories("") + assert_equal nil, to_utf8_for_repositories(nil) end - def test_to_utf8_returns_ascii_as_utf8 + def test_to_utf8_for_repositories_returns_ascii_as_utf8 s1 = "ASCII" s2 = s1.dup if s1.respond_to?(:force_encoding) s1.force_encoding("UTF-8") s2.force_encoding("ISO-8859-1") end - str1 = to_utf8(s1) - str2 = to_utf8(s2) + str1 = to_utf8_for_repositories(s1) + str2 = to_utf8_for_repositories(s2) assert_equal s1, str1 assert_equal s1, str2 if s1.respond_to?(:force_encoding) @@ -87,10 +87,10 @@ class RepositoryHelperTest < HelperTestCase end end - def test_to_utf8_invalid_utf8_sequences_should_be_stripped + def test_to_utf8_for_repositories_invalid_utf8_sequences_should_be_stripped with_settings :repositories_encodings => '' do s1 = File.read("#{RAILS_ROOT}/test/fixtures/encoding/iso-8859-1.txt") - str = to_utf8(s1) + str = to_utf8_for_repositories(s1) if str.respond_to?(:force_encoding) assert_equal "Texte encod? en ISO-8859-1.", str assert str.valid_encoding? From 87d8634b04ee38d6b1541889600905ee0d9fb9c1 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Fri, 18 Mar 2011 21:25:45 +0100 Subject: [PATCH 641/777] [#290] using bundler * following setup instructions from http://gembundler.com/rails23.html * adding generated files to .gitignore and .hgignore * removing config.gem calls * adding Gemfile that should work with all supported dbs and interpreters * removing work-around for rubygems 1.5 deprecation. this seems to be fixed since now bundler handles the gem loading --- .gitignore | 2 ++ .hgignore | 3 ++ Gemfile | 64 +++++++++++++++++++++++++++++++++++++ config/boot.rb | 9 ++++++ config/environment.rb | 5 +-- config/environments/test.rb | 4 --- config/preinitializer.rb | 20 ++++++++++++ 7 files changed, 99 insertions(+), 8 deletions(-) create mode 100644 Gemfile create mode 100644 config/preinitializer.rb diff --git a/.gitignore b/.gitignore index f4461f60..1b6527d6 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ /vendor/rails *.rbc doc/app +/.bundle +/Gemfile.lock diff --git a/.hgignore b/.hgignore index e407dd69..bfe73cfc 100644 --- a/.hgignore +++ b/.hgignore @@ -27,3 +27,6 @@ vendor/rails *.rbc .svn/ .git/ +doc/app +/.bundle +/Gemfile.lock diff --git a/Gemfile b/Gemfile new file mode 100644 index 00000000..eb961436 --- /dev/null +++ b/Gemfile @@ -0,0 +1,64 @@ +source :rubygems + +gem "rails", "2.3.11" + +gem "coderay", "~> 0.9.7" +gem "i18n", "< 0.5" # explicit version 0.4.2 is used in config! +gem "ruby-openid" +gem "rubytree", "~> 0.5.2", :require => 'tree' + +group :development, :test do + gem 'edavis10-object_daddy', :require => 'object_daddy' + gem 'mocha' + gem 'shoulda', '~> 2.10.3' +end + + +# Use the commented pure ruby gems, if you have not the needed prerequisites on +# board to compile the native ones. Note, that their use is discouraged, since +# their integration is propbably not that well tested and their are slower in +# orders of magnitude compared to their native counterparts. You have been +# warned. +# +platforms :mri do + group :mysql do + gem "mysql" + # gem "ruby-mysql" + end + + group :mysql2 do + gem "mysql2" + end + + group :postgres do + gem "pg", "~> 0.9.0" + # gem "postgres-pr" + end + + group :sqlite do + gem "sqlite3-ruby", "< 1.3", :require => "sqlite3" + # please tell me, if you are fond of a pure ruby sqlite3 binding + end +end + +platforms :jruby do + gem "jruby-openssl" + + group :mysql do + gem "activerecord-jdbcmysql-adapter" + end + + group :postgres do + gem "activerecord-jdbcpostgresql-adapter" + end + + group :sqlite do + gem "activerecord-jdbcsqlite3-adapter" + end +end + +# Load plugins' Gemfiles +Dir.glob File.expand_path("../vendor/plugins/*/Gemfile", __FILE__) do |file| + puts "Loading #{file} ..." + instance_eval File.read(file) +end diff --git a/config/boot.rb b/config/boot.rb index 6686664c..b5869a8c 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -36,6 +36,15 @@ module Rails class Boot def run load_initializer + + # This block was added for bundler support while following setup + # instructions from http://gembundler.com/rails23.html + Rails::Initializer.class_eval do + def load_gems + @bundler_loaded ||= Bundler.require :default, Rails.env + end + end + Rails::Initializer.run(:set_load_path) end end diff --git a/config/environment.rb b/config/environment.rb index 00e81517..0fa17409 100644 --- a/config/environment.rb +++ b/config/environment.rb @@ -50,11 +50,8 @@ Rails::Initializer.run do |config| # It will automatically turn deliveries on config.action_mailer.perform_deliveries = false - config.gem 'rubytree', :lib => 'tree' - config.gem 'coderay', :version => '~>0.9.7' - # Load any local configuration that is kept out of source control - # (e.g. gems, patches). + # (e.g. patches). if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb')) instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb')) end diff --git a/config/environments/test.rb b/config/environments/test.rb index 79ee6af9..4ce45527 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -23,7 +23,3 @@ config.action_controller.session = { # Skip protect_from_forgery in requests http://m.onkey.org/2007/9/28/csrf-protection-for-your-existing-rails-application config.action_controller.allow_forgery_protection = false - -config.gem "shoulda", :version => "~> 2.10.3" -config.gem "edavis10-object_daddy", :lib => "object_daddy" -config.gem "mocha" diff --git a/config/preinitializer.rb b/config/preinitializer.rb new file mode 100644 index 00000000..3ad02415 --- /dev/null +++ b/config/preinitializer.rb @@ -0,0 +1,20 @@ +begin + require "rubygems" + require "bundler" +rescue LoadError + raise "Could not load the bundler gem. Install it with `gem install bundler`." +end + +if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.24") + raise RuntimeError, "Your bundler version is too old for Rails 2.3." + + "Run `gem install bundler` to upgrade." +end + +begin + # Set up load paths for all bundled gems + ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__) + Bundler.setup +rescue Bundler::GemNotFound + raise RuntimeError, "Bundler couldn't find some gems." + + "Did you run `bundle install`?" +end From ec569be5071d3c81c5d55322f09a5ae58873e16a Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Fri, 18 Mar 2011 21:26:29 +0100 Subject: [PATCH 642/777] [#290] ignoring .rvmrc files --- .gitignore | 1 + .hgignore | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 1b6527d6..6f7528fc 100644 --- a/.gitignore +++ b/.gitignore @@ -26,3 +26,4 @@ doc/app /.bundle /Gemfile.lock +/.rvmrc* diff --git a/.hgignore b/.hgignore index bfe73cfc..307d49af 100644 --- a/.hgignore +++ b/.hgignore @@ -30,3 +30,4 @@ vendor/rails doc/app /.bundle /Gemfile.lock +/.rvmrc* From 2ec21614fd189fdfdc4087e154ea2e83f50ad34c Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Fri, 18 Mar 2011 21:59:29 +0100 Subject: [PATCH 643/777] [#290] Removing all vendored gems --- vendor/gems/coderay-0.9.7/.specification | 155 -- vendor/gems/coderay-0.9.7/FOLDERS | 53 - vendor/gems/coderay-0.9.7/LICENSE | 504 ---- vendor/gems/coderay-0.9.7/Rakefile | 35 - vendor/gems/coderay-0.9.7/bin/coderay | 86 - .../gems/coderay-0.9.7/bin/coderay_stylesheet | 4 - vendor/gems/coderay-0.9.7/lib/README | 134 - vendor/gems/coderay-0.9.7/lib/coderay.rb | 322 --- vendor/gems/coderay-0.9.7/lib/coderay/duo.rb | 85 - .../gems/coderay-0.9.7/lib/coderay/encoder.rb | 213 -- .../lib/coderay/encoders/_map.rb | 12 - .../lib/coderay/encoders/comment_filter.rb | 43 - .../lib/coderay/encoders/count.rb | 21 - .../lib/coderay/encoders/debug.rb | 49 - .../coderay-0.9.7/lib/coderay/encoders/div.rb | 19 - .../lib/coderay/encoders/filter.rb | 75 - .../lib/coderay/encoders/html.rb | 309 --- .../lib/coderay/encoders/html/css.rb | 70 - .../lib/coderay/encoders/html/numerization.rb | 133 - .../lib/coderay/encoders/html/output.rb | 206 -- .../lib/coderay/encoders/json.rb | 69 - .../lib/coderay/encoders/lines_of_code.rb | 90 - .../lib/coderay/encoders/null.rb | 26 - .../lib/coderay/encoders/page.rb | 20 - .../lib/coderay/encoders/span.rb | 19 - .../lib/coderay/encoders/statistic.rb | 77 - .../lib/coderay/encoders/term.rb | 158 -- .../lib/coderay/encoders/text.rb | 32 - .../coderay/encoders/token_class_filter.rb | 84 - .../coderay-0.9.7/lib/coderay/encoders/xml.rb | 71 - .../lib/coderay/encoders/yaml.rb | 22 - .../coderay-0.9.7/lib/coderay/for_redcloth.rb | 95 - .../lib/coderay/helpers/file_type.rb | 255 -- .../lib/coderay/helpers/gzip_simple.rb | 123 - .../lib/coderay/helpers/plugin.rb | 349 --- .../lib/coderay/helpers/word_list.rb | 138 - .../gems/coderay-0.9.7/lib/coderay/scanner.rb | 298 --- .../lib/coderay/scanners/_map.rb | 23 - .../coderay-0.9.7/lib/coderay/scanners/c.rb | 203 -- .../coderay-0.9.7/lib/coderay/scanners/cpp.rb | 228 -- .../coderay-0.9.7/lib/coderay/scanners/css.rb | 209 -- .../lib/coderay/scanners/debug.rb | 62 - .../lib/coderay/scanners/delphi.rb | 150 -- .../lib/coderay/scanners/diff.rb | 110 - .../lib/coderay/scanners/groovy.rb | 264 -- .../lib/coderay/scanners/html.rb | 182 -- .../lib/coderay/scanners/java.rb | 176 -- .../coderay/scanners/java/builtin_types.rb | 419 --- .../lib/coderay/scanners/java_script-0.9.6.rb | 224 -- .../lib/coderay/scanners/java_script.rb | 224 -- .../lib/coderay/scanners/json.rb | 108 - .../lib/coderay/scanners/nitro_xhtml.rb | 136 - .../coderay-0.9.7/lib/coderay/scanners/php.rb | 533 ---- .../lib/coderay/scanners/plaintext.rb | 21 - .../lib/coderay/scanners/python.rb | 285 -- .../lib/coderay/scanners/rhtml.rb | 78 - .../lib/coderay/scanners/ruby.rb | 444 ---- .../lib/coderay/scanners/ruby/patterns.rb | 252 -- .../lib/coderay/scanners/scheme.rb | 145 - .../coderay-0.9.7/lib/coderay/scanners/sql.rb | 162 -- .../coderay-0.9.7/lib/coderay/scanners/xml.rb | 17 - .../lib/coderay/scanners/yaml.rb | 140 - .../gems/coderay-0.9.7/lib/coderay/style.rb | 20 - .../coderay-0.9.7/lib/coderay/styles/_map.rb | 7 - .../lib/coderay/styles/cycnus.rb | 152 -- .../lib/coderay/styles/murphy.rb | 134 - .../lib/coderay/token_classes.rb | 86 - .../gems/coderay-0.9.7/lib/coderay/tokens.rb | 390 --- .../coderay-0.9.7/test/functional/basic.rb | 122 - .../coderay-0.9.7/test/functional/basic.rbc | 2022 -------------- .../test/functional/for_redcloth.rb | 77 - .../test/functional/for_redcloth.rbc | 1708 ------------ .../test/functional/load_plugin_scanner.rb | 11 - .../test/functional/load_plugin_scanner.rbc | 317 --- .../coderay-0.9.7/test/functional/suite.rb | 12 - .../coderay-0.9.7/test/functional/suite.rbc | 322 --- .../coderay-0.9.7/test/functional/vhdl.rb | 126 - .../coderay-0.9.7/test/functional/vhdl.rbc | 2334 ----------------- .../test/functional/word_list.rb | 79 - .../test/functional/word_list.rbc | 1763 ------------- vendor/gems/rubytree-0.5.2/.specification | 80 - vendor/gems/rubytree-0.5.2/COPYING | 31 - vendor/gems/rubytree-0.5.2/ChangeLog | 163 -- vendor/gems/rubytree-0.5.2/History.txt | 20 - vendor/gems/rubytree-0.5.2/Manifest.txt | 12 - vendor/gems/rubytree-0.5.2/README | 147 -- vendor/gems/rubytree-0.5.2/Rakefile | 212 -- vendor/gems/rubytree-0.5.2/TODO | 7 - vendor/gems/rubytree-0.5.2/lib/tree.rb | 539 ---- .../rubytree-0.5.2/lib/tree/binarytree.rb | 131 - vendor/gems/rubytree-0.5.2/setup.rb | 1585 ----------- .../rubytree-0.5.2/test/test_binarytree.rb | 204 -- vendor/gems/rubytree-0.5.2/test/test_tree.rb | 718 ----- 93 files changed, 22780 deletions(-) delete mode 100644 vendor/gems/coderay-0.9.7/.specification delete mode 100644 vendor/gems/coderay-0.9.7/FOLDERS delete mode 100644 vendor/gems/coderay-0.9.7/LICENSE delete mode 100644 vendor/gems/coderay-0.9.7/Rakefile delete mode 100644 vendor/gems/coderay-0.9.7/bin/coderay delete mode 100644 vendor/gems/coderay-0.9.7/bin/coderay_stylesheet delete mode 100644 vendor/gems/coderay-0.9.7/lib/README delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/duo.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoder.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/_map.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/comment_filter.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/count.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/debug.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/div.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/filter.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/html.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/css.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/numerization.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/output.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/json.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/lines_of_code.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/null.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/page.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/span.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/statistic.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/term.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/text.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/token_class_filter.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/xml.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/encoders/yaml.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/for_redcloth.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/helpers/file_type.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/helpers/gzip_simple.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/helpers/plugin.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/helpers/word_list.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanner.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/_map.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/c.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/cpp.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/css.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/debug.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/delphi.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/diff.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/groovy.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/html.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/java.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/java/builtin_types.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script-0.9.6.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/json.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/nitro_xhtml.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/php.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/plaintext.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/python.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/rhtml.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby/patterns.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/scheme.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/sql.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/xml.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/scanners/yaml.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/style.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/styles/_map.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/styles/cycnus.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/styles/murphy.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/token_classes.rb delete mode 100644 vendor/gems/coderay-0.9.7/lib/coderay/tokens.rb delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/basic.rb delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/basic.rbc delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rb delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rbc delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rb delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rbc delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/suite.rb delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/suite.rbc delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/vhdl.rb delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/vhdl.rbc delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/word_list.rb delete mode 100644 vendor/gems/coderay-0.9.7/test/functional/word_list.rbc delete mode 100644 vendor/gems/rubytree-0.5.2/.specification delete mode 100644 vendor/gems/rubytree-0.5.2/COPYING delete mode 100644 vendor/gems/rubytree-0.5.2/ChangeLog delete mode 100644 vendor/gems/rubytree-0.5.2/History.txt delete mode 100644 vendor/gems/rubytree-0.5.2/Manifest.txt delete mode 100644 vendor/gems/rubytree-0.5.2/README delete mode 100644 vendor/gems/rubytree-0.5.2/Rakefile delete mode 100644 vendor/gems/rubytree-0.5.2/TODO delete mode 100644 vendor/gems/rubytree-0.5.2/lib/tree.rb delete mode 100644 vendor/gems/rubytree-0.5.2/lib/tree/binarytree.rb delete mode 100644 vendor/gems/rubytree-0.5.2/setup.rb delete mode 100644 vendor/gems/rubytree-0.5.2/test/test_binarytree.rb delete mode 100644 vendor/gems/rubytree-0.5.2/test/test_tree.rb diff --git a/vendor/gems/coderay-0.9.7/.specification b/vendor/gems/coderay-0.9.7/.specification deleted file mode 100644 index 03cf3ec2..00000000 --- a/vendor/gems/coderay-0.9.7/.specification +++ /dev/null @@ -1,155 +0,0 @@ ---- !ruby/object:Gem::Specification -name: coderay -version: !ruby/object:Gem::Version - hash: 53 - prerelease: false - segments: - - 0 - - 9 - - 7 - version: 0.9.7 -platform: ruby -authors: -- murphy -autorequire: -bindir: bin -cert_chain: [] - -date: 2011-01-15 00:00:00 +01:00 -default_executable: -dependencies: [] - -description: | - Fast and easy syntax highlighting for selected languages, written in Ruby. - Comes with RedCloth integration and LOC counter. - -email: murphy@rubychan.de -executables: -- coderay -- coderay_stylesheet -extensions: [] - -extra_rdoc_files: -- lib/README -- FOLDERS -files: -- ./lib/coderay/duo.rb -- ./lib/coderay/encoder.rb -- ./lib/coderay/encoders/_map.rb -- ./lib/coderay/encoders/comment_filter.rb -- ./lib/coderay/encoders/count.rb -- ./lib/coderay/encoders/debug.rb -- ./lib/coderay/encoders/div.rb -- ./lib/coderay/encoders/filter.rb -- ./lib/coderay/encoders/html/css.rb -- ./lib/coderay/encoders/html/numerization.rb -- ./lib/coderay/encoders/html/output.rb -- ./lib/coderay/encoders/html.rb -- ./lib/coderay/encoders/json.rb -- ./lib/coderay/encoders/lines_of_code.rb -- ./lib/coderay/encoders/null.rb -- ./lib/coderay/encoders/page.rb -- ./lib/coderay/encoders/span.rb -- ./lib/coderay/encoders/statistic.rb -- ./lib/coderay/encoders/term.rb -- ./lib/coderay/encoders/text.rb -- ./lib/coderay/encoders/token_class_filter.rb -- ./lib/coderay/encoders/xml.rb -- ./lib/coderay/encoders/yaml.rb -- ./lib/coderay/for_redcloth.rb -- ./lib/coderay/helpers/file_type.rb -- ./lib/coderay/helpers/gzip_simple.rb -- ./lib/coderay/helpers/plugin.rb -- ./lib/coderay/helpers/word_list.rb -- ./lib/coderay/scanner.rb -- ./lib/coderay/scanners/_map.rb -- ./lib/coderay/scanners/c.rb -- ./lib/coderay/scanners/cpp.rb -- ./lib/coderay/scanners/css.rb -- ./lib/coderay/scanners/debug.rb -- ./lib/coderay/scanners/delphi.rb -- ./lib/coderay/scanners/diff.rb -- ./lib/coderay/scanners/groovy.rb -- ./lib/coderay/scanners/html.rb -- ./lib/coderay/scanners/java/builtin_types.rb -- ./lib/coderay/scanners/java.rb -- ./lib/coderay/scanners/java_script-0.9.6.rb -- ./lib/coderay/scanners/java_script.rb -- ./lib/coderay/scanners/json.rb -- ./lib/coderay/scanners/nitro_xhtml.rb -- ./lib/coderay/scanners/php.rb -- ./lib/coderay/scanners/plaintext.rb -- ./lib/coderay/scanners/python.rb -- ./lib/coderay/scanners/rhtml.rb -- ./lib/coderay/scanners/ruby/patterns.rb -- ./lib/coderay/scanners/ruby.rb -- ./lib/coderay/scanners/scheme.rb -- ./lib/coderay/scanners/sql.rb -- ./lib/coderay/scanners/xml.rb -- ./lib/coderay/scanners/yaml.rb -- ./lib/coderay/style.rb -- ./lib/coderay/styles/_map.rb -- ./lib/coderay/styles/cycnus.rb -- ./lib/coderay/styles/murphy.rb -- ./lib/coderay/token_classes.rb -- ./lib/coderay/tokens.rb -- ./lib/coderay.rb -- ./Rakefile -- ./test/functional/basic.rb -- ./test/functional/basic.rbc -- ./test/functional/for_redcloth.rb -- ./test/functional/for_redcloth.rbc -- ./test/functional/load_plugin_scanner.rb -- ./test/functional/load_plugin_scanner.rbc -- ./test/functional/suite.rb -- ./test/functional/suite.rbc -- ./test/functional/vhdl.rb -- ./test/functional/vhdl.rbc -- ./test/functional/word_list.rb -- ./test/functional/word_list.rbc -- ./lib/README -- ./LICENSE -- lib/README -- FOLDERS -- bin/coderay -- bin/coderay_stylesheet -has_rdoc: true -homepage: http://coderay.rubychan.de -licenses: [] - -post_install_message: -rdoc_options: -- -SNw2 -- -mlib/README -- -t CodeRay Documentation -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 51 - segments: - - 1 - - 8 - - 2 - version: 1.8.2 -required_rubygems_version: !ruby/object:Gem::Requirement - none: false - requirements: - - - ">=" - - !ruby/object:Gem::Version - hash: 3 - segments: - - 0 - version: "0" -requirements: [] - -rubyforge_project: coderay -rubygems_version: 1.3.7 -signing_key: -specification_version: 3 -summary: Fast syntax highlighting for selected languages. -test_files: -- ./test/functional/suite.rb diff --git a/vendor/gems/coderay-0.9.7/FOLDERS b/vendor/gems/coderay-0.9.7/FOLDERS deleted file mode 100644 index 654df137..00000000 --- a/vendor/gems/coderay-0.9.7/FOLDERS +++ /dev/null @@ -1,53 +0,0 @@ -= CodeRay - Trunk folder structure - -== bench - Benchmarking system - -All benchmarking stuff goes here. - -Test inputs are stored in files named example.. -Test outputs go to bench/test.. - -Run bench/bench.rb to get a usage description. - -Run rake bench to perform an example benchmark. - - -== bin - Scripts - -Executional files for CodeRay. - - -== demo - Demos and functional tests - -Demonstrational scripts to show of CodeRay's features. - -Run them as functional tests with rake test:demos. - - -== etc - Lots of stuff - -Some addidtional files for CodeRay, mainly graphics and Vim scripts. - - -== gem_server - Gem output folder - -For rake gem. - - -== lib - CodeRay library code - -This is the base directory for the CodeRay library. - - -== rake_helpers - Rake helper libraries - -Some files to enhance Rake, including the Autumnal Rdoc template and some scripts. - - -== test - Tests - -Tests for the scanners. - -Each language has its own subfolder and sub-suite. - -Run with rake test. diff --git a/vendor/gems/coderay-0.9.7/LICENSE b/vendor/gems/coderay-0.9.7/LICENSE deleted file mode 100644 index c00103de..00000000 --- a/vendor/gems/coderay-0.9.7/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/vendor/gems/coderay-0.9.7/Rakefile b/vendor/gems/coderay-0.9.7/Rakefile deleted file mode 100644 index 05d0144d..00000000 --- a/vendor/gems/coderay-0.9.7/Rakefile +++ /dev/null @@ -1,35 +0,0 @@ -require 'rake/rdoctask' - -ROOT = '.' -LIB_ROOT = File.join ROOT, 'lib' -EXTRA_RDOC_FILES = %w(lib/README FOLDERS) - -task :default => :test - -if File.directory? 'rake_tasks' - - # load rake tasks from subfolder - for task_file in Dir['rake_tasks/*.rake'].sort - load task_file - end - -else - - # fallback tasks when rake_tasks folder is not present - desc 'Run CodeRay tests (basic)' - task :test do - ruby './test/functional/suite.rb' - ruby './test/functional/for_redcloth.rb' - end - - desc 'Generate documentation for CodeRay' - Rake::RDocTask.new :doc do |rd| - rd.title = 'CodeRay Documentation' - rd.main = 'lib/README' - rd.rdoc_files.add Dir['lib'] - rd.rdoc_files.add 'lib/README' - rd.rdoc_files.add 'FOLDERS' - rd.rdoc_dir = 'doc' - end - -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/bin/coderay b/vendor/gems/coderay-0.9.7/bin/coderay deleted file mode 100644 index 62101a83..00000000 --- a/vendor/gems/coderay-0.9.7/bin/coderay +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env ruby -# CodeRay Executable -# -# Version: 0.2 -# Author: murphy - -require 'coderay' - -if ARGV.empty? - $stderr.puts <<-USAGE -CodeRay #{CodeRay::VERSION} (http://coderay.rubychan.de) - -Usage: - coderay file [-] - coderay - [-] [< file] [> output] - -Defaults: - lang: based on file extension - format: ANSI colorized output for terminal, HTML page for files - -Examples: - coderay foo.rb # colorized output to terminal, based on file extension - coderay foo.rb -loc # print LOC count, based on file extension and format - coderay foo.rb > foo.html # HTML page output to file, based on extension - coderay -ruby < foo.rb # colorized output to terminal, based on lang - coderay -ruby -loc < foo.rb # print LOC count, based on lang - coderay -ruby -page foo.rb # HTML page output to terminal, based on lang and format - coderay -ruby -page foo.rb > foo.html # HTML page output to file, based on lang and format - USAGE -end - -first, second = ARGV - -def read - file = ARGV.grep(/^(?!-)/).last - if file - if File.exist?(file) - File.read file - else - $stderr.puts "No such file: #{file}" - end - else - $stdin.read - end -end - -if first - if first[/-(\w+)/] == first - lang = $1 - input = read - tokens = :scan - else - file = first - unless File.exist? file - $stderr.puts "No such file: #{file}" - exit 2 - end - tokens = CodeRay.scan_file file - end -else - $stderr.puts 'No lang/file given.' - exit 1 -end - -if second - if second[/-(\w+)/] == second - format = $1.to_sym - else - raise 'invalid format (must be -xxx)' - end -else - if $stdout.tty? - format = :term - else - $stderr.puts 'No format given; setting to default (HTML Page).' - format = :page - end -end - -if tokens == :scan - output = CodeRay::Duo[lang => format].highlight input -else - output = tokens.encode format -end -out = $stdout -out.puts output diff --git a/vendor/gems/coderay-0.9.7/bin/coderay_stylesheet b/vendor/gems/coderay-0.9.7/bin/coderay_stylesheet deleted file mode 100644 index 0e193952..00000000 --- a/vendor/gems/coderay-0.9.7/bin/coderay_stylesheet +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env ruby -require 'coderay' - -puts CodeRay::Encoders[:html]::CSS.new.stylesheet diff --git a/vendor/gems/coderay-0.9.7/lib/README b/vendor/gems/coderay-0.9.7/lib/README deleted file mode 100644 index c440f30c..00000000 --- a/vendor/gems/coderay-0.9.7/lib/README +++ /dev/null @@ -1,134 +0,0 @@ -= CodeRay - -[- Tired of blue'n'gray? Try the original version of this documentation on -coderay.rubychan.de[http://coderay.rubychan.de/doc/] (use Ctrl+Click to open it in its own frame.) -] - -== About -CodeRay is a Ruby library for syntax highlighting. - -Syntax highlighting means: You put your code in, and you get it back colored; -Keywords, strings, floats, comments - all in different colors. -And with line numbers. - -*Syntax* *Highlighting*... -* makes code easier to read and maintain -* lets you detect syntax errors faster -* helps you to understand the syntax of a language -* looks nice -* is what everybody should have on their website -* solves all your problems and makes the girls run after you - -Version: 0.9.7 -Author:: murphy (Kornelius Kalnbach) -Contact:: murphy rubychan de -Website:: coderay.rubychan.de[http://coderay.rubychan.de] -License:: GNU LGPL; see LICENSE file in the main directory. - -== Installation - -You need RubyGems[http://rubyforge.org/frs/?group_id=126]. - - % gem install coderay - - -=== Dependencies - -CodeRay needs Ruby 1.8.6 or later. It also runs with Ruby 1.9.1+ and JRuby 1.1+. - - -== Example Usage -(Forgive me, but this is not highlighted.) - - require 'coderay' - - tokens = CodeRay.scan "puts 'Hello, world!'", :ruby - page = tokens.html :line_numbers => :inline, :wrap => :page - puts page - - -== Documentation - -See CodeRay. - -Please report errors in this documentation to . - - -== Credits - -=== Special Thanks to - -* licenser (Heinz N. Gies) for ending my QBasic career, inventing the Coder - project and the input/output plugin system. - CodeRay would not exist without him. -* bovi (Daniel Bovensiepen) for helping me out on various occasions. - -=== Thanks to - -* Caleb Clausen for writing RubyLexer (see - http://rubyforge.org/projects/rubylexer) and lots of very interesting mail - traffic -* birkenfeld (Georg Brandl) and mitsuhiku (Arnim Ronacher) for PyKleur, now pygments. - You guys rock! -* Jamis Buck for writing Syntax (see http://rubyforge.org/projects/syntax) - I got some useful ideas from it. -* Doug Kearns and everyone else who worked on ruby.vim - it not only helped me - coding CodeRay, but also gave me a wonderful target to reach for the Ruby - scanner. -* everyone who uses CodeBB on http://www.rubyforen.de and http://www.python-forum.de -* iGEL, magichisoka, manveru, WoNáDo and everyone I forgot from rubyforen.de -* Dethix from ruby-mine.de -* zickzackw -* Dookie (who is no longer with us...) and Leonidas from http://www.python-forum.de -* Andreas Schwarz for finding out that CaseIgnoringWordList was not case - ignoring! Such things really make you write tests. -* closure for the first version of the Scheme scanner. -* Stefan Walk for the first version of the JavaScript and PHP scanners. -* Josh Goebel for another version of the JavaScript scanner, a SQL and a Diff scanner. -* Jonathan Younger for pointing out the licence confusion caused by wrong LICENSE file. -* Jeremy Hinegardner for finding the shebang-on-empty-file bug in FileType. -* Charles Oliver Nutter and Yehuda Katz for helping me benchmark CodeRay on JRuby. -* Andreas Neuhaus for pointing out a markup bug in coderay/for_redcloth. -* 0xf30fc7 for the FileType patch concerning Delphi file extensions. -* The folks at redmine.org - thank you for using and fixing CodeRay! -* Keith Pitt for his SQL scanners -* Rob Aldred for the terminal encoder -* Trans for pointing out $DEBUG dependencies -* Flameeyes for finding that Term::ANSIColor was obsolete -* Etienne Massip for reporting a serious bug in JavaScript scanner -* matz and all Ruby gods and gurus -* The inventors of: the computer, the internet, the true color display, HTML & - CSS, VIM, Ruby, pizza, microwaves, guitars, scouting, programming, anime, - manga, coke and green ice tea. - -Where would we be without all those people? - -=== Created using - -* Ruby[http://ruby-lang.org/] -* Chihiro (my Sony VAIO laptop); Henrietta (my old MacBook); - Triella, born Rico (my new MacBook); as well as - Seras and Hikari (my PCs) -* RDE[http://homepage2.nifty.com/sakazuki/rde_e.html], - VIM[http://vim.org] and TextMate[http://macromates.com] -* Subversion[http://subversion.tigris.org/] -* Redmine[http://redmine.org/] -* Firefox[http://www.mozilla.org/products/firefox/], - Firebug[http://getfirebug.com/], Safari[http://www.apple.com/safari/], and - Thunderbird[http://www.mozilla.org/products/thunderbird/] -* RubyGems[http://docs.rubygems.org/] and Rake[http://rake.rubyforge.org/] -* TortoiseSVN[http://tortoisesvn.tigris.org/] using Apache via - XAMPP[http://www.apachefriends.org/en/xampp.html] -* RDoc (though I'm quite unsatisfied with it) -* Microsoft Windows (yes, I confess!) and MacOS X -* GNUWin32, MinGW and some other tools to make the shell under windows a bit - less useless -* Term::ANSIColor[http://term-ansicolor.rubyforge.org/] -* PLEAC[http://pleac.sourceforge.net/] code examples - -=== Free - -* As you can see, CodeRay was created under heavy use of *free* software. -* So CodeRay is also *free*. -* If you use CodeRay to create software, think about making this software - *free*, too. -* Thanks :) diff --git a/vendor/gems/coderay-0.9.7/lib/coderay.rb b/vendor/gems/coderay-0.9.7/lib/coderay.rb deleted file mode 100644 index 3e2d10b7..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay.rb +++ /dev/null @@ -1,322 +0,0 @@ -# = CodeRay Library -# -# CodeRay is a Ruby library for syntax highlighting. -# -# I try to make CodeRay easy to use and intuitive, but at the same time fully featured, complete, -# fast and efficient. -# -# See README. -# -# It consists mainly of -# * the main engine: CodeRay (Scanners::Scanner, Tokens/TokenStream, Encoders::Encoder), PluginHost -# * the scanners in CodeRay::Scanners -# * the encoders in CodeRay::Encoders -# -# Here's a fancy graphic to light up this gray docu: -# -# http://cycnus.de/raindark/coderay/scheme.png -# -# == Documentation -# -# See CodeRay, Encoders, Scanners, Tokens. -# -# == Usage -# -# Remember you need RubyGems to use CodeRay, unless you have it in your load path. Run Ruby with -# -rubygems option if required. -# -# === Highlight Ruby code in a string as html -# -# require 'coderay' -# print CodeRay.scan('puts "Hello, world!"', :ruby).html -# -# # prints something like this: -# puts "Hello, world!" -# -# -# === Highlight C code from a file in a html div -# -# require 'coderay' -# print CodeRay.scan(File.read('ruby.h'), :c).div -# print CodeRay.scan_file('ruby.h').html.div -# -# You can include this div in your page. The used CSS styles can be printed with -# -# % coderay_stylesheet -# -# === Highlight without typing too much -# -# If you are one of the hasty (or lazy, or extremely curious) people, just run this file: -# -# % ruby -rubygems /path/to/coderay/coderay.rb > example.html -# -# and look at the file it created in your browser. -# -# = CodeRay Module -# -# The CodeRay module provides convenience methods for the engine. -# -# * The +lang+ and +format+ arguments select Scanner and Encoder to use. These are -# simply lower-case symbols, like :python or :html. -# * All methods take an optional hash as last parameter, +options+, that is send to -# the Encoder / Scanner. -# * Input and language are always sorted in this order: +code+, +lang+. -# (This is in alphabetical order, if you need a mnemonic ;) -# -# You should be able to highlight everything you want just using these methods; -# so there is no need to dive into CodeRay's deep class hierarchy. -# -# The examples in the demo directory demonstrate common cases using this interface. -# -# = Basic Access Ways -# -# Read this to get a general view what CodeRay provides. -# -# == Scanning -# -# Scanning means analysing an input string, splitting it up into Tokens. -# Each Token knows about what type it is: string, comment, class name, etc. -# -# Each +lang+ (language) has its own Scanner; for example, :ruby code is -# handled by CodeRay::Scanners::Ruby. -# -# CodeRay.scan:: Scan a string in a given language into Tokens. -# This is the most common method to use. -# CodeRay.scan_file:: Scan a file and guess the language using FileType. -# -# The Tokens object you get from these methods can encode itself; see Tokens. -# -# == Encoding -# -# Encoding means compiling Tokens into an output. This can be colored HTML or -# LaTeX, a textual statistic or just the number of non-whitespace tokens. -# -# Each Encoder provides output in a specific +format+, so you select Encoders via -# formats like :html or :statistic. -# -# CodeRay.encode:: Scan and encode a string in a given language. -# CodeRay.encode_tokens:: Encode the given tokens. -# CodeRay.encode_file:: Scan a file, guess the language using FileType and encode it. -# -# == Streaming -# -# Streaming saves RAM by running Scanner and Encoder in some sort of -# pipe mode; see TokenStream. -# -# CodeRay.scan_stream:: Scan in stream mode. -# -# == All-in-One Encoding -# -# CodeRay.encode:: Highlight a string with a given input and output format. -# -# == Instanciating -# -# You can use an Encoder instance to highlight multiple inputs. This way, the setup -# for this Encoder must only be done once. -# -# CodeRay.encoder:: Create an Encoder instance with format and options. -# CodeRay.scanner:: Create an Scanner instance for lang, with '' as default code. -# -# To make use of CodeRay.scanner, use CodeRay::Scanner::code=. -# -# The scanning methods provide more flexibility; we recommend to use these. -# -# == Reusing Scanners and Encoders -# -# If you want to re-use scanners and encoders (because that is faster), see -# CodeRay::Duo for the most convenient (and recommended) interface. -module CodeRay - - $CODERAY_DEBUG ||= false - - # Version: Major.Minor.Teeny[.Revision] - # Major: 0 for pre-stable, 1 for stable - # Minor: feature milestone - # Teeny: development state, 0 for pre-release - # Revision: Subversion Revision number (generated on rake gem:make) - VERSION = '0.9.7' - - require 'coderay/tokens' - require 'coderay/token_classes' - require 'coderay/scanner' - require 'coderay/encoder' - require 'coderay/duo' - require 'coderay/style' - - - class << self - - # Scans the given +code+ (a String) with the Scanner for +lang+. - # - # This is a simple way to use CodeRay. Example: - # require 'coderay' - # page = CodeRay.scan("puts 'Hello, world!'", :ruby).html - # - # See also demo/demo_simple. - def scan code, lang, options = {}, &block - scanner = Scanners[lang].new code, options, &block - scanner.tokenize - end - - # Scans +filename+ (a path to a code file) with the Scanner for +lang+. - # - # If +lang+ is :auto or omitted, the CodeRay::FileType module is used to - # determine it. If it cannot find out what type it is, it uses - # CodeRay::Scanners::Plaintext. - # - # Calls CodeRay.scan. - # - # Example: - # require 'coderay' - # page = CodeRay.scan_file('some_c_code.c').html - def scan_file filename, lang = :auto, options = {}, &block - file = IO.read filename - if lang == :auto - require 'coderay/helpers/file_type' - lang = FileType.fetch filename, :plaintext, true - end - scan file, lang, options = {}, &block - end - - # Scan the +code+ (a string) with the scanner for +lang+. - # - # Calls scan. - # - # See CodeRay.scan. - def scan_stream code, lang, options = {}, &block - options[:stream] = true - scan code, lang, options, &block - end - - # Encode a string in Streaming mode. - # - # This starts scanning +code+ with the the Scanner for +lang+ - # while encodes the output with the Encoder for +format+. - # +options+ will be passed to the Encoder. - # - # See CodeRay::Encoder.encode_stream - def encode_stream code, lang, format, options = {} - encoder(format, options).encode_stream code, lang, options - end - - # Encode a string. - # - # This scans +code+ with the the Scanner for +lang+ and then - # encodes it with the Encoder for +format+. - # +options+ will be passed to the Encoder. - # - # See CodeRay::Encoder.encode - def encode code, lang, format, options = {} - encoder(format, options).encode code, lang, options - end - - # Highlight a string into a HTML
    . - # - # CSS styles use classes, so you have to include a stylesheet - # in your output. - # - # See encode. - def highlight code, lang, options = { :css => :class }, format = :div - encode code, lang, format, options - end - - # Encode pre-scanned Tokens. - # Use this together with CodeRay.scan: - # - # require 'coderay' - # - # # Highlight a short Ruby code example in a HTML span - # tokens = CodeRay.scan '1 + 2', :ruby - # puts CodeRay.encode_tokens(tokens, :span) - # - def encode_tokens tokens, format, options = {} - encoder(format, options).encode_tokens tokens, options - end - - # Encodes +filename+ (a path to a code file) with the Scanner for +lang+. - # - # See CodeRay.scan_file. - # Notice that the second argument is the output +format+, not the input language. - # - # Example: - # require 'coderay' - # page = CodeRay.encode_file 'some_c_code.c', :html - def encode_file filename, format, options = {} - tokens = scan_file filename, :auto, get_scanner_options(options) - encode_tokens tokens, format, options - end - - # Highlight a file into a HTML
    . - # - # CSS styles use classes, so you have to include a stylesheet - # in your output. - # - # See encode. - def highlight_file filename, options = { :css => :class }, format = :div - encode_file filename, format, options - end - - # Finds the Encoder class for +format+ and creates an instance, passing - # +options+ to it. - # - # Example: - # require 'coderay' - # - # stats = CodeRay.encoder(:statistic) - # stats.encode("puts 17 + 4\n", :ruby) - # - # puts '%d out of %d tokens have the kind :integer.' % [ - # stats.type_stats[:integer].count, - # stats.real_token_count - # ] - # #-> 2 out of 4 tokens have the kind :integer. - def encoder format, options = {} - Encoders[format].new options - end - - # Finds the Scanner class for +lang+ and creates an instance, passing - # +options+ to it. - # - # See Scanner.new. - def scanner lang, options = {} - Scanners[lang].new '', options - end - - # Extract the options for the scanner from the +options+ hash. - # - # Returns an empty Hash if :scanner_options is not set. - # - # This is used if a method like CodeRay.encode has to provide options - # for Encoder _and_ scanner. - def get_scanner_options options - options.fetch :scanner_options, {} - end - - end - - # This Exception is raised when you try to stream with something that is not - # capable of streaming. - class NotStreamableError < Exception - def initialize obj - @obj = obj - end - - def to_s - '%s is not Streamable!' % @obj.class - end - end - - # A dummy module that is included by subclasses of CodeRay::Scanner an CodeRay::Encoder - # to show that they are able to handle streams. - module Streamable - end - -end - -# Run a test script. -if $0 == __FILE__ - $stderr.print 'Press key to print demo.'; gets - # Just use this file as an example of Ruby code. - code = File.read(__FILE__)[/module CodeRay.*/m] - print CodeRay.scan(code, :ruby).html -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/duo.rb b/vendor/gems/coderay-0.9.7/lib/coderay/duo.rb deleted file mode 100644 index 5468dda8..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/duo.rb +++ /dev/null @@ -1,85 +0,0 @@ -module CodeRay - - # = Duo - # - # A Duo is a convenient way to use CodeRay. You just create a Duo, - # giving it a lang (language of the input code) and a format (desired - # output format), and call Duo#highlight with the code. - # - # Duo makes it easy to re-use both scanner and encoder for a repetitive - # task. It also provides a very easy interface syntax: - # - # require 'coderay' - # CodeRay::Duo[:python, :div].highlight 'import this' - # - # Until you want to do uncommon things with CodeRay, I recommend to use - # this method, since it takes care of everything. - class Duo - - attr_accessor :lang, :format, :options - - # Create a new Duo, holding a lang and a format to highlight code. - # - # simple: - # CodeRay::Duo[:ruby, :page].highlight 'bla 42' - # - # streaming: - # CodeRay::Duo[:ruby, :page].highlight 'bar 23', :stream => true - # - # with options: - # CodeRay::Duo[:ruby, :html, :hint => :debug].highlight '????::??' - # - # alternative syntax without options: - # CodeRay::Duo[:ruby => :statistic].encode 'class << self; end' - # - # alternative syntax with options: - # CodeRay::Duo[{ :ruby => :statistic }, :do => :something].encode 'abc' - # - # The options are forwarded to scanner and encoder - # (see CodeRay.get_scanner_options). - def initialize lang = nil, format = nil, options = {} - if format == nil and lang.is_a? Hash and lang.size == 1 - @lang = lang.keys.first - @format = lang[@lang] - else - @lang = lang - @format = format - end - @options = options - end - - class << self - # To allow calls like Duo[:ruby, :html].highlight. - alias [] new - end - - # The scanner of the duo. Only created once. - def scanner - @scanner ||= CodeRay.scanner @lang, CodeRay.get_scanner_options(@options) - end - - # The encoder of the duo. Only created once. - def encoder - @encoder ||= CodeRay.encoder @format, @options - end - - # Tokenize and highlight the code using +scanner+ and +encoder+. - # - # If the :stream option is set, the Duo will go into streaming mode, - # saving memory for the cost of time. - def encode code, options = { :stream => false } - stream = options.delete :stream - options = @options.merge options - if stream - encoder.encode_stream(code, @lang, options) - else - scanner.code = code - encoder.encode_tokens(scanner.tokenize, options) - end - end - alias highlight encode - - end - -end - diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoder.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoder.rb deleted file mode 100644 index 3ae29244..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoder.rb +++ /dev/null @@ -1,213 +0,0 @@ -module CodeRay - - # This module holds the Encoder class and its subclasses. - # For example, the HTML encoder is named CodeRay::Encoders::HTML - # can be found in coderay/encoders/html. - # - # Encoders also provides methods and constants for the register - # mechanism and the [] method that returns the Encoder class - # belonging to the given format. - module Encoders - extend PluginHost - plugin_path File.dirname(__FILE__), 'encoders' - - # = Encoder - # - # The Encoder base class. Together with Scanner and - # Tokens, it forms the highlighting triad. - # - # Encoder instances take a Tokens object and do something with it. - # - # The most common Encoder is surely the HTML encoder - # (CodeRay::Encoders::HTML). It highlights the code in a colorful - # html page. - # If you want the highlighted code in a div or a span instead, - # use its subclasses Div and Span. - class Encoder - extend Plugin - plugin_host Encoders - - attr_reader :token_stream - - class << self - - # Returns if the Encoder can be used in streaming mode. - def streamable? - is_a? Streamable - end - - # If FILE_EXTENSION isn't defined, this method returns the - # downcase class name instead. - def const_missing sym - if sym == :FILE_EXTENSION - plugin_id - else - super - end - end - - end - - # Subclasses are to store their default options in this constant. - DEFAULT_OPTIONS = { :stream => false } - - # The options you gave the Encoder at creating. - attr_accessor :options - - # Creates a new Encoder. - # +options+ is saved and used for all encode operations, as long - # as you don't overwrite it there by passing additional options. - # - # Encoder objects provide three encode methods: - # - encode simply takes a +code+ string and a +lang+ - # - encode_tokens expects a +tokens+ object instead - # - encode_stream is like encode, but uses streaming mode. - # - # Each method has an optional +options+ parameter. These are - # added to the options you passed at creation. - def initialize options = {} - @options = self.class::DEFAULT_OPTIONS.merge options - raise "I am only the basic Encoder class. I can't encode "\ - "anything. :( Use my subclasses." if self.class == Encoder - end - - # Encode a Tokens object. - def encode_tokens tokens, options = {} - options = @options.merge options - setup options - compile tokens, options - finish options - end - - # Encode the given +code+ after tokenizing it using the Scanner - # for +lang+. - def encode code, lang, options = {} - options = @options.merge options - scanner_options = CodeRay.get_scanner_options(options) - tokens = CodeRay.scan code, lang, scanner_options - encode_tokens tokens, options - end - - # You can use highlight instead of encode, if that seems - # more clear to you. - alias highlight encode - - # Encode the given +code+ using the Scanner for +lang+ in - # streaming mode. - def encode_stream code, lang, options = {} - raise NotStreamableError, self unless kind_of? Streamable - options = @options.merge options - setup options - scanner_options = CodeRay.get_scanner_options options - @token_stream = - CodeRay.scan_stream code, lang, scanner_options, &self - finish options - end - - # Behave like a proc. The token method is converted to a proc. - def to_proc - method(:token).to_proc - end - - # Return the default file extension for outputs of this encoder. - def file_extension - self.class::FILE_EXTENSION - end - - protected - - # Called with merged options before encoding starts. - # Sets @out to an empty string. - # - # See the HTML Encoder for an example of option caching. - def setup options - @out = '' - end - - # Called with +content+ and +kind+ of the currently scanned token. - # For simple scanners, it's enougth to implement this method. - # - # By default, it calls text_token or block_token, depending on - # whether +content+ is a String. - def token content, kind - encoded_token = - if content.is_a? ::String - text_token content, kind - elsif content.is_a? ::Symbol - block_token content, kind - else - raise 'Unknown token content type: %p' % [content] - end - append_encoded_token_to_output encoded_token - end - - def append_encoded_token_to_output encoded_token - @out << encoded_token if encoded_token && defined?(@out) && @out - end - - # Called for each text token ([text, kind]), where text is a String. - def text_token text, kind - end - - # Called for each block (non-text) token ([action, kind]), - # where +action+ is a Symbol. - # - # Calls open_token, close_token, begin_line, and end_line according to - # the value of +action+. - def block_token action, kind - case action - when :open - open_token kind - when :close - close_token kind - when :begin_line - begin_line kind - when :end_line - end_line kind - else - raise 'unknown block action: %p' % action - end - end - - # Called for each block token at the start of the block ([:open, kind]). - def open_token kind - end - - # Called for each block token end of the block ([:close, kind]). - def close_token kind - end - - # Called for each line token block at the start of the line ([:begin_line, kind]). - def begin_line kind - end - - # Called for each line token block at the end of the line ([:end_line, kind]). - def end_line kind - end - - # Called with merged options after encoding starts. - # The return value is the result of encoding, typically @out. - def finish options - @out - end - - # Do the encoding. - # - # The already created +tokens+ object must be used; it can be a - # TokenStream or a Tokens object. - if RUBY_VERSION >= '1.9' - def compile tokens, options - for text, kind in tokens - token text, kind - end - end - else - def compile tokens, options - tokens.each(&self) - end - end - - end - - end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/_map.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/_map.rb deleted file mode 100644 index 526c3a07..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/_map.rb +++ /dev/null @@ -1,12 +0,0 @@ -module CodeRay -module Encoders - - map \ - :loc => :lines_of_code, - :plain => :text, - :stats => :statistic, - :terminal => :term, - :tex => :latex - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/comment_filter.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/comment_filter.rb deleted file mode 100644 index 4d3fb54c..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/comment_filter.rb +++ /dev/null @@ -1,43 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - load :token_class_filter - - class CommentFilter < TokenClassFilter - - register_for :comment_filter - - DEFAULT_OPTIONS = superclass::DEFAULT_OPTIONS.merge \ - :exclude => [:comment] - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class CommentFilterTest < Test::Unit::TestCase - - def test_filtering_comments - tokens = CodeRay.scan <<-RUBY, :ruby -#!/usr/bin/env ruby -# a minimal Ruby program -puts "Hello world!" - RUBY - assert_equal <<-RUBY_FILTERED, tokens.comment_filter.text -#!/usr/bin/env ruby - -puts "Hello world!" - RUBY_FILTERED - end - -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/count.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/count.rb deleted file mode 100644 index c9a6dfde..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/count.rb +++ /dev/null @@ -1,21 +0,0 @@ -module CodeRay -module Encoders - - class Count < Encoder - - include Streamable - register_for :count - - protected - - def setup options - @out = 0 - end - - def token text, kind - @out += 1 - end - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/debug.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/debug.rb deleted file mode 100644 index a4b06483..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/debug.rb +++ /dev/null @@ -1,49 +0,0 @@ -module CodeRay -module Encoders - - # = Debug Encoder - # - # Fast encoder producing simple debug output. - # - # It is readable and diff-able and is used for testing. - # - # You cannot fully restore the tokens information from the - # output, because consecutive :space tokens are merged. - # Use Tokens#dump for caching purposes. - class Debug < Encoder - - include Streamable - register_for :debug - - FILE_EXTENSION = 'raydebug' - - protected - def text_token text, kind - if kind == :space - text - else - text = text.gsub(/[)\\]/, '\\\\\0') # escape ) and \ - "#{kind}(#{text})" - end - end - - def open_token kind - "#{kind}<" - end - - def close_token kind - ">" - end - - def begin_line kind - "#{kind}[" - end - - def end_line kind - "]" - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/div.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/div.rb deleted file mode 100644 index 41201724..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/div.rb +++ /dev/null @@ -1,19 +0,0 @@ -module CodeRay -module Encoders - - load :html - - class Div < HTML - - FILE_EXTENSION = 'div.html' - - register_for :div - - DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ - :css => :style, - :wrap => :div - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/filter.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/filter.rb deleted file mode 100644 index 5e4b34d1..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/filter.rb +++ /dev/null @@ -1,75 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - class Filter < Encoder - - register_for :filter - - protected - def setup options - @out = Tokens.new - end - - def text_token text, kind - [text, kind] if include_text_token? text, kind - end - - def include_text_token? text, kind - true - end - - def block_token action, kind - [action, kind] if include_block_token? action, kind - end - - def include_block_token? action, kind - true - end - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class FilterTest < Test::Unit::TestCase - - def test_creation - assert CodeRay::Encoders::Filter < CodeRay::Encoders::Encoder - filter = nil - assert_nothing_raised do - filter = CodeRay.encoder :filter - end - assert_kind_of CodeRay::Encoders::Encoder, filter - end - - def test_filtering_text_tokens - tokens = CodeRay::Tokens.new - 10.times do |i| - tokens << [i.to_s, :index] - end - assert_equal tokens, CodeRay::Encoders::Filter.new.encode_tokens(tokens) - assert_equal tokens, tokens.filter - end - - def test_filtering_block_tokens - tokens = CodeRay::Tokens.new - 10.times do |i| - tokens << [:open, :index] - tokens << [i.to_s, :content] - tokens << [:close, :index] - end - assert_equal tokens, CodeRay::Encoders::Filter.new.encode_tokens(tokens) - assert_equal tokens, tokens.filter - end - -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html.rb deleted file mode 100644 index f280c7d3..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html.rb +++ /dev/null @@ -1,309 +0,0 @@ -require 'set' - -module CodeRay -module Encoders - - # = HTML Encoder - # - # This is CodeRay's most important highlighter: - # It provides save, fast XHTML generation and CSS support. - # - # == Usage - # - # require 'coderay' - # puts CodeRay.scan('Some /code/', :ruby).html #-> a HTML page - # puts CodeRay.scan('Some /code/', :ruby).html(:wrap => :span) - # #-> Some /code/ - # puts CodeRay.scan('Some /code/', :ruby).span #-> the same - # - # puts CodeRay.scan('Some code', :ruby).html( - # :wrap => nil, - # :line_numbers => :inline, - # :css => :style - # ) - # #-> 1 Some code - # - # == Options - # - # === :tab_width - # Convert \t characters to +n+ spaces (a number.) - # Default: 8 - # - # === :css - # How to include the styles; can be :class or :style. - # - # Default: :class - # - # === :wrap - # Wrap in :page, :div, :span or nil. - # - # You can also use Encoders::Div and Encoders::Span. - # - # Default: nil - # - # === :title - # - # The title of the HTML page (works only when :wrap is set to :page.) - # - # Default: 'CodeRay output' - # - # === :line_numbers - # Include line numbers in :table, :inline, :list or nil (no line numbers) - # - # Default: nil - # - # === :line_number_start - # Where to start with line number counting. - # - # Default: 1 - # - # === :bold_every - # Make every +n+-th number appear bold. - # - # Default: 10 - # - # === :highlight_lines - # - # Highlights certain line numbers. - # Can be any Enumerable, typically just an Array or Range, of numbers. - # - # Bolding is deactivated when :highlight_lines is set. It only makes sense - # in combination with :line_numbers. - # - # Default: nil - # - # === :hint - # Include some information into the output using the title attribute. - # Can be :info (show token type on mouse-over), :info_long (with full path) - # or :debug (via inspect). - # - # Default: false - class HTML < Encoder - - include Streamable - register_for :html - - FILE_EXTENSION = 'html' - - DEFAULT_OPTIONS = { - :tab_width => 8, - - :css => :class, - - :style => :cycnus, - :wrap => nil, - :title => 'CodeRay output', - - :line_numbers => nil, - :line_number_start => 1, - :bold_every => 10, - :highlight_lines => nil, - - :hint => false, - } - - helper :output, :css - - attr_reader :css - - protected - - HTML_ESCAPE = { #:nodoc: - '&' => '&', - '"' => '"', - '>' => '>', - '<' => '<', - } - - # This was to prevent illegal HTML. - # Strange chars should still be avoided in codes. - evil_chars = Array(0x00...0x20) - [?\n, ?\t, ?\s] - evil_chars.each { |i| HTML_ESCAPE[i.chr] = ' ' } - #ansi_chars = Array(0x7f..0xff) - #ansi_chars.each { |i| HTML_ESCAPE[i.chr] = '&#%d;' % i } - # \x9 (\t) and \xA (\n) not included - #HTML_ESCAPE_PATTERN = /[\t&"><\0-\x8\xB-\x1f\x7f-\xff]/ - HTML_ESCAPE_PATTERN = /[\t"&><\0-\x8\xB-\x1f]/ - - TOKEN_KIND_TO_INFO = Hash.new { |h, kind| - h[kind] = - case kind - when :pre_constant - 'Predefined constant' - else - kind.to_s.gsub(/_/, ' ').gsub(/\b\w/) { $&.capitalize } - end - } - - TRANSPARENT_TOKEN_KINDS = [ - :delimiter, :modifier, :content, :escape, :inline_delimiter, - ].to_set - - # Generate a hint about the given +classes+ in a +hint+ style. - # - # +hint+ may be :info, :info_long or :debug. - def self.token_path_to_hint hint, classes - title = - case hint - when :info - TOKEN_KIND_TO_INFO[classes.first] - when :info_long - classes.reverse.map { |kind| TOKEN_KIND_TO_INFO[kind] }.join('/') - when :debug - classes.inspect - end - title ? " title=\"#{title}\"" : '' - end - - def setup options - super - - @HTML_ESCAPE = HTML_ESCAPE.dup - @HTML_ESCAPE["\t"] = ' ' * options[:tab_width] - - @opened = [nil] - @css = CSS.new options[:style] - - hint = options[:hint] - if hint and not [:debug, :info, :info_long].include? hint - raise ArgumentError, "Unknown value %p for :hint; \ - expected :info, :debug, false, or nil." % hint - end - - case options[:css] - - when :class - @css_style = Hash.new do |h, k| - c = CodeRay::Tokens::ClassOfKind[k.first] - if c == :NO_HIGHLIGHT and not hint - h[k.dup] = false - else - title = if hint - HTML.token_path_to_hint(hint, k[1..-1] << k.first) - else - '' - end - if c == :NO_HIGHLIGHT - h[k.dup] = '' % [title] - else - h[k.dup] = '' % [title, c] - end - end - end - - when :style - @css_style = Hash.new do |h, k| - if k.is_a? ::Array - styles = k.dup - else - styles = [k] - end - type = styles.first - classes = styles.map { |c| Tokens::ClassOfKind[c] } - if classes.first == :NO_HIGHLIGHT and not hint - h[k] = false - else - styles.shift if TRANSPARENT_TOKEN_KINDS.include? styles.first - title = HTML.token_path_to_hint hint, styles - style = @css[*classes] - h[k] = - if style - '' % [title, style] - else - false - end - end - end - - else - raise ArgumentError, "Unknown value %p for :css." % options[:css] - - end - end - - def finish options - not_needed = @opened.shift - @out << '' * @opened.size - unless @opened.empty? - warn '%d tokens still open: %p' % [@opened.size, @opened] - end - - @out.extend Output - @out.css = @css - @out.numerize! options[:line_numbers], options - @out.wrap! options[:wrap] - @out.apply_title! options[:title] - - super - end - - def token text, type = :plain - case text - - when nil - # raise 'Token with nil as text was given: %p' % [[text, type]] - - when String - if text =~ /#{HTML_ESCAPE_PATTERN}/o - text = text.gsub(/#{HTML_ESCAPE_PATTERN}/o) { |m| @HTML_ESCAPE[m] } - end - @opened[0] = type - if text != "\n" && style = @css_style[@opened] - @out << style << text << '' - else - @out << text - end - - - # token groups, eg. strings - when :open - @opened[0] = type - @out << (@css_style[@opened] || '') - @opened << type - when :close - if @opened.empty? - # nothing to close - else - if $CODERAY_DEBUG and (@opened.size == 1 or @opened.last != type) - raise 'Malformed token stream: Trying to close a token (%p) \ - that is not open. Open are: %p.' % [type, @opened[1..-1]] - end - @out << '' - @opened.pop - end - - # whole lines to be highlighted, eg. a deleted line in a diff - when :begin_line - @opened[0] = type - if style = @css_style[@opened] - if style['class="'] - @out << style.sub('class="', 'class="line ') - else - @out << style.sub('>', ' class="line">') - end - else - @out << '' - end - @opened << type - when :end_line - if @opened.empty? - # nothing to close - else - if $CODERAY_DEBUG and (@opened.size == 1 or @opened.last != type) - raise 'Malformed token stream: Trying to close a line (%p) \ - that is not open. Open are: %p.' % [type, @opened[1..-1]] - end - @out << '' - @opened.pop - end - - else - raise 'unknown token kind: %p' % [text] - - end - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/css.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/css.rb deleted file mode 100644 index 09ac8bc0..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/css.rb +++ /dev/null @@ -1,70 +0,0 @@ -module CodeRay -module Encoders - - class HTML - class CSS - - attr :stylesheet - - def CSS.load_stylesheet style = nil - CodeRay::Styles[style] - end - - def initialize style = :default - @classes = Hash.new - style = CSS.load_stylesheet style - @stylesheet = [ - style::CSS_MAIN_STYLES, - style::TOKEN_COLORS.gsub(/^(?!$)/, '.CodeRay ') - ].join("\n") - parse style::TOKEN_COLORS - end - - def [] *styles - cl = @classes[styles.first] - return '' unless cl - style = '' - 1.upto(styles.size) do |offset| - break if style = cl[styles[offset .. -1]] - end - # warn 'Style not found: %p' % [styles] if style.empty? - return style - end - - private - - CSS_CLASS_PATTERN = / - ( # $1 = selectors - (?: - (?: \s* \. [-\w]+ )+ - \s* ,? - )+ - ) - \s* \{ \s* - ( [^\}]+ )? # $2 = style - \s* \} \s* - | - ( . ) # $3 = error - /mx - def parse stylesheet - stylesheet.scan CSS_CLASS_PATTERN do |selectors, style, error| - raise "CSS parse error: '#{error.inspect}' not recognized" if error - for selector in selectors.split(',') - classes = selector.scan(/[-\w]+/) - cl = classes.pop - @classes[cl] ||= Hash.new - @classes[cl][classes] = style.to_s.strip.delete(' ').chomp(';') - end - end - end - - end - end - -end -end - -if $0 == __FILE__ - require 'pp' - pp CodeRay::Encoders::HTML::CSS.new -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/numerization.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/numerization.rb deleted file mode 100644 index 17e8ddb0..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/numerization.rb +++ /dev/null @@ -1,133 +0,0 @@ -module CodeRay -module Encoders - - class HTML - - module Output - - def numerize *args - clone.numerize!(*args) - end - -=begin NUMERIZABLE_WRAPPINGS = { - :table => [:div, :page, nil], - :inline => :all, - :list => [:div, :page, nil] - } - NUMERIZABLE_WRAPPINGS.default = :all -=end - def numerize! mode = :table, options = {} - return self unless mode - - options = DEFAULT_OPTIONS.merge options - - start = options[:line_number_start] - unless start.is_a? Integer - raise ArgumentError, "Invalid value %p for :line_number_start; Integer expected." % start - end - - #allowed_wrappings = NUMERIZABLE_WRAPPINGS[mode] - #unless allowed_wrappings == :all or allowed_wrappings.include? options[:wrap] - # raise ArgumentError, "Can't numerize, :wrap must be in %p, but is %p" % [NUMERIZABLE_WRAPPINGS, options[:wrap]] - #end - - bold_every = options[:bold_every] - highlight_lines = options[:highlight_lines] - bolding = - if bold_every == false && highlight_lines == nil - proc { |line| line.to_s } - elsif highlight_lines.is_a? Enumerable - highlight_lines = highlight_lines.to_set - proc do |line| - if highlight_lines.include? line - "#{line}" # highlighted line numbers in bold - else - line.to_s - end - end - elsif bold_every.is_a? Integer - raise ArgumentError, ":bolding can't be 0." if bold_every == 0 - proc do |line| - if line % bold_every == 0 - "#{line}" # every bold_every-th number in bold - else - line.to_s - end - end - else - raise ArgumentError, 'Invalid value %p for :bolding; false or Integer expected.' % bold_every - end - - case mode - when :inline - max_width = (start + line_count).to_s.size - line_number = start - gsub!(/^/) do - line_number_text = bolding.call line_number - indent = ' ' * (max_width - line_number.to_s.size) # TODO: Optimize (10^x) - res = "#{indent}#{line_number_text} " - line_number += 1 - res - end - - when :table - # This is really ugly. - # Because even monospace fonts seem to have different heights when bold, - # I make the newline bold, both in the code and the line numbers. - # FIXME Still not working perfect for Mr. Internet Exploder - line_numbers = (start ... start + line_count).to_a.map(&bolding).join("\n") - line_numbers << "\n" # also for Mr. MS Internet Exploder :-/ - line_numbers.gsub!(/\n/) { "\n" } - - line_numbers_table_tpl = TABLE.apply('LINE_NUMBERS', line_numbers) - gsub!("
    \n", '
    ') - gsub!("\n", "\n") - wrap_in! line_numbers_table_tpl - @wrapped_in = :div - - when :list - opened_tags = [] - gsub!(/^.*$\n?/) do |line| - line.chomp! - - open = opened_tags.join - line.scan(%r!<(/)?span[^>]*>?!) do |close,| - if close - opened_tags.pop - else - opened_tags << $& - end - end - close = '' * opened_tags.size - - "
  • #{open}#{line}#{close}
  • \n" - end - chomp!("\n") - wrap_in! LIST - @wrapped_in = :div - - else - raise ArgumentError, 'Unknown value %p for mode: expected one of %p' % - [mode, [:table, :list, :inline]] - end - - self - end - - def line_count - line_count = count("\n") - position_of_last_newline = rindex(?\n) - if position_of_last_newline - after_last_newline = self[position_of_last_newline + 1 .. -1] - ends_with_newline = after_last_newline[/\A(?:<\/span>)*\z/] - line_count += 1 if not ends_with_newline - end - line_count - end - - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/output.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/output.rb deleted file mode 100644 index 28574a5d..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/html/output.rb +++ /dev/null @@ -1,206 +0,0 @@ -module CodeRay -module Encoders - - class HTML - - # This module is included in the output String from thew HTML Encoder. - # - # It provides methods like wrap, div, page etc. - # - # Remember to use #clone instead of #dup to keep the modules the object was - # extended with. - # - # TODO: more doc. - module Output - - require 'coderay/encoders/html/numerization.rb' - - attr_accessor :css - - class << self - - # This makes Output look like a class. - # - # Example: - # - # a = Output.new 'Code' - # a.wrap! :page - def new string, css = CSS.new, element = nil - output = string.clone.extend self - output.wrapped_in = element - output.css = css - output - end - - # Raises an exception if an object that doesn't respond to to_str is extended by Output, - # to prevent users from misuse. Use Module#remove_method to disable. - def extended o - warn "The Output module is intended to extend instances of String, not #{o.class}." unless o.respond_to? :to_str - end - - def make_stylesheet css, in_tag = false - sheet = css.stylesheet - sheet = <<-CSS if in_tag - - CSS - sheet - end - - def page_template_for_css css - sheet = make_stylesheet css - PAGE.apply 'CSS', sheet - end - - # Define a new wrapper. This is meta programming. - def wrapper *wrappers - wrappers.each do |wrapper| - define_method wrapper do |*args| - wrap wrapper, *args - end - define_method "#{wrapper}!".to_sym do |*args| - wrap! wrapper, *args - end - end - end - - end - - wrapper :div, :span, :page - - def wrapped_in? element - wrapped_in == element - end - - def wrapped_in - @wrapped_in ||= nil - end - attr_writer :wrapped_in - - def wrap_in template - clone.wrap_in! template - end - - def wrap_in! template - Template.wrap! self, template, 'CONTENT' - self - end - - def apply_title! title - self.sub!(/()(<\/title>)/) { $1 + title + $2 } - self - end - - def wrap! element, *args - return self if not element or element == wrapped_in - case element - when :div - raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil - wrap_in! DIV - when :span - raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? nil - wrap_in! SPAN - when :page - wrap! :div if wrapped_in? nil - raise "Can't wrap %p in %p" % [wrapped_in, element] unless wrapped_in? :div - wrap_in! Output.page_template_for_css(@css) - if args.first.is_a?(Hash) && title = args.first[:title] - apply_title! title - end - self - when nil - return self - else - raise "Unknown value %p for :wrap" % element - end - @wrapped_in = element - self - end - - def wrap *args - clone.wrap!(*args) - end - - def stylesheet in_tag = false - Output.make_stylesheet @css, in_tag - end - - class Template < String - - def self.wrap! str, template, target - target = Regexp.new(Regexp.escape("<%#{target}%>")) - if template =~ target - str[0,0] = $` - str << $' - else - raise "Template target <%%%p%%> not found" % target - end - end - - def apply target, replacement - target = Regexp.new(Regexp.escape("<%#{target}%>")) - if self =~ target - Template.new($` + replacement + $') - else - raise "Template target <%%%p%%> not found" % target - end - end - - module Simple - def ` str #` <-- for stupid editors - Template.new str - end - end - end - - extend Template::Simple - -#-- don't include the templates in docu - - SPAN = `<span class="CodeRay"><%CONTENT%></span>` - - DIV = <<-`DIV` -<div class="CodeRay"> - <div class="code"><pre><%CONTENT%></pre></div> -</div> - DIV - - TABLE = <<-`TABLE` -<table class="CodeRay"><tr> - <td class="line_numbers" title="click to toggle" onclick="with (this.firstChild.style) { display = (display == '') ? 'none' : '' }"><pre><%LINE_NUMBERS%></pre></td> - <td class="code"><pre ondblclick="with (this.style) { overflow = (overflow == 'auto' || overflow == '') ? 'visible' : 'auto' }"><%CONTENT%></pre></td> -</tr></table> - TABLE - # title="double click to expand" - - LIST = <<-`LIST` -<ol class="CodeRay"> -<%CONTENT%> -</ol> - LIST - - PAGE = <<-`PAGE` -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="de"> -<head> - <meta http-equiv="content-type" content="text/html; charset=utf-8" /> - <title> - - - - -<%CONTENT%> - - - PAGE - - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/json.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/json.rb deleted file mode 100644 index 7aa077c2..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/json.rb +++ /dev/null @@ -1,69 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - # = JSON Encoder - class JSON < Encoder - - register_for :json - FILE_EXTENSION = 'json' - - protected - def setup options - begin - require 'json' - rescue LoadError - require 'rubygems' - require 'json' - end - @out = [] - end - - def text_token text, kind - { :type => 'text', :text => text, :kind => kind } - end - - def block_token action, kind - { :type => 'block', :action => action, :kind => kind } - end - - def finish options - @out.to_json - end - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' -$:.delete '.' -require 'rubygems' if RUBY_VERSION < '1.9' - -class JSONEncoderTest < Test::Unit::TestCase - - def test_json_output - tokens = CodeRay.scan <<-RUBY, :ruby -puts "Hello world!" - RUBY - require 'json' - assert_equal [ - {"type"=>"text", "text"=>"puts", "kind"=>"ident"}, - {"type"=>"text", "text"=>" ", "kind"=>"space"}, - {"type"=>"block", "action"=>"open", "kind"=>"string"}, - {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, - {"type"=>"text", "text"=>"Hello world!", "kind"=>"content"}, - {"type"=>"text", "text"=>"\"", "kind"=>"delimiter"}, - {"type"=>"block", "action"=>"close", "kind"=>"string"}, - {"type"=>"text", "text"=>"\n", "kind"=>"space"} - ], JSON.load(tokens.json) - end - -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/lines_of_code.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/lines_of_code.rb deleted file mode 100644 index c1ad66e2..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/lines_of_code.rb +++ /dev/null @@ -1,90 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - # Counts the LoC (Lines of Code). Returns an Integer >= 0. - # - # Alias: :loc - # - # Everything that is not comment, markup, doctype/shebang, or an empty line, - # is considered to be code. - # - # For example, - # * HTML files not containing JavaScript have 0 LoC - # * in a Java class without comments, LoC is the number of non-empty lines - # - # A Scanner class should define the token kinds that are not code in the - # KINDS_NOT_LOC constant, which defaults to [:comment, :doctype]. - class LinesOfCode < Encoder - - register_for :lines_of_code - - NON_EMPTY_LINE = /^\s*\S.*$/ - - def compile tokens, options - if scanner = tokens.scanner - kinds_not_loc = scanner.class::KINDS_NOT_LOC - else - warn ArgumentError, 'Tokens have no scanner.' if $VERBOSE - kinds_not_loc = CodeRay::Scanners::Scanner::KINDS_NOT_LOC - end - code = tokens.token_class_filter :exclude => kinds_not_loc - @loc = code.text.scan(NON_EMPTY_LINE).size - end - - def finish options - @loc - end - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class LinesOfCodeTest < Test::Unit::TestCase - - def test_creation - assert CodeRay::Encoders::LinesOfCode < CodeRay::Encoders::Encoder - filter = nil - assert_nothing_raised do - filter = CodeRay.encoder :loc - end - assert_kind_of CodeRay::Encoders::LinesOfCode, filter - assert_nothing_raised do - filter = CodeRay.encoder :lines_of_code - end - assert_kind_of CodeRay::Encoders::LinesOfCode, filter - end - - def test_lines_of_code - tokens = CodeRay.scan <<-RUBY, :ruby -#!/usr/bin/env ruby - -# a minimal Ruby program -puts "Hello world!" - RUBY - assert_equal 1, CodeRay::Encoders::LinesOfCode.new.encode_tokens(tokens) - assert_equal 1, tokens.lines_of_code - assert_equal 1, tokens.loc - end - - def test_filtering_block_tokens - tokens = CodeRay::Tokens.new - tokens << ["Hello\n", :world] - tokens << ["Hello\n", :space] - tokens << ["Hello\n", :comment] - assert_equal 2, CodeRay::Encoders::LinesOfCode.new.encode_tokens(tokens) - assert_equal 2, tokens.lines_of_code - assert_equal 2, tokens.loc - end - -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/null.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/null.rb deleted file mode 100644 index add3862a..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/null.rb +++ /dev/null @@ -1,26 +0,0 @@ -module CodeRay -module Encoders - - # = Null Encoder - # - # Does nothing and returns an empty string. - class Null < Encoder - - include Streamable - register_for :null - - # Defined for faster processing - def to_proc - proc {} - end - - protected - - def token(*) - # do nothing - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/page.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/page.rb deleted file mode 100644 index 1b69cce9..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/page.rb +++ /dev/null @@ -1,20 +0,0 @@ -module CodeRay -module Encoders - - load :html - - class Page < HTML - - FILE_EXTENSION = 'html' - - register_for :page - - DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ - :css => :class, - :wrap => :page, - :line_numbers => :table - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/span.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/span.rb deleted file mode 100644 index 319f6fd0..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/span.rb +++ /dev/null @@ -1,19 +0,0 @@ -module CodeRay -module Encoders - - load :html - - class Span < HTML - - FILE_EXTENSION = 'span.html' - - register_for :span - - DEFAULT_OPTIONS = HTML::DEFAULT_OPTIONS.merge \ - :css => :style, - :wrap => :span - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/statistic.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/statistic.rb deleted file mode 100644 index 6d0c6468..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/statistic.rb +++ /dev/null @@ -1,77 +0,0 @@ -module CodeRay -module Encoders - - # Makes a statistic for the given tokens. - class Statistic < Encoder - - include Streamable - register_for :stats, :statistic - - attr_reader :type_stats, :real_token_count - - protected - - TypeStats = Struct.new :count, :size - - def setup options - @type_stats = Hash.new { |h, k| h[k] = TypeStats.new 0, 0 } - @real_token_count = 0 - end - - def generate tokens, options - @tokens = tokens - super - end - - def text_token text, kind - @real_token_count += 1 unless kind == :space - @type_stats[kind].count += 1 - @type_stats[kind].size += text.size - @type_stats['TOTAL'].size += text.size - @type_stats['TOTAL'].count += 1 - end - - # TODO Hierarchy handling - def block_token action, kind - @type_stats['TOTAL'].count += 1 - @type_stats['open/close'].count += 1 - end - - STATS = <<-STATS - -Code Statistics - -Tokens %8d - Non-Whitespace %8d -Bytes Total %8d - -Token Types (%d): - type count ratio size (average) -------------------------------------------------------------- -%s - STATS -# space 12007 33.81 % 1.7 - TOKEN_TYPES_ROW = <<-TKR - %-20s %8d %6.2f %% %5.1f - TKR - - def finish options - all = @type_stats['TOTAL'] - all_count, all_size = all.count, all.size - @type_stats.each do |type, stat| - stat.size /= stat.count.to_f - end - types_stats = @type_stats.sort_by { |k, v| [-v.count, k.to_s] }.map do |k, v| - TOKEN_TYPES_ROW % [k, v.count, 100.0 * v.count / all_count, v.size] - end.join - STATS % [ - all_count, @real_token_count, all_size, - @type_stats.delete_if { |k, v| k.is_a? String }.size, - types_stats - ] - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/term.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/term.rb deleted file mode 100644 index 1f284ed1..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/term.rb +++ /dev/null @@ -1,158 +0,0 @@ -# encoders/term.rb -# By Rob Aldred (http://robaldred.co.uk) -# Based on idea by Nathan Weizenbaum (http://nex-3.com) -# MIT License (http://www.opensource.org/licenses/mit-license.php) -# -# A CodeRay encoder that outputs code highlighted for a color terminal. -# Check out http://robaldred.co.uk - -module CodeRay - module Encoders - class Term < Encoder - register_for :term - - TOKEN_COLORS = { - :annotation => '35', - :attribute_name => '33', - :attribute_name_fat => '33', - :attribute_value => '31', - :attribute_value_fat => '31', - :bin => '1;35', - :char => {:self => '36', :delimiter => '34'}, - :class => '1;35', - :class_variable => '36', - :color => '32', - :comment => '37', - :complex => '34', - :constant => ['34', '4'], - :decoration => '35', - :definition => '1;32', - :directive => ['32', '4'], - :doc => '46', - :doctype => '1;30', - :doc_string => ['31', '4'], - :entity => '33', - :error => ['1;33', '41'], - :exception => '1;31', - :float => '1;35', - :function => '1;34', - :global_variable => '42', - :hex => '1;36', - :important => '1;31', - :include => '33', - :integer => '1;34', - :interpreted => '1;35', - :key => '35', - :label => '1;4', - :local_variable => '33', - :oct => '1;35', - :operator_name => '1;29', - :pre_constant => '1;36', - :pre_type => '1;30', - :predefined => ['4', '1;34'], - :preprocessor => '36', - :pseudo_class => '34', - :regexp => { - :content => '31', - :delimiter => '1;29', - :modifier => '35', - :function => '1;29' - }, - :reserved => '1;31', - :shell => { - :self => '42', - :content => '1;29', - :delimiter => '37', - }, - :string => { - :self => '32', - :modifier => '1;32', - :escape => '1;36', - :delimiter => '1;32', - }, - :symbol => '1;32', - :tag => '34', - :tag_fat => '1;34', - :tag_special => ['34', '4'], - :type => '1;34', - :value => '36', - :variable => '34', - :insert => '42', - :delete => '41', - :change => '44', - :head => '45', - } - TOKEN_COLORS[:keyword] = TOKEN_COLORS[:reserved] - TOKEN_COLORS[:method] = TOKEN_COLORS[:function] - TOKEN_COLORS[:imaginary] = TOKEN_COLORS[:complex] - TOKEN_COLORS[:open] = TOKEN_COLORS[:close] = TOKEN_COLORS[:nesting_delimiter] = TOKEN_COLORS[:escape] = TOKEN_COLORS[:delimiter] - - protected - - def setup(options) - @out = '' - @opened = [nil] - @subcolors = nil - end - - def finish(options) - super - end - - def token text, type = :plain - case text - - when nil - # raise 'Token with nil as text was given: %p' % [[text, type]] - - when String - - if color = (@subcolors || TOKEN_COLORS)[type] - color = color[:self] || return if Hash === color - - @out << col(color) + text.gsub("\n", col(0) + "\n" + col(color)) + col(0) - @out << col(@subcolors[:self]) if @subcolors && @subcolors[:self] - else - @out << text - end - - # token groups, eg. strings - when :open - @opened[0] = type - if color = TOKEN_COLORS[type] - if Hash === color - @subcolors = color - @out << col(color[:self]) if color[:self] - else - @subcolors = {} - @out << col(color) - end - end - @opened << type - when :close - if @opened.empty? - # nothing to close - else - @out << col(0) if (@subcolors || {})[:self] - @subcolors = nil - @opened.pop - end - - # whole lines to be highlighted, eg. a added/modified/deleted lines in a diff - when :begin_line - - when :end_line - - else - raise 'unknown token kind: %p' % [text] - end - end - - private - - def col(color) - Array(color).map { |c| "\e[#{c}m" }.join - end - end - end -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/text.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/text.rb deleted file mode 100644 index 161ee67c..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/text.rb +++ /dev/null @@ -1,32 +0,0 @@ -module CodeRay -module Encoders - - class Text < Encoder - - include Streamable - register_for :text - - FILE_EXTENSION = 'txt' - - DEFAULT_OPTIONS = { - :separator => '' - } - - protected - def setup options - super - @sep = options[:separator] - end - - def text_token text, kind - text + @sep - end - - def finish options - super.chomp @sep - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/token_class_filter.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/token_class_filter.rb deleted file mode 100644 index a9e8673a..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/token_class_filter.rb +++ /dev/null @@ -1,84 +0,0 @@ -($:.unshift '../..'; require 'coderay') unless defined? CodeRay -module CodeRay -module Encoders - - load :filter - - class TokenClassFilter < Filter - - include Streamable - register_for :token_class_filter - - DEFAULT_OPTIONS = { - :exclude => [], - :include => :all - } - - protected - def setup options - super - @exclude = options[:exclude] - @exclude = Array(@exclude) unless @exclude == :all - @include = options[:include] - @include = Array(@include) unless @include == :all - end - - def include_text_token? text, kind - (@include == :all || @include.include?(kind)) && - !(@exclude == :all || @exclude.include?(kind)) - end - - end - -end -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class TokenClassFilterTest < Test::Unit::TestCase - - def test_creation - assert CodeRay::Encoders::TokenClassFilter < CodeRay::Encoders::Encoder - assert CodeRay::Encoders::TokenClassFilter < CodeRay::Encoders::Filter - filter = nil - assert_nothing_raised do - filter = CodeRay.encoder :token_class_filter - end - assert_instance_of CodeRay::Encoders::TokenClassFilter, filter - end - - def test_filtering_text_tokens - tokens = CodeRay::Tokens.new - for i in 1..10 - tokens << [i.to_s, :index] - tokens << [' ', :space] if i < 10 - end - assert_equal 10, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :exclude => :space).size - assert_equal 10, tokens.token_class_filter(:exclude => :space).size - assert_equal 9, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :include => :space).size - assert_equal 9, tokens.token_class_filter(:include => :space).size - assert_equal 0, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :exclude => :all).size - assert_equal 0, tokens.token_class_filter(:exclude => :all).size - end - - def test_filtering_block_tokens - tokens = CodeRay::Tokens.new - 10.times do |i| - tokens << [:open, :index] - tokens << [i.to_s, :content] - tokens << [:close, :index] - end - assert_equal 20, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :include => :blubb).size - assert_equal 20, tokens.token_class_filter(:include => :blubb).size - assert_equal 30, CodeRay::Encoders::TokenClassFilter.new.encode_tokens(tokens, :exclude => :index).size - assert_equal 30, tokens.token_class_filter(:exclude => :index).size - end - -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/xml.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/xml.rb deleted file mode 100644 index f32c967b..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/xml.rb +++ /dev/null @@ -1,71 +0,0 @@ -module CodeRay -module Encoders - - # = XML Encoder - # - # Uses REXML. Very slow. - class XML < Encoder - - include Streamable - register_for :xml - - FILE_EXTENSION = 'xml' - - require 'rexml/document' - - DEFAULT_OPTIONS = { - :tab_width => 8, - :pretty => -1, - :transitive => false, - } - - protected - - def setup options - @doc = REXML::Document.new - @doc << REXML::XMLDecl.new - @tab_width = options[:tab_width] - @root = @node = @doc.add_element('coderay-tokens') - end - - def finish options - @out = '' - @doc.write @out, options[:pretty], options[:transitive], true - @out - end - - def text_token text, kind - if kind == :space - token = @node - else - token = @node.add_element kind.to_s - end - text.scan(/(\x20+)|(\t+)|(\n)|[^\x20\t\n]+/) do |space, tab, nl| - case - when space - token << REXML::Text.new(space, true) - when tab - token << REXML::Text.new(tab, true) - when nl - token << REXML::Text.new(nl, true) - else - token << REXML::Text.new($&) - end - end - end - - def open_token kind - @node = @node.add_element kind.to_s - end - - def close_token kind - if @node == @root - raise 'no token to close!' - end - @node = @node.parent - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/yaml.rb b/vendor/gems/coderay-0.9.7/lib/coderay/encoders/yaml.rb deleted file mode 100644 index 5564e58a..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/encoders/yaml.rb +++ /dev/null @@ -1,22 +0,0 @@ -module CodeRay -module Encoders - - # = YAML Encoder - # - # Slow. - class YAML < Encoder - - register_for :yaml - - FILE_EXTENSION = 'yaml' - - protected - def compile tokens, options - require 'yaml' - @out = tokens.to_a.to_yaml - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/for_redcloth.rb b/vendor/gems/coderay-0.9.7/lib/coderay/for_redcloth.rb deleted file mode 100644 index 69985bca..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/for_redcloth.rb +++ /dev/null @@ -1,95 +0,0 @@ -module CodeRay - - # A little hack to enable CodeRay highlighting in RedCloth. - # - # Usage: - # require 'coderay' - # require 'coderay/for_redcloth' - # RedCloth.new('@[ruby]puts "Hello, World!"@').to_html - # - # Make sure you have RedCloth 4.0.3 activated, for example by calling - # require 'rubygems' - # before RedCloth is loaded and before calling CodeRay.for_redcloth. - module ForRedCloth - - def self.install - gem 'RedCloth', '>= 4.0.3' if defined? gem - require 'redcloth' - unless RedCloth::VERSION.to_s >= '4.0.3' - if defined? gem - raise 'CodeRay.for_redcloth needs RedCloth version 4.0.3 or later. ' + - "You have #{RedCloth::VERSION}. Please gem install RedCloth." - else - $".delete 'redcloth.rb' # sorry, but it works - require 'rubygems' - return install # retry - end - end - unless RedCloth::VERSION.to_s >= '4.2.2' - warn 'CodeRay.for_redcloth works best with RedCloth version 4.2.2 or later.' - end - RedCloth::TextileDoc.send :include, ForRedCloth::TextileDoc - RedCloth::Formatters::HTML.module_eval do - def unescape(html) - replacements = { - '&' => '&', - '"' => '"', - '>' => '>', - '<' => '<', - } - html.gsub(/&(?:amp|quot|[gl]t);/) { |entity| replacements[entity] } - end - undef code, bc_open, bc_close, escape_pre - def code(opts) # :nodoc: - opts[:block] = true - if !opts[:lang] && RedCloth::VERSION.to_s >= '4.2.0' - # simulating pre-4.2 behavior - if opts[:text].sub!(/\A\[(\w+)\]/, '') - if CodeRay::Scanners[$1].plugin_id == 'plaintext' - opts[:text] = $& + opts[:text] - else - opts[:lang] = $1 - end - end - end - if opts[:lang] && !filter_coderay - require 'coderay' - @in_bc ||= nil - format = @in_bc ? :div : :span - opts[:text] = unescape(opts[:text]) unless @in_bc - highlighted_code = CodeRay.encode opts[:text], opts[:lang], format, :stream => true - highlighted_code.sub!(/\A<(span|div)/) { |m| m + pba(@in_bc || opts) } - highlighted_code - else - "#{opts[:text]}" - end - end - def bc_open(opts) # :nodoc: - opts[:block] = true - @in_bc = opts - opts[:lang] ? '' : "" - end - def bc_close(opts) # :nodoc: - opts = @in_bc - @in_bc = nil - opts[:lang] ? '' : "\n" - end - def escape_pre(text) - if @in_bc ||= nil - text - else - html_esc(text, :html_escape_preformatted) - end - end - end - end - - module TextileDoc # :nodoc: - attr_accessor :filter_coderay - end - - end - -end - -CodeRay::ForRedCloth.install \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/file_type.rb b/vendor/gems/coderay-0.9.7/lib/coderay/helpers/file_type.rb deleted file mode 100644 index e8a03849..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/file_type.rb +++ /dev/null @@ -1,255 +0,0 @@ -#!/usr/bin/env ruby -module CodeRay - -# = FileType -# -# A simple filetype recognizer. -# -# Copyright (c) 2006 by murphy (Kornelius Kalnbach) -# -# License:: LGPL / ask the author -# Version:: 0.1 (2005-09-01) -# -# == Documentation -# -# # determine the type of the given -# lang = FileType[ARGV.first] -# -# # return :plaintext if the file type is unknown -# lang = FileType.fetch ARGV.first, :plaintext -# -# # try the shebang line, too -# lang = FileType.fetch ARGV.first, :plaintext, true -module FileType - - UnknownFileType = Class.new Exception - - class << self - - # Try to determine the file type of the file. - # - # +filename+ is a relative or absolute path to a file. - # - # The file itself is only accessed when +read_shebang+ is set to true. - # That means you can get filetypes from files that don't exist. - def [] filename, read_shebang = false - name = File.basename filename - ext = File.extname(name).sub(/^\./, '') # from last dot, delete the leading dot - ext2 = filename.to_s[/\.(.*)/, 1] # from first dot - - type = - TypeFromExt[ext] || - TypeFromExt[ext.downcase] || - (TypeFromExt[ext2] if ext2) || - (TypeFromExt[ext2.downcase] if ext2) || - TypeFromName[name] || - TypeFromName[name.downcase] - type ||= shebang(filename) if read_shebang - - type - end - - def shebang filename - begin - File.open filename, 'r' do |f| - if first_line = f.gets - if type = first_line[TypeFromShebang] - type.to_sym - end - end - end - rescue IOError - nil - end - end - - # This works like Hash#fetch. - # - # If the filetype cannot be found, the +default+ value - # is returned. - def fetch filename, default = nil, read_shebang = false - if default and block_given? - warn 'block supersedes default value argument' - end - - unless type = self[filename, read_shebang] - return yield if block_given? - return default if default - raise UnknownFileType, 'Could not determine type of %p.' % filename - end - type - end - - end - - TypeFromExt = { - 'c' => :c, - 'css' => :css, - 'diff' => :diff, - 'dpr' => :delphi, - 'groovy' => :groovy, - 'gvy' => :groovy, - 'h' => :c, - 'htm' => :html, - 'html' => :html, - 'html.erb' => :rhtml, - 'java' => :java, - 'js' => :java_script, - 'json' => :json, - 'mab' => :ruby, - 'pas' => :delphi, - 'patch' => :diff, - 'php' => :php, - 'php3' => :php, - 'php4' => :php, - 'php5' => :php, - 'py' => :python, - 'py3' => :python, - 'pyw' => :python, - 'rake' => :ruby, - 'raydebug' => :debug, - 'rb' => :ruby, - 'rbw' => :ruby, - 'rhtml' => :rhtml, - 'rxml' => :ruby, - 'sch' => :scheme, - 'sql' => :sql, - 'ss' => :scheme, - 'xhtml' => :xhtml, - 'xml' => :xml, - 'yaml' => :yaml, - 'yml' => :yaml, - } - for cpp_alias in %w[cc cpp cp cxx c++ C hh hpp h++ cu] - TypeFromExt[cpp_alias] = :cpp - end - - TypeFromShebang = /\b(?:ruby|perl|python|sh)\b/ - - TypeFromName = { - 'Rakefile' => :ruby, - 'Rantfile' => :ruby, - } - -end - -end - -if $0 == __FILE__ - $VERBOSE = true - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class FileTypeTests < Test::Unit::TestCase - - include CodeRay - - def test_fetch - assert_raise FileType::UnknownFileType do - FileType.fetch '' - end - - assert_throws :not_found do - FileType.fetch '.' do - throw :not_found - end - end - - assert_equal :default, FileType.fetch('c', :default) - - stderr, fake_stderr = $stderr, Object.new - $err = '' - def fake_stderr.write x - $err << x - end - $stderr = fake_stderr - FileType.fetch('c', :default) { } - assert_equal "block supersedes default value argument\n", $err - $stderr = stderr - end - - def test_ruby - assert_equal :ruby, FileType['test.rb'] - assert_equal :ruby, FileType['test.java.rb'] - assert_equal :java, FileType['test.rb.java'] - assert_equal :ruby, FileType['C:\\Program Files\\x\\y\\c\\test.rbw'] - assert_equal :ruby, FileType['/usr/bin/something/Rakefile'] - assert_equal :ruby, FileType['~/myapp/gem/Rantfile'] - assert_equal :ruby, FileType['./lib/tasks\repository.rake'] - assert_not_equal :ruby, FileType['test_rb'] - assert_not_equal :ruby, FileType['Makefile'] - assert_not_equal :ruby, FileType['set.rb/set'] - assert_not_equal :ruby, FileType['~/projects/blabla/rb'] - end - - def test_c - assert_equal :c, FileType['test.c'] - assert_equal :c, FileType['C:\\Program Files\\x\\y\\c\\test.h'] - assert_not_equal :c, FileType['test_c'] - assert_not_equal :c, FileType['Makefile'] - assert_not_equal :c, FileType['set.h/set'] - assert_not_equal :c, FileType['~/projects/blabla/c'] - end - - def test_cpp - assert_equal :cpp, FileType['test.c++'] - assert_equal :cpp, FileType['test.cxx'] - assert_equal :cpp, FileType['test.hh'] - assert_equal :cpp, FileType['test.hpp'] - assert_equal :cpp, FileType['test.cu'] - assert_equal :cpp, FileType['test.C'] - assert_not_equal :cpp, FileType['test.c'] - assert_not_equal :cpp, FileType['test.h'] - end - - def test_html - assert_equal :html, FileType['test.htm'] - assert_equal :xhtml, FileType['test.xhtml'] - assert_equal :xhtml, FileType['test.html.xhtml'] - assert_equal :rhtml, FileType['_form.rhtml'] - assert_equal :rhtml, FileType['_form.html.erb'] - end - - def test_yaml - assert_equal :yaml, FileType['test.yml'] - assert_equal :yaml, FileType['test.yaml'] - assert_equal :yaml, FileType['my.html.yaml'] - assert_not_equal :yaml, FileType['YAML'] - end - - def test_pathname - require 'pathname' - pn = Pathname.new 'test.rb' - assert_equal :ruby, FileType[pn] - dir = Pathname.new '/etc/var/blubb' - assert_equal :ruby, FileType[dir + pn] - assert_equal :cpp, FileType[dir + 'test.cpp'] - end - - def test_no_shebang - dir = './test' - if File.directory? dir - Dir.chdir dir do - assert_equal :c, FileType['test.c'] - end - end - end - - def test_shebang_empty_file - require 'tmpdir' - tmpfile = File.join(Dir.tmpdir, 'bla') - File.open(tmpfile, 'w') { } # touch - assert_equal nil, FileType[tmpfile] - end - - def test_shebang - require 'tmpdir' - tmpfile = File.join(Dir.tmpdir, 'bla') - File.open(tmpfile, 'w') { |f| f.puts '#!/usr/bin/env ruby' } - assert_equal :ruby, FileType[tmpfile, true] - end - -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/gzip_simple.rb b/vendor/gems/coderay-0.9.7/lib/coderay/helpers/gzip_simple.rb deleted file mode 100644 index b979f665..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/gzip_simple.rb +++ /dev/null @@ -1,123 +0,0 @@ -# =GZip Simple -# -# A simplified interface to the gzip library +zlib+ (from the Ruby Standard Library.) -# -# Author: murphy (mail to murphy rubychan de) -# -# Version: 0.2 (2005.may.28) -# -# ==Documentation -# -# See +GZip+ module and the +String+ extensions. -# -module GZip - - require 'zlib' - - # The default zipping level. 7 zips good and fast. - DEFAULT_GZIP_LEVEL = 7 - - # Unzips the given string +s+. - # - # Example: - # require 'gzip_simple' - # print GZip.gunzip(File.read('adresses.gz')) - def GZip.gunzip s - Zlib::Inflate.inflate s - end - - # Zips the given string +s+. - # - # Example: - # require 'gzip_simple' - # File.open('adresses.gz', 'w') do |file - # file.write GZip.gzip('Mum: 0123 456 789', 9) - # end - # - # If you provide a +level+, you can control how strong - # the string is compressed: - # - 0: no compression, only convert to gzip format - # - 1: compress fast - # - 7: compress more, but still fast (default) - # - 8: compress more, slower - # - 9: compress best, very slow - def GZip.gzip s, level = DEFAULT_GZIP_LEVEL - Zlib::Deflate.new(level).deflate s, Zlib::FINISH - end -end - - -# String extensions to use the GZip module. -# -# The methods gzip and gunzip provide an even more simple -# interface to the ZLib: -# -# # create a big string -# x = 'a' * 1000 -# -# # zip it -# x_gz = x.gzip -# -# # test the result -# puts 'Zipped %d bytes to %d bytes.' % [x.size, x_gz.size] -# #-> Zipped 1000 bytes to 19 bytes. -# -# # unzipping works -# p x_gz.gunzip == x #-> true -class String - # Returns the string, unzipped. - # See GZip.gunzip - def gunzip - GZip.gunzip self - end - # Replaces the string with its unzipped value. - # See GZip.gunzip - def gunzip! - replace gunzip - end - - # Returns the string, zipped. - # +level+ is the gzip compression level, see GZip.gzip. - def gzip level = GZip::DEFAULT_GZIP_LEVEL - GZip.gzip self, level - end - # Replaces the string with its zipped value. - # See GZip.gzip. - def gzip!(*args) - replace gzip(*args) - end -end - -if $0 == __FILE__ - eval DATA.read, nil, $0, __LINE__+4 -end - -__END__ -#CODE - -# Testing / Benchmark -x = 'a' * 1000 -x_gz = x.gzip -puts 'Zipped %d bytes to %d bytes.' % [x.size, x_gz.size] #-> Zipped 1000 bytes to 19 bytes. -p x_gz.gunzip == x #-> true - -require 'benchmark' - -INFO = 'packed to %0.3f%%' # :nodoc: - -x = Array.new(100000) { rand(255).chr + 'aaaaaaaaa' + rand(255).chr }.join -Benchmark.bm(10) do |bm| - for level in 0..9 - bm.report "zip #{level}" do - $x = x.gzip level - end - puts INFO % [100.0 * $x.size / x.size] - end - bm.report 'zip' do - $x = x.gzip - end - puts INFO % [100.0 * $x.size / x.size] - bm.report 'unzip' do - $x.gunzip - end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/plugin.rb b/vendor/gems/coderay-0.9.7/lib/coderay/helpers/plugin.rb deleted file mode 100644 index 2dffbdc9..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/plugin.rb +++ /dev/null @@ -1,349 +0,0 @@ -module CodeRay - -# = PluginHost -# -# A simple subclass plugin system. -# -# Example: -# class Generators < PluginHost -# plugin_path 'app/generators' -# end -# -# class Generator -# extend Plugin -# PLUGIN_HOST = Generators -# end -# -# class FancyGenerator < Generator -# register_for :fancy -# end -# -# Generators[:fancy] #-> FancyGenerator -# # or -# CodeRay.require_plugin 'Generators/fancy' -module PluginHost - - # Raised if Encoders::[] fails because: - # * a file could not be found - # * the requested Encoder is not registered - PluginNotFound = Class.new Exception - HostNotFound = Class.new Exception - - PLUGIN_HOSTS = [] - PLUGIN_HOSTS_BY_ID = {} # dummy hash - - # Loads all plugins using list and load. - def load_all - for plugin in list - load plugin - end - end - - # Returns the Plugin for +id+. - # - # Example: - # yaml_plugin = MyPluginHost[:yaml] - def [] id, *args, &blk - plugin = validate_id(id) - begin - plugin = plugin_hash.[] plugin, *args, &blk - end while plugin.is_a? Symbol - plugin - end - - # Alias for +[]+. - alias load [] - - def require_helper plugin_id, helper_name - path = path_to File.join(plugin_id, helper_name) - require path - end - - class << self - - # Adds the module/class to the PLUGIN_HOSTS list. - def extended mod - PLUGIN_HOSTS << mod - end - - # Warns you that you should not #include this module. - def included mod - warn "#{name} should not be included. Use extend." - end - - # Find the PluginHost for host_id. - def host_by_id host_id - unless PLUGIN_HOSTS_BY_ID.default_proc - ph = Hash.new do |h, a_host_id| - for host in PLUGIN_HOSTS - h[host.host_id] = host - end - h.fetch a_host_id, nil - end - PLUGIN_HOSTS_BY_ID.replace ph - end - PLUGIN_HOSTS_BY_ID[host_id] - end - - end - - # The path where the plugins can be found. - def plugin_path *args - unless args.empty? - @plugin_path = File.expand_path File.join(*args) - load_map - end - @plugin_path - end - - # The host's ID. - # - # If PLUGIN_HOST_ID is not set, it is simply the class name. - def host_id - if self.const_defined? :PLUGIN_HOST_ID - self::PLUGIN_HOST_ID - else - name - end - end - - # Map a plugin_id to another. - # - # Usage: Put this in a file plugin_path/_map.rb. - # - # class MyColorHost < PluginHost - # map :navy => :dark_blue, - # :maroon => :brown, - # :luna => :moon - # end - def map hash - for from, to in hash - from = validate_id from - to = validate_id to - plugin_hash[from] = to unless plugin_hash.has_key? from - end - end - - # Define the default plugin to use when no plugin is found - # for a given id. - # - # See also map. - # - # class MyColorHost < PluginHost - # map :navy => :dark_blue - # default :gray - # end - def default id = nil - if id - id = validate_id id - plugin_hash[nil] = id - else - plugin_hash[nil] - end - end - - # Every plugin must register itself for one or more - # +ids+ by calling register_for, which calls this method. - # - # See Plugin#register_for. - def register plugin, *ids - for id in ids - unless id.is_a? Symbol - raise ArgumentError, - "id must be a Symbol, but it was a #{id.class}" - end - plugin_hash[validate_id(id)] = plugin - end - end - - # A Hash of plugion_id => Plugin pairs. - def plugin_hash - @plugin_hash ||= create_plugin_hash - end - - # Returns an array of all .rb files in the plugin path. - # - # The extension .rb is not included. - def list - Dir[path_to('*')].select do |file| - File.basename(file)[/^(?!_)\w+\.rb$/] - end.map do |file| - File.basename file, '.rb' - end - end - - # Makes a map of all loaded plugins. - def inspect - map = plugin_hash.dup - map.each do |id, plugin| - map[id] = plugin.to_s[/(?>\w+)$/] - end - "#{name}[#{host_id}]#{map.inspect}" - end - -protected - # Created a new plugin list and stores it to @plugin_hash. - def create_plugin_hash - @plugin_hash = - Hash.new do |h, plugin_id| - id = validate_id(plugin_id) - path = path_to id - begin - require path - rescue LoadError => boom - if h.has_key? nil # default plugin - h[id] = h[nil] - else - raise PluginNotFound, 'Could not load plugin %p: %s' % [id, boom] - end - else - # Plugin should have registered by now - unless h.has_key? id - raise PluginNotFound, - "No #{self.name} plugin for #{id.inspect} found in #{path}." - end - end - h[id] - end - end - - # Loads the map file (see map). - # - # This is done automatically when plugin_path is called. - def load_map - mapfile = path_to '_map' - if File.exist? mapfile - require mapfile - elsif $VERBOSE - warn 'no _map.rb found for %s' % name - end - end - - # Returns the Plugin for +id+. - # Use it like Hash#fetch. - # - # Example: - # yaml_plugin = MyPluginHost[:yaml, :default] - def fetch id, *args, &blk - plugin_hash.fetch validate_id(id), *args, &blk - end - - # Returns the expected path to the plugin file for the given id. - def path_to plugin_id - File.join plugin_path, "#{plugin_id}.rb" - end - - # Converts +id+ to a Symbol if it is a String, - # or returns +id+ if it already is a Symbol. - # - # Raises +ArgumentError+ for all other objects, or if the - # given String includes non-alphanumeric characters (\W). - def validate_id id - if id.is_a? Symbol or id.nil? - id - elsif id.is_a? String - if id[/\w+/] == id - id.downcase.to_sym - else - raise ArgumentError, "Invalid id: '#{id}' given." - end - else - raise ArgumentError, - "String or Symbol expected, but #{id.class} given." - end - end - -end - - -# = Plugin -# -# Plugins have to include this module. -# -# IMPORTANT: use extend for this module. -# -# Example: see PluginHost. -module Plugin - - def included mod - warn "#{name} should not be included. Use extend." - end - - # Register this class for the given langs. - # Example: - # class MyPlugin < PluginHost::BaseClass - # register_for :my_id - # ... - # end - # - # See PluginHost.register. - def register_for *ids - plugin_host.register self, *ids - end - - # Returns the title of the plugin, or sets it to the - # optional argument +title+. - def title title = nil - if title - @title = title.to_s - else - @title ||= name[/([^:]+)$/, 1] - end - end - - # The host for this Plugin class. - def plugin_host host = nil - if host and not host.is_a? PluginHost - raise ArgumentError, - "PluginHost expected, but #{host.class} given." - end - self.const_set :PLUGIN_HOST, host if host - self::PLUGIN_HOST - end - - # Require some helper files. - # - # Example: - # - # class MyPlugin < PluginHost::BaseClass - # register_for :my_id - # helper :my_helper - # - # The above example loads the file myplugin/my_helper.rb relative to the - # file in which MyPlugin was defined. - # - # You can also load a helper from a different plugin: - # - # helper 'other_plugin/helper_name' - def helper *helpers - for helper in helpers - if helper.is_a?(String) && helper[/\//] - self::PLUGIN_HOST.require_helper $`, $' - else - self::PLUGIN_HOST.require_helper plugin_id, helper.to_s - end - end - end - - # Returns the pulgin id used by the engine. - def plugin_id - name[/\w+$/].downcase - end - -end - -# Convenience method for plugin loading. -# The syntax used is: -# -# CodeRay.require_plugin '/' -# -# Returns the loaded plugin. -def self.require_plugin path - host_id, plugin_id = path.split '/', 2 - host = PluginHost.host_by_id(host_id) - raise PluginHost::HostNotFound, - "No host for #{host_id.inspect} found." unless host - host.load plugin_id -end - -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/word_list.rb b/vendor/gems/coderay-0.9.7/lib/coderay/helpers/word_list.rb deleted file mode 100644 index 9b4f4569..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/helpers/word_list.rb +++ /dev/null @@ -1,138 +0,0 @@ -module CodeRay - -# = WordList -# -# A Hash subclass designed for mapping word lists to token types. -# -# Copyright (c) 2006 by murphy (Kornelius Kalnbach) -# -# License:: LGPL / ask the author -# Version:: 1.1 (2006-Oct-19) -# -# A WordList is a Hash with some additional features. -# It is intended to be used for keyword recognition. -# -# WordList is highly optimized to be used in Scanners, -# typically to decide whether a given ident is a special token. -# -# For case insensitive words use CaseIgnoringWordList. -# -# Example: -# -# # define word arrays -# RESERVED_WORDS = %w[ -# asm break case continue default do else -# ... -# ] -# -# PREDEFINED_TYPES = %w[ -# int long short char void -# ... -# ] -# -# PREDEFINED_CONSTANTS = %w[ -# EOF NULL ... -# ] -# -# # make a WordList -# IDENT_KIND = WordList.new(:ident). -# add(RESERVED_WORDS, :reserved). -# add(PREDEFINED_TYPES, :pre_type). -# add(PREDEFINED_CONSTANTS, :pre_constant) -# -# ... -# -# def scan_tokens tokens, options -# ... -# -# elsif scan(/[A-Za-z_][A-Za-z_0-9]*/) -# # use it -# kind = IDENT_KIND[match] -# ... -class WordList < Hash - - # Creates a new WordList with +default+ as default value. - # - # You can activate +caching+ to store the results for every [] request. - # - # With caching, methods like +include?+ or +delete+ may no longer behave - # as you expect. Therefore, it is recommended to use the [] method only. - def initialize default = false, caching = false, &block - if block - raise ArgumentError, 'Can\'t combine block with caching.' if caching - super(&block) - else - if caching - super() do |h, k| - h[k] = h.fetch k, default - end - else - super default - end - end - end - - # Add words to the list and associate them with +kind+. - # - # Returns +self+, so you can concat add calls. - def add words, kind = true - words.each do |word| - self[word] = kind - end - self - end - -end - - -# A CaseIgnoringWordList is like a WordList, only that -# keys are compared case-insensitively. -# -# Ignoring the text case is realized by sending the +downcase+ message to -# all keys. -# -# Caching usually makes a CaseIgnoringWordList faster, but it has to be -# activated explicitely. -class CaseIgnoringWordList < WordList - - # Creates a new case-insensitive WordList with +default+ as default value. - # - # You can activate caching to store the results for every [] request. - # This speeds up subsequent lookups for the same word, but also - # uses memory. - def initialize default = false, caching = false - if caching - super(default, false) do |h, k| - h[k] = h.fetch k.downcase, default - end - else - super(default, false) - extend Uncached - end - end - - module Uncached # :nodoc: - def [] key - super(key.downcase) - end - end - - # Add +words+ to the list and associate them with +kind+. - def add words, kind = true - words.each do |word| - self[word.downcase] = kind - end - self - end - -end - -end - -__END__ -# check memory consumption -END { - ObjectSpace.each_object(CodeRay::CaseIgnoringWordList) do |wl| - p wl.inject(0) { |memo, key, value| memo + key.size + 24 } - end -} \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanner.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanner.rb deleted file mode 100644 index b12c865f..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanner.rb +++ /dev/null @@ -1,298 +0,0 @@ -module CodeRay - - require 'coderay/helpers/plugin' - - # = Scanners - # - # This module holds the Scanner class and its subclasses. - # For example, the Ruby scanner is named CodeRay::Scanners::Ruby - # can be found in coderay/scanners/ruby. - # - # Scanner also provides methods and constants for the register - # mechanism and the [] method that returns the Scanner class - # belonging to the given lang. - # - # See PluginHost. - module Scanners - extend PluginHost - plugin_path File.dirname(__FILE__), 'scanners' - - require 'strscan' - - # = Scanner - # - # The base class for all Scanners. - # - # It is a subclass of Ruby's great +StringScanner+, which - # makes it easy to access the scanning methods inside. - # - # It is also +Enumerable+, so you can use it like an Array of - # Tokens: - # - # require 'coderay' - # - # c_scanner = CodeRay::Scanners[:c].new "if (*p == '{') nest++;" - # - # for text, kind in c_scanner - # puts text if kind == :operator - # end - # - # # prints: (*==)++; - # - # OK, this is a very simple example :) - # You can also use +map+, +any?+, +find+ and even +sort_by+, - # if you want. - class Scanner < StringScanner - - extend Plugin - plugin_host Scanners - - # Raised if a Scanner fails while scanning - ScanError = Class.new(Exception) - - require 'coderay/helpers/word_list' - - # The default options for all scanner classes. - # - # Define @default_options for subclasses. - DEFAULT_OPTIONS = { :stream => false } - - KINDS_NOT_LOC = [:comment, :doctype] - - class << self - - # Returns if the Scanner can be used in streaming mode. - def streamable? - is_a? Streamable - end - - def normify code - code = code.to_s - if code.respond_to?(:encoding) && (code.encoding.name != 'UTF-8' || !code.valid_encoding?) - code = code.dup - original_encoding = code.encoding - code.force_encoding 'Windows-1252' - unless code.valid_encoding? - code.force_encoding original_encoding - if code.encoding.name == 'UTF-8' - code.encode! 'UTF-16BE', :invalid => :replace, :undef => :replace, :replace => '?' - end - code.encode! 'UTF-8', :invalid => :replace, :undef => :replace, :replace => '?' - end - end - code.to_unix - end - - def file_extension extension = nil - if extension - @file_extension = extension.to_s - else - @file_extension ||= plugin_id.to_s - end - end - - end - -=begin -## Excluded for speed reasons; protected seems to make methods slow. - - # Save the StringScanner methods from being called. - # This would not be useful for highlighting. - strscan_public_methods = - StringScanner.instance_methods - - StringScanner.ancestors[1].instance_methods - protected(*strscan_public_methods) -=end - - # Create a new Scanner. - # - # * +code+ is the input String and is handled by the superclass - # StringScanner. - # * +options+ is a Hash with Symbols as keys. - # It is merged with the default options of the class (you can - # overwrite default options here.) - # * +block+ is the callback for streamed highlighting. - # - # If you set :stream to +true+ in the options, the Scanner uses a - # TokenStream with the +block+ as callback to handle the tokens. - # - # Else, a Tokens object is used. - def initialize code='', options = {}, &block - raise "I am only the basic Scanner class. I can't scan "\ - "anything. :( Use my subclasses." if self.class == Scanner - - @options = self.class::DEFAULT_OPTIONS.merge options - - super Scanner.normify(code) - - @tokens = options[:tokens] - if @options[:stream] - warn "warning in CodeRay::Scanner.new: :stream is set, "\ - "but no block was given" unless block_given? - raise NotStreamableError, self unless kind_of? Streamable - @tokens ||= TokenStream.new(&block) - else - warn "warning in CodeRay::Scanner.new: Block given, "\ - "but :stream is #{@options[:stream]}" if block_given? - @tokens ||= Tokens.new - end - @tokens.scanner = self - - setup - end - - def reset - super - reset_instance - end - - def string= code - code = Scanner.normify(code) - if defined?(RUBY_DESCRIPTION) && RUBY_DESCRIPTION['rubinius 1.0.1'] - reset_state - @string = code - else - super code - end - reset_instance - end - - # More mnemonic accessor name for the input string. - alias code string - alias code= string= - - # Returns the Plugin ID for this scanner. - def lang - self.class.plugin_id - end - - # Scans the code and returns all tokens in a Tokens object. - def tokenize new_string=nil, options = {} - options = @options.merge(options) - self.string = new_string if new_string - @cached_tokens = - if @options[:stream] # :stream must have been set already - reset unless new_string - scan_tokens @tokens, options - @tokens - else - scan_tokens @tokens, options - end - end - - def tokens - @cached_tokens ||= tokenize - end - - # Whether the scanner is in streaming mode. - def streaming? - !!@options[:stream] - end - - # Traverses the tokens. - def each &block - raise ArgumentError, - 'Cannot traverse TokenStream.' if @options[:stream] - tokens.each(&block) - end - include Enumerable - - # The current line position of the scanner. - # - # Beware, this is implemented inefficiently. It should be used - # for debugging only. - def line - string[0..pos].count("\n") + 1 - end - - def column pos = self.pos - return 0 if pos <= 0 - string = string() - if string.respond_to?(:bytesize) && (defined?(@bin_string) || string.bytesize != string.size) - @bin_string ||= string.dup.force_encoding('binary') - string = @bin_string - end - pos - (string.rindex(?\n, pos) || 0) - end - - def marshal_dump - @options - end - - def marshal_load options - @options = options - end - - protected - - # Can be implemented by subclasses to do some initialization - # that has to be done once per instance. - # - # Use reset for initialization that has to be done once per - # scan. - def setup - end - - # This is the central method, and commonly the only one a - # subclass implements. - # - # Subclasses must implement this method; it must return +tokens+ - # and must only use Tokens#<< for storing scanned tokens! - def scan_tokens tokens, options - raise NotImplementedError, - "#{self.class}#scan_tokens not implemented." - end - - def reset_instance - @tokens.clear unless @options[:keep_tokens] - @cached_tokens = nil - @bin_string = nil if defined? @bin_string - end - - # Scanner error with additional status information - def raise_inspect msg, tokens, state = 'No state given!', ambit = 30 - raise ScanError, <<-EOE % [ - - -***ERROR in %s: %s (after %d tokens) - -tokens: -%s - -current line: %d column: %d pos: %d -matched: %p state: %p -bol? = %p, eos? = %p - -surrounding code: -%p ~~ %p - - -***ERROR*** - - EOE - File.basename(caller[0]), - msg, - tokens.size, - tokens.last(10).map { |t| t.inspect }.join("\n"), - line, column, pos, - matched, state, bol?, eos?, - string[pos - ambit, ambit], - string[pos, ambit], - ] - end - - end - - end -end - -class String - # I love this hack. It seems to silence all dos/unix/mac newline problems. - def to_unix - if index ?\r - gsub(/\r\n?/, "\n") - else - self - end - end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/_map.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/_map.rb deleted file mode 100644 index 01078c1a..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/_map.rb +++ /dev/null @@ -1,23 +0,0 @@ -module CodeRay -module Scanners - - map \ - :h => :c, - :cplusplus => :cpp, - :'c++' => :cpp, - :ecma => :java_script, - :ecmascript => :java_script, - :ecma_script => :java_script, - :irb => :ruby, - :javascript => :java_script, - :js => :java_script, - :nitro => :nitro_xhtml, - :pascal => :delphi, - :plain => :plaintext, - :xhtml => :html, - :yml => :yaml - - default :plain - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/c.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/c.rb deleted file mode 100644 index d7f2be7c..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/c.rb +++ /dev/null @@ -1,203 +0,0 @@ -module CodeRay -module Scanners - - class C < Scanner - - include Streamable - - register_for :c - file_extension 'c' - - RESERVED_WORDS = [ - 'asm', 'break', 'case', 'continue', 'default', 'do', - 'else', 'enum', 'for', 'goto', 'if', 'return', - 'sizeof', 'struct', 'switch', 'typedef', 'union', 'while', - 'restrict', # added in C99 - ] - - PREDEFINED_TYPES = [ - 'int', 'long', 'short', 'char', - 'signed', 'unsigned', 'float', 'double', - 'bool', 'complex', # added in C99 - ] - - PREDEFINED_CONSTANTS = [ - 'EOF', 'NULL', - 'true', 'false', # added in C99 - ] - DIRECTIVES = [ - 'auto', 'extern', 'register', 'static', 'void', - 'const', 'volatile', # added in C89 - 'inline', # added in C99 - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(DIRECTIVES, :directive). - add(PREDEFINED_CONSTANTS, :pre_constant) - - ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - - def scan_tokens tokens, options - - state = :initial - label_expected = true - case_expected = false - label_expected_before_preproc_line = nil - in_preproc_line = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - if in_preproc_line && match != "\\\n" && match.index(?\n) - in_preproc_line = false - label_expected = label_expected_before_preproc_line - end - tokens << [match, :space] - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - kind = :comment - - elsif match = scan(/ \# \s* if \s* 0 /x) - match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? - kind = :comment - - elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) - label_expected = match =~ /[;\{\}]/ - if case_expected - label_expected = true if match == ':' - case_expected = false - end - kind = :operator - - elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = IDENT_KIND[match] - if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) - kind = :label - match << matched - else - label_expected = false - if kind == :reserved - case match - when 'case', 'default' - case_expected = true - end - end - end - - elsif scan(/\$/) - kind = :ident - - elsif match = scan(/L?"/) - tokens << [:open, :string] - if match[0] == ?L - tokens << ['L', :modifier] - match = '"' - end - state = :string - kind = :delimiter - - elsif scan(/#[ \t]*(\w*)/) - kind = :preprocessor - in_preproc_line = true - label_expected_before_preproc_line = label_expected - state = :include_expected if self[1] == 'include' - - elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) - label_expected = false - kind = :char - - elsif scan(/0[xX][0-9A-Fa-f]+/) - label_expected = false - kind = :hex - - elsif scan(/(?:0[0-7]+)(?![89.eEfF])/) - label_expected = false - kind = :oct - - elsif scan(/(?:\d+)(?![.eEfF])L?L?/) - label_expected = false - kind = :integer - - elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - label_expected = false - kind = :float - - else - getch - kind = :error - - end - - when :string - if scan(/[^\\\n"]+/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, :string] - state = :initial - label_expected = false - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/ \\ | $ /x) - tokens << [:close, :string] - kind = :error - state = :initial - label_expected = false - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - when :include_expected - if scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) - kind = :include - state = :initial - - elsif match = scan(/\s+/) - kind = :space - state = :initial if match.index ?\n - - else - state = :initial - next - - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, :string] - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/cpp.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/cpp.rb deleted file mode 100644 index c29083a4..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/cpp.rb +++ /dev/null @@ -1,228 +0,0 @@ -module CodeRay -module Scanners - - class CPlusPlus < Scanner - - include Streamable - - register_for :cpp - file_extension 'cpp' - title 'C++' - - # http://www.cppreference.com/wiki/keywords/start - RESERVED_WORDS = [ - 'and', 'and_eq', 'asm', 'bitand', 'bitor', 'break', - 'case', 'catch', 'class', 'compl', 'const_cast', - 'continue', 'default', 'delete', 'do', 'dynamic_cast', 'else', - 'enum', 'export', 'for', 'goto', 'if', 'namespace', 'new', - 'not', 'not_eq', 'or', 'or_eq', 'reinterpret_cast', 'return', - 'sizeof', 'static_cast', 'struct', 'switch', 'template', - 'throw', 'try', 'typedef', 'typeid', 'typename', 'union', - 'while', 'xor', 'xor_eq' - ] - - PREDEFINED_TYPES = [ - 'bool', 'char', 'double', 'float', 'int', 'long', - 'short', 'signed', 'unsigned', 'wchar_t', 'string' - ] - PREDEFINED_CONSTANTS = [ - 'false', 'true', - 'EOF', 'NULL', - ] - PREDEFINED_VARIABLES = [ - 'this' - ] - DIRECTIVES = [ - 'auto', 'const', 'explicit', 'extern', 'friend', 'inline', 'mutable', 'operator', - 'private', 'protected', 'public', 'register', 'static', 'using', 'virtual', 'void', - 'volatile' - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(PREDEFINED_VARIABLES, :local_variable). - add(DIRECTIVES, :directive). - add(PREDEFINED_CONSTANTS, :pre_constant) - - ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - - def scan_tokens tokens, options - - state = :initial - label_expected = true - case_expected = false - label_expected_before_preproc_line = nil - in_preproc_line = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - if in_preproc_line && match != "\\\n" && match.index(?\n) - in_preproc_line = false - label_expected = label_expected_before_preproc_line - end - tokens << [match, :space] - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - kind = :comment - - elsif match = scan(/ \# \s* if \s* 0 /x) - match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos? - kind = :comment - - elsif match = scan(/ [-+*=<>?:;,!&^|()\[\]{}~%]+ | \/=? | \.(?!\d) /x) - label_expected = match =~ /[;\{\}]/ - if case_expected - label_expected = true if match == ':' - case_expected = false - end - kind = :operator - - elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = IDENT_KIND[match] - if kind == :ident && label_expected && !in_preproc_line && scan(/:(?!:)/) - kind = :label - match << matched - else - label_expected = false - if kind == :reserved - case match - when 'class' - state = :class_name_expected - when 'case', 'default' - case_expected = true - end - end - end - - elsif scan(/\$/) - kind = :ident - - elsif match = scan(/L?"/) - tokens << [:open, :string] - if match[0] == ?L - tokens << ['L', :modifier] - match = '"' - end - state = :string - kind = :delimiter - - elsif scan(/#[ \t]*(\w*)/) - kind = :preprocessor - in_preproc_line = true - label_expected_before_preproc_line = label_expected - state = :include_expected if self[1] == 'include' - - elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) - label_expected = false - kind = :char - - elsif scan(/0[xX][0-9A-Fa-f]+/) - label_expected = false - kind = :hex - - elsif scan(/(?:0[0-7]+)(?![89.eEfF])/) - label_expected = false - kind = :oct - - elsif scan(/(?:\d+)(?![.eEfF])L?L?/) - label_expected = false - kind = :integer - - elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - label_expected = false - kind = :float - - else - getch - kind = :error - - end - - when :string - if scan(/[^\\"]+/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, :string] - state = :initial - label_expected = false - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/ \\ | $ /x) - tokens << [:close, :string] - kind = :error - state = :initial - label_expected = false - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - when :include_expected - if scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/) - kind = :include - state = :initial - - elsif match = scan(/\s+/) - kind = :space - state = :initial if match.index ?\n - - else - state = :initial - next - - end - - when :class_name_expected - if scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = :class - state = :initial - - elsif match = scan(/\s+/) - kind = :space - - else - getch - kind = :error - state = :initial - - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, :string] - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/css.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/css.rb deleted file mode 100644 index 08ecbb18..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/css.rb +++ /dev/null @@ -1,209 +0,0 @@ -module CodeRay -module Scanners - - class CSS < Scanner - - register_for :css - - KINDS_NOT_LOC = [ - :comment, - :class, :pseudo_class, :type, - :constant, :directive, - :key, :value, :operator, :color, :float, - :error, :important, - ] - - module RE - Hex = /[0-9a-fA-F]/ - Unicode = /\\#{Hex}{1,6}(?:\r\n|\s)?/ # differs from standard because it allows uppercase hex too - Escape = /#{Unicode}|\\[^\r\n\f0-9a-fA-F]/ - NMChar = /[-_a-zA-Z0-9]|#{Escape}/ - NMStart = /[_a-zA-Z]|#{Escape}/ - NL = /\r\n|\r|\n|\f/ - String1 = /"(?:[^\n\r\f\\"]|\\#{NL}|#{Escape})*"?/ # FIXME: buggy regexp - String2 = /'(?:[^\n\r\f\\']|\\#{NL}|#{Escape})*'?/ # FIXME: buggy regexp - String = /#{String1}|#{String2}/ - - HexColor = /#(?:#{Hex}{6}|#{Hex}{3})/ - Color = /#{HexColor}/ - - Num = /-?(?:[0-9]+|[0-9]*\.[0-9]+)/ - Name = /#{NMChar}+/ - Ident = /-?#{NMStart}#{NMChar}*/ - AtKeyword = /@#{Ident}/ - Percentage = /#{Num}%/ - - reldimensions = %w[em ex px] - absdimensions = %w[in cm mm pt pc] - Unit = Regexp.union(*(reldimensions + absdimensions)) - - Dimension = /#{Num}#{Unit}/ - - Comment = %r! /\* (?: .*? \*/ | .* ) !mx - Function = /(?:url|alpha)\((?:[^)\n\r\f]|\\\))*\)?/ - - Id = /##{Name}/ - Class = /\.#{Name}/ - PseudoClass = /:#{Name}/ - AttributeSelector = /\[[^\]]*\]?/ - - end - - def scan_tokens tokens, options - - value_expected = nil - states = [:initial] - - until eos? - - kind = nil - match = nil - - if scan(/\s+/) - kind = :space - - elsif case states.last - when :initial, :media - if scan(/(?>#{RE::Ident})(?!\()|\*/ox) - kind = :type - elsif scan RE::Class - kind = :class - elsif scan RE::Id - kind = :constant - elsif scan RE::PseudoClass - kind = :pseudo_class - elsif match = scan(RE::AttributeSelector) - # TODO: Improve highlighting inside of attribute selectors. - tokens << [:open, :string] - tokens << [match[0,1], :delimiter] - tokens << [match[1..-2], :content] if match.size > 2 - tokens << [match[-1,1], :delimiter] if match[-1] == ?] - tokens << [:close, :string] - next - elsif match = scan(/@media/) - kind = :directive - states.push :media_before_name - end - - when :block - if scan(/(?>#{RE::Ident})(?!\()/ox) - if value_expected - kind = :value - else - kind = :key - end - end - - when :media_before_name - if scan RE::Ident - kind = :type - states[-1] = :media_after_name - end - - when :media_after_name - if scan(/\{/) - kind = :operator - states[-1] = :media - end - - when :comment - if scan(/(?:[^*\s]|\*(?!\/))+/) - kind = :comment - elsif scan(/\*\//) - kind = :comment - states.pop - elsif scan(/\s+/) - kind = :space - end - - else - raise_inspect 'Unknown state', tokens - - end - - elsif scan(/\/\*/) - kind = :comment - states.push :comment - - elsif scan(/\{/) - value_expected = false - kind = :operator - states.push :block - - elsif scan(/\}/) - value_expected = false - if states.last == :block || states.last == :media - kind = :operator - states.pop - else - kind = :error - end - - elsif match = scan(/#{RE::String}/o) - tokens << [:open, :string] - tokens << [match[0, 1], :delimiter] - tokens << [match[1..-2], :content] if match.size > 2 - tokens << [match[-1, 1], :delimiter] if match.size >= 2 - tokens << [:close, :string] - next - - elsif match = scan(/#{RE::Function}/o) - tokens << [:open, :string] - start = match[/^\w+\(/] - tokens << [start, :delimiter] - if match[-1] == ?) - tokens << [match[start.size..-2], :content] - tokens << [')', :delimiter] - else - tokens << [match[start.size..-1], :content] - end - tokens << [:close, :string] - next - - elsif scan(/(?: #{RE::Dimension} | #{RE::Percentage} | #{RE::Num} )/ox) - kind = :float - - elsif scan(/#{RE::Color}/o) - kind = :color - - elsif scan(/! *important/) - kind = :important - - elsif scan(/rgb\([^()\n]*\)?/) - kind = :color - - elsif scan(/#{RE::AtKeyword}/o) - kind = :directive - - elsif match = scan(/ [+>:;,.=()\/] /x) - if match == ':' - value_expected = true - elsif match == ';' - value_expected = false - end - kind = :operator - - else - getch - kind = :error - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/debug.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/debug.rb deleted file mode 100644 index 0e78b239..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/debug.rb +++ /dev/null @@ -1,62 +0,0 @@ -module CodeRay -module Scanners - - # = Debug Scanner - class Debug < Scanner - - include Streamable - register_for :debug - file_extension 'raydebug' - title 'CodeRay Token Dump' - - protected - def scan_tokens tokens, options - - opened_tokens = [] - - until eos? - - kind = nil - match = nil - - if scan(/\s+/) - tokens << [matched, :space] - next - - elsif scan(/ (\w+) \( ( [^\)\\]* ( \\. [^\)\\]* )* ) \) /x) - kind = self[1].to_sym - match = self[2].gsub(/\\(.)/, '\1') - - elsif scan(/ (\w+) < /x) - kind = self[1].to_sym - opened_tokens << kind - match = :open - - elsif !opened_tokens.empty? && scan(/ > /x) - kind = opened_tokens.pop || :error - match = :close - - else - kind = :error - getch - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/delphi.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/delphi.rb deleted file mode 100644 index de0ee718..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/delphi.rb +++ /dev/null @@ -1,150 +0,0 @@ -module CodeRay -module Scanners - - class Delphi < Scanner - - register_for :delphi - file_extension 'pas' - - RESERVED_WORDS = [ - 'and', 'array', 'as', 'at', 'asm', 'at', 'begin', 'case', 'class', - 'const', 'constructor', 'destructor', 'dispinterface', 'div', 'do', - 'downto', 'else', 'end', 'except', 'exports', 'file', 'finalization', - 'finally', 'for', 'function', 'goto', 'if', 'implementation', 'in', - 'inherited', 'initialization', 'inline', 'interface', 'is', 'label', - 'library', 'mod', 'nil', 'not', 'object', 'of', 'or', 'out', 'packed', - 'procedure', 'program', 'property', 'raise', 'record', 'repeat', - 'resourcestring', 'set', 'shl', 'shr', 'string', 'then', 'threadvar', - 'to', 'try', 'type', 'unit', 'until', 'uses', 'var', 'while', 'with', - 'xor', 'on' - ] - - DIRECTIVES = [ - 'absolute', 'abstract', 'assembler', 'at', 'automated', 'cdecl', - 'contains', 'deprecated', 'dispid', 'dynamic', 'export', - 'external', 'far', 'forward', 'implements', 'local', - 'near', 'nodefault', 'on', 'overload', 'override', - 'package', 'pascal', 'platform', 'private', 'protected', 'public', - 'published', 'read', 'readonly', 'register', 'reintroduce', - 'requires', 'resident', 'safecall', 'stdcall', 'stored', 'varargs', - 'virtual', 'write', 'writeonly' - ] - - IDENT_KIND = CaseIgnoringWordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(DIRECTIVES, :directive) - - NAME_FOLLOWS = CaseIgnoringWordList.new(false). - add(%w(procedure function .)) - - private - def scan_tokens tokens, options - - state = :initial - last_token = '' - - until eos? - - kind = nil - match = nil - - if state == :initial - - if scan(/ \s+ /x) - tokens << [matched, :space] - next - - elsif scan(%r! \{ \$ [^}]* \}? | \(\* \$ (?: .*? \*\) | .* ) !mx) - tokens << [matched, :preprocessor] - next - - elsif scan(%r! // [^\n]* | \{ [^}]* \}? | \(\* (?: .*? \*\) | .* ) !mx) - tokens << [matched, :comment] - next - - elsif match = scan(/ <[>=]? | >=? | :=? | [-+=*\/;,@\^|\(\)\[\]] | \.\. /x) - kind = :operator - - elsif match = scan(/\./) - kind = :operator - if last_token == 'end' - tokens << [match, kind] - next - end - - elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = NAME_FOLLOWS[last_token] ? :ident : IDENT_KIND[match] - - elsif match = scan(/ ' ( [^\n']|'' ) (?:'|$) /x) - tokens << [:open, :char] - tokens << ["'", :delimiter] - tokens << [self[1], :content] - tokens << ["'", :delimiter] - tokens << [:close, :char] - next - - elsif match = scan(/ ' /x) - tokens << [:open, :string] - state = :string - kind = :delimiter - - elsif scan(/ \# (?: \d+ | \$[0-9A-Fa-f]+ ) /x) - kind = :char - - elsif scan(/ \$ [0-9A-Fa-f]+ /x) - kind = :hex - - elsif scan(/ (?: \d+ ) (?![eE]|\.[^.]) /x) - kind = :integer - - elsif scan(/ \d+ (?: \.\d+ (?: [eE][+-]? \d+ )? | [eE][+-]? \d+ ) /x) - kind = :float - - else - kind = :error - getch - - end - - elsif state == :string - if scan(/[^\n']+/) - kind = :content - elsif scan(/''/) - kind = :char - elsif scan(/'/) - tokens << ["'", :delimiter] - tokens << [:close, :string] - state = :initial - next - elsif scan(/\n/) - tokens << [:close, :string] - kind = :error - state = :initial - else - raise "else case \' reached; %p not handled." % peek(1), tokens - end - - else - raise 'else-case reached', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, state - end - raise_inspect 'Empty token', tokens unless match - - last_token = match - tokens << [match, kind] - - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/diff.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/diff.rb deleted file mode 100644 index 353b9669..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/diff.rb +++ /dev/null @@ -1,110 +0,0 @@ -module CodeRay -module Scanners - - class Diff < Scanner - - register_for :diff - title 'diff output' - - def scan_tokens tokens, options - - line_kind = nil - state = :initial - - until eos? - kind = match = nil - - if match = scan(/\n/) - if line_kind - tokens << [:end_line, line_kind] - line_kind = nil - end - tokens << [match, :space] - next - end - - case state - - when :initial - if match = scan(/--- |\+\+\+ |=+|_+/) - tokens << [:begin_line, line_kind = :head] - tokens << [match, :head] - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/Index: |Property changes on: /) - tokens << [:begin_line, line_kind = :head] - tokens << [match, :head] - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/Added: /) - tokens << [:begin_line, line_kind = :head] - tokens << [match, :head] - next unless match = scan(/.+/) - kind = :plain - state = :added - elsif match = scan(/\\ /) - tokens << [:begin_line, line_kind = :change] - tokens << [match, :change] - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/@@(?>[^@\n]*)@@/) - if check(/\n|$/) - tokens << [:begin_line, line_kind = :change] - else - tokens << [:open, :change] - end - tokens << [match[0,2], :change] - tokens << [match[2...-2], :plain] - tokens << [match[-2,2], :change] - tokens << [:close, :change] unless line_kind - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/\+/) - tokens << [:begin_line, line_kind = :insert] - tokens << [match, :insert] - next unless match = scan(/.+/) - kind = :plain - elsif match = scan(/-/) - tokens << [:begin_line, line_kind = :delete] - tokens << [match, :delete] - next unless match = scan(/.+/) - kind = :plain - elsif scan(/ .*/) - kind = :comment - elsif scan(/.+/) - tokens << [:begin_line, line_kind = :comment] - kind = :plain - else - raise_inspect 'else case rached' - end - - when :added - if match = scan(/ \+/) - tokens << [:begin_line, line_kind = :insert] - tokens << [match, :insert] - next unless match = scan(/.+/) - kind = :plain - else - state = :initial - next - end - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - end - - tokens << [:end_line, line_kind] if line_kind - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/groovy.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/groovy.rb deleted file mode 100644 index 17330e64..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/groovy.rb +++ /dev/null @@ -1,264 +0,0 @@ -module CodeRay -module Scanners - - load :java - - class Groovy < Java - - include Streamable - register_for :groovy - - # TODO: Check this! - GROOVY_KEYWORDS = %w[ - as assert def in - ] - KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ - case instanceof new return throw typeof while as assert in - ] - GROOVY_MAGIC_VARIABLES = %w[ it ] - - IDENT_KIND = Java::IDENT_KIND.dup. - add(GROOVY_KEYWORDS, :keyword). - add(GROOVY_MAGIC_VARIABLES, :local_variable) - - ESCAPE = / [bfnrtv$\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x # no 4-byte unicode chars? U[a-fA-F0-9]{8} - REGEXP_ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | \d | [bBdDsSwW\/] /x - - # TODO: interpretation inside ', ", / - STRING_CONTENT_PATTERN = { - "'" => /(?>\\[^\\'\n]+|[^\\'\n]+)+/, - '"' => /[^\\$"\n]+/, - "'''" => /(?>[^\\']+|'(?!''))+/, - '"""' => /(?>[^\\$"]+|"(?!""))+/, - '/' => /[^\\$\/\n]+/, - } - - def scan_tokens tokens, options - - state = :initial - inline_block_stack = [] - inline_block_paren_depth = nil - string_delimiter = nil - import_clause = class_name_follows = last_token = after_def = false - value_expected = true - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - tokens << [match, :space] - if match.index ?\n - import_clause = after_def = false - value_expected = true unless value_expected - end - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - value_expected = true - after_def = false - kind = :comment - - elsif bol? && scan(/ \#!.* /x) - kind = :doctype - - elsif import_clause && scan(/ (?!as) #{IDENT} (?: \. #{IDENT} )* (?: \.\* )? /ox) - after_def = value_expected = false - kind = :include - - elsif match = scan(/ #{IDENT} | \[\] /ox) - kind = IDENT_KIND[match] - value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] - if last_token == '.' - kind = :ident - elsif class_name_follows - kind = :class - class_name_follows = false - elsif after_def && check(/\s*[({]/) - kind = :method - after_def = false - elsif kind == :ident && last_token != '?' && check(/:/) - kind = :key - else - class_name_follows = true if match == 'class' || (import_clause && match == 'as') - import_clause = match == 'import' - after_def = true if match == 'def' - end - - elsif scan(/;/) - import_clause = after_def = false - value_expected = true - kind = :operator - - elsif scan(/\{/) - class_name_follows = after_def = false - value_expected = true - kind = :operator - if !inline_block_stack.empty? - inline_block_paren_depth += 1 - end - - # TODO: ~'...', ~"..." and ~/.../ style regexps - elsif match = scan(/ \.\.] | \+\+ | - && | \|\| | \*\*=? | ==?~ | <=?>? | [-+*%^~&|>=!]=? | <<>>?=? /x) - value_expected = true - value_expected = :regexp if match == '~' - after_def = false - kind = :operator - - elsif match = scan(/ [)\]}] /x) - value_expected = after_def = false - if !inline_block_stack.empty? && match == '}' - inline_block_paren_depth -= 1 - if inline_block_paren_depth == 0 # closing brace of inline block reached - tokens << [match, :inline_delimiter] - tokens << [:close, :inline] - state, string_delimiter, inline_block_paren_depth = inline_block_stack.pop - next - end - end - kind = :operator - - elsif check(/[\d.]/) - after_def = value_expected = false - if scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - elsif scan(/(?>0[0-7]+)(?![89.eEfF])/) - kind = :oct - elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) - kind = :float - elsif scan(/\d+[lLgG]?/) - kind = :integer - end - - elsif match = scan(/'''|"""/) - after_def = value_expected = false - state = :multiline_string - tokens << [:open, :string] - string_delimiter = match - kind = :delimiter - - # TODO: record.'name' - elsif match = scan(/["']/) - after_def = value_expected = false - state = match == '/' ? :regexp : :string - tokens << [:open, state] - string_delimiter = match - kind = :delimiter - - elsif value_expected && (match = scan(/\//)) - after_def = value_expected = false - tokens << [:open, :regexp] - state = :regexp - string_delimiter = '/' - kind = :delimiter - - elsif scan(/ @ #{IDENT} /ox) - after_def = value_expected = false - kind = :annotation - - elsif scan(/\//) - after_def = false - value_expected = true - kind = :operator - - else - getch - kind = :error - - end - - when :string, :regexp, :multiline_string - if scan(STRING_CONTENT_PATTERN[string_delimiter]) - kind = :content - - elsif match = scan(state == :multiline_string ? /'''|"""/ : /["'\/]/) - tokens << [match, :delimiter] - if state == :regexp - # TODO: regexp modifiers? s, m, x, i? - modifiers = scan(/[ix]+/) - tokens << [modifiers, :modifier] if modifiers && !modifiers.empty? - end - state = :string if state == :multiline_string - tokens << [:close, state] - string_delimiter = nil - after_def = value_expected = false - state = :initial - next - - elsif (state == :string || state == :multiline_string) && - (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) - if string_delimiter[0] == ?' && !(match == "\\\\" || match == "\\'") - kind = :content - else - kind = :char - end - elsif state == :regexp && scan(/ \\ (?: #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - - elsif match = scan(/ \$ #{IDENT} /mox) - tokens << [:open, :inline] - tokens << ['$', :inline_delimiter] - match = match[1..-1] - tokens << [match, IDENT_KIND[match]] - tokens << [:close, :inline] - next - elsif match = scan(/ \$ \{ /x) - tokens << [:open, :inline] - tokens << ['${', :inline_delimiter] - inline_block_stack << [state, string_delimiter, inline_block_paren_depth] - inline_block_paren_depth = 1 - state = :initial - next - - elsif scan(/ \$ /mx) - kind = :content - - elsif scan(/ \\. /mx) - kind = :content - - elsif scan(/ \\ | \n /x) - tokens << [:close, state] - kind = :error - after_def = value_expected = false - state = :initial - - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - last_token = match unless [:space, :comment, :doctype].include? kind - - tokens << [match, kind] - - end - - if [:multiline_string, :string, :regexp].include? state - tokens << [:close, state] - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/html.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/html.rb deleted file mode 100644 index 009a461d..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/html.rb +++ /dev/null @@ -1,182 +0,0 @@ -module CodeRay -module Scanners - - # HTML Scanner - class HTML < Scanner - - include Streamable - register_for :html - - KINDS_NOT_LOC = [ - :comment, :doctype, :preprocessor, - :tag, :attribute_name, :operator, - :attribute_value, :delimiter, :content, - :plain, :entity, :error - ] - - ATTR_NAME = /[\w.:-]+/ - ATTR_VALUE_UNQUOTED = ATTR_NAME - TAG_END = /\/?>/ - HEX = /[0-9a-fA-F]/ - ENTITY = / - & - (?: - \w+ - | - \# - (?: - \d+ - | - x#{HEX}+ - ) - ) - ; - /ox - - PLAIN_STRING_CONTENT = { - "'" => /[^&'>\n]+/, - '"' => /[^&">\n]+/, - } - - def reset - super - @state = :initial - end - - private - def setup - @state = :initial - @plain_string_content = nil - end - - def scan_tokens tokens, options - - state = @state - plain_string_content = @plain_string_content - - until eos? - - kind = nil - match = nil - - if scan(/\s+/m) - kind = :space - - else - - case state - - when :initial - if scan(//m) - kind = :comment - elsif scan(//m) - kind = :doctype - elsif scan(/<\?xml.*?\?>/m) - kind = :preprocessor - elsif scan(/<\?.*?\?>|<%.*?%>/m) - kind = :comment - elsif scan(/<\/[-\w.:]*>/m) - kind = :tag - elsif match = scan(/<[-\w.:]+>?/m) - kind = :tag - state = :attribute unless match[-1] == ?> - elsif scan(/[^<>&]+/) - kind = :plain - elsif scan(/#{ENTITY}/ox) - kind = :entity - elsif scan(/[<>&]/) - kind = :error - else - raise_inspect '[BUG] else-case reached with state %p' % [state], tokens - end - - when :attribute - if scan(/#{TAG_END}/o) - kind = :tag - state = :initial - elsif scan(/#{ATTR_NAME}/o) - kind = :attribute_name - state = :attribute_equal - else - kind = :error - getch - end - - when :attribute_equal - if scan(/=/) - kind = :operator - state = :attribute_value - elsif scan(/#{ATTR_NAME}/o) - kind = :attribute_name - elsif scan(/#{TAG_END}/o) - kind = :tag - state = :initial - elsif scan(/./) - kind = :error - state = :attribute - end - - when :attribute_value - if scan(/#{ATTR_VALUE_UNQUOTED}/o) - kind = :attribute_value - state = :attribute - elsif match = scan(/["']/) - tokens << [:open, :string] - state = :attribute_value_string - plain_string_content = PLAIN_STRING_CONTENT[match] - kind = :delimiter - elsif scan(/#{TAG_END}/o) - kind = :tag - state = :initial - else - kind = :error - getch - end - - when :attribute_value_string - if scan(plain_string_content) - kind = :content - elsif scan(/['"]/) - tokens << [matched, :delimiter] - tokens << [:close, :string] - state = :attribute - next - elsif scan(/#{ENTITY}/ox) - kind = :entity - elsif scan(/&/) - kind = :content - elsif scan(/[\n>]/) - tokens << [:close, :string] - kind = :error - state = :initial - end - - else - raise_inspect 'Unknown state: %p' % [state], tokens - - end - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, state - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - end - - if options[:keep_state] - @state = state - @plain_string_content = plain_string_content - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java.rb deleted file mode 100644 index caf36199..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java.rb +++ /dev/null @@ -1,176 +0,0 @@ -module CodeRay -module Scanners - - class Java < Scanner - - include Streamable - register_for :java - helper :builtin_types - - # http://java.sun.com/docs/books/tutorial/java/nutsandbolts/_keywords.html - KEYWORDS = %w[ - assert break case catch continue default do else - finally for if instanceof import new package - return switch throw try typeof while - debugger export - ] - RESERVED = %w[ const goto ] - CONSTANTS = %w[ false null true ] - MAGIC_VARIABLES = %w[ this super ] - TYPES = %w[ - boolean byte char class double enum float int interface long - short void - ] << '[]' # because int[] should be highlighted as a type - DIRECTIVES = %w[ - abstract extends final implements native private protected public - static strictfp synchronized throws transient volatile - ] - - IDENT_KIND = WordList.new(:ident). - add(KEYWORDS, :keyword). - add(RESERVED, :reserved). - add(CONSTANTS, :pre_constant). - add(MAGIC_VARIABLES, :local_variable). - add(TYPES, :type). - add(BuiltinTypes::List, :pre_type). - add(BuiltinTypes::List.select { |builtin| builtin[/(Error|Exception)$/] }, :exception). - add(DIRECTIVES, :directive) - - ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - STRING_CONTENT_PATTERN = { - "'" => /[^\\']+/, - '"' => /[^\\"]+/, - '/' => /[^\\\/]+/, - } - IDENT = /[a-zA-Z_][A-Za-z_0-9]*/ - - def scan_tokens tokens, options - - state = :initial - string_delimiter = nil - import_clause = class_name_follows = last_token_dot = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - tokens << [match, :space] - next - - elsif match = scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - tokens << [match, :comment] - next - - elsif import_clause && scan(/ #{IDENT} (?: \. #{IDENT} )* /ox) - kind = :include - - elsif match = scan(/ #{IDENT} | \[\] /ox) - kind = IDENT_KIND[match] - if last_token_dot - kind = :ident - elsif class_name_follows - kind = :class - class_name_follows = false - else - import_clause = true if match == 'import' - class_name_follows = true if match == 'class' || match == 'interface' - end - - elsif scan(/ \.(?!\d) | [,?:()\[\]}] | -- | \+\+ | && | \|\| | \*\*=? | [-+*\/%^~&|<>=!]=? | <<>>?=? /x) - kind = :operator - - elsif scan(/;/) - import_clause = false - kind = :operator - - elsif scan(/\{/) - class_name_follows = false - kind = :operator - - elsif check(/[\d.]/) - if scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - elsif scan(/(?>0[0-7]+)(?![89.eEfF])/) - kind = :oct - elsif scan(/\d+[fFdD]|\d*\.\d+(?:[eE][+-]?\d+)?[fFdD]?|\d+[eE][+-]?\d+[fFdD]?/) - kind = :float - elsif scan(/\d+[lL]?/) - kind = :integer - end - - elsif match = scan(/["']/) - tokens << [:open, :string] - state = :string - string_delimiter = match - kind = :delimiter - - elsif scan(/ @ #{IDENT} /ox) - kind = :annotation - - else - getch - kind = :error - - end - - when :string - if scan(STRING_CONTENT_PATTERN[string_delimiter]) - kind = :content - elsif match = scan(/["'\/]/) - tokens << [match, :delimiter] - tokens << [:close, state] - string_delimiter = nil - state = :initial - next - elsif state == :string && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) - if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") - kind = :content - else - kind = :char - end - elsif scan(/\\./m) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, state] - kind = :error - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - last_token_dot = match == '.' - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, state] - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java/builtin_types.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java/builtin_types.rb deleted file mode 100644 index 8087edd2..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java/builtin_types.rb +++ /dev/null @@ -1,419 +0,0 @@ -module CodeRay -module Scanners - - module Java::BuiltinTypes # :nodoc: - - List = %w[ - AbstractAction AbstractBorder AbstractButton AbstractCellEditor AbstractCollection - AbstractColorChooserPanel AbstractDocument AbstractExecutorService AbstractInterruptibleChannel - AbstractLayoutCache AbstractList AbstractListModel AbstractMap AbstractMethodError AbstractPreferences - AbstractQueue AbstractQueuedSynchronizer AbstractSelectableChannel AbstractSelectionKey AbstractSelector - AbstractSequentialList AbstractSet AbstractSpinnerModel AbstractTableModel AbstractUndoableEdit - AbstractWriter AccessControlContext AccessControlException AccessController AccessException Accessible - AccessibleAction AccessibleAttributeSequence AccessibleBundle AccessibleComponent AccessibleContext - AccessibleEditableText AccessibleExtendedComponent AccessibleExtendedTable AccessibleExtendedText - AccessibleHyperlink AccessibleHypertext AccessibleIcon AccessibleKeyBinding AccessibleObject - AccessibleRelation AccessibleRelationSet AccessibleResourceBundle AccessibleRole AccessibleSelection - AccessibleState AccessibleStateSet AccessibleStreamable AccessibleTable AccessibleTableModelChange - AccessibleText AccessibleTextSequence AccessibleValue AccountException AccountExpiredException - AccountLockedException AccountNotFoundException Acl AclEntry AclNotFoundException Action ActionEvent - ActionListener ActionMap ActionMapUIResource Activatable ActivateFailedException ActivationDesc - ActivationException ActivationGroup ActivationGroupDesc ActivationGroupID ActivationGroup_Stub - ActivationID ActivationInstantiator ActivationMonitor ActivationSystem Activator ActiveEvent - ActivityCompletedException ActivityRequiredException Adjustable AdjustmentEvent AdjustmentListener - Adler32 AffineTransform AffineTransformOp AlgorithmParameterGenerator AlgorithmParameterGeneratorSpi - AlgorithmParameters AlgorithmParameterSpec AlgorithmParametersSpi AllPermission AlphaComposite - AlreadyBoundException AlreadyConnectedException AncestorEvent AncestorListener AnnotatedElement - Annotation AnnotationFormatError AnnotationTypeMismatchException AppConfigurationEntry Appendable Applet - AppletContext AppletInitializer AppletStub Arc2D Area AreaAveragingScaleFilter ArithmeticException Array - ArrayBlockingQueue ArrayIndexOutOfBoundsException ArrayList Arrays ArrayStoreException ArrayType - AssertionError AsyncBoxView AsynchronousCloseException AtomicBoolean AtomicInteger AtomicIntegerArray - AtomicIntegerFieldUpdater AtomicLong AtomicLongArray AtomicLongFieldUpdater AtomicMarkableReference - AtomicReference AtomicReferenceArray AtomicReferenceFieldUpdater AtomicStampedReference Attribute - AttributeChangeNotification AttributeChangeNotificationFilter AttributedCharacterIterator - AttributedString AttributeException AttributeInUseException AttributeList AttributeModificationException - AttributeNotFoundException Attributes AttributeSet AttributeSetUtilities AttributeValueExp AudioClip - AudioFileFormat AudioFileReader AudioFileWriter AudioFormat AudioInputStream AudioPermission AudioSystem - AuthenticationException AuthenticationNotSupportedException Authenticator AuthorizeCallback - AuthPermission AuthProvider Autoscroll AWTError AWTEvent AWTEventListener AWTEventListenerProxy - AWTEventMulticaster AWTException AWTKeyStroke AWTPermission BackingStoreException - BadAttributeValueExpException BadBinaryOpValueExpException BadLocationException BadPaddingException - BadStringOperationException BandCombineOp BandedSampleModel BaseRowSet BasicArrowButton BasicAttribute - BasicAttributes BasicBorders BasicButtonListener BasicButtonUI BasicCheckBoxMenuItemUI BasicCheckBoxUI - BasicColorChooserUI BasicComboBoxEditor BasicComboBoxRenderer BasicComboBoxUI BasicComboPopup - BasicControl BasicDesktopIconUI BasicDesktopPaneUI BasicDirectoryModel BasicEditorPaneUI - BasicFileChooserUI BasicFormattedTextFieldUI BasicGraphicsUtils BasicHTML BasicIconFactory - BasicInternalFrameTitlePane BasicInternalFrameUI BasicLabelUI BasicListUI BasicLookAndFeel - BasicMenuBarUI BasicMenuItemUI BasicMenuUI BasicOptionPaneUI BasicPanelUI BasicPasswordFieldUI - BasicPermission BasicPopupMenuSeparatorUI BasicPopupMenuUI BasicProgressBarUI BasicRadioButtonMenuItemUI - BasicRadioButtonUI BasicRootPaneUI BasicScrollBarUI BasicScrollPaneUI BasicSeparatorUI BasicSliderUI - BasicSpinnerUI BasicSplitPaneDivider BasicSplitPaneUI BasicStroke BasicTabbedPaneUI BasicTableHeaderUI - BasicTableUI BasicTextAreaUI BasicTextFieldUI BasicTextPaneUI BasicTextUI BasicToggleButtonUI - BasicToolBarSeparatorUI BasicToolBarUI BasicToolTipUI BasicTreeUI BasicViewportUI BatchUpdateException - BeanContext BeanContextChild BeanContextChildComponentProxy BeanContextChildSupport - BeanContextContainerProxy BeanContextEvent BeanContextMembershipEvent BeanContextMembershipListener - BeanContextProxy BeanContextServiceAvailableEvent BeanContextServiceProvider - BeanContextServiceProviderBeanInfo BeanContextServiceRevokedEvent BeanContextServiceRevokedListener - BeanContextServices BeanContextServicesListener BeanContextServicesSupport BeanContextSupport - BeanDescriptor BeanInfo Beans BevelBorder Bidi BigDecimal BigInteger BinaryRefAddr BindException Binding - BitSet Blob BlockingQueue BlockView BMPImageWriteParam Book Boolean BooleanControl Border BorderFactory - BorderLayout BorderUIResource BoundedRangeModel Box BoxLayout BoxView BreakIterator - BrokenBarrierException Buffer BufferCapabilities BufferedImage BufferedImageFilter BufferedImageOp - BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter BufferOverflowException - BufferStrategy BufferUnderflowException Button ButtonGroup ButtonModel ButtonUI Byte - ByteArrayInputStream ByteArrayOutputStream ByteBuffer ByteChannel ByteLookupTable ByteOrder CachedRowSet - CacheRequest CacheResponse Calendar Callable CallableStatement Callback CallbackHandler - CancelablePrintJob CancellationException CancelledKeyException CannotProceedException - CannotRedoException CannotUndoException Canvas CardLayout Caret CaretEvent CaretListener CellEditor - CellEditorListener CellRendererPane Certificate CertificateEncodingException CertificateException - CertificateExpiredException CertificateFactory CertificateFactorySpi CertificateNotYetValidException - CertificateParsingException CertPath CertPathBuilder CertPathBuilderException CertPathBuilderResult - CertPathBuilderSpi CertPathParameters CertPathTrustManagerParameters CertPathValidator - CertPathValidatorException CertPathValidatorResult CertPathValidatorSpi CertSelector CertStore - CertStoreException CertStoreParameters CertStoreSpi ChangedCharSetException ChangeEvent ChangeListener - Channel Channels Character CharacterCodingException CharacterIterator CharArrayReader CharArrayWriter - CharBuffer CharConversionException CharSequence Charset CharsetDecoder CharsetEncoder CharsetProvider - Checkbox CheckboxGroup CheckboxMenuItem CheckedInputStream CheckedOutputStream Checksum Choice - ChoiceCallback ChoiceFormat Chromaticity Cipher CipherInputStream CipherOutputStream CipherSpi Class - ClassCastException ClassCircularityError ClassDefinition ClassDesc ClassFileTransformer ClassFormatError - ClassLoader ClassLoaderRepository ClassLoadingMXBean ClassNotFoundException Clip Clipboard - ClipboardOwner Clob Cloneable CloneNotSupportedException Closeable ClosedByInterruptException - ClosedChannelException ClosedSelectorException CMMException CoderMalfunctionError CoderResult CodeSigner - CodeSource CodingErrorAction CollationElementIterator CollationKey Collator Collection - CollectionCertStoreParameters Collections Color ColorChooserComponentFactory ColorChooserUI - ColorConvertOp ColorModel ColorSelectionModel ColorSpace ColorSupported ColorType ColorUIResource - ComboBoxEditor ComboBoxModel ComboBoxUI ComboPopup CommunicationException Comparable Comparator - CompilationMXBean Compiler CompletionService Component ComponentAdapter ComponentColorModel - ComponentEvent ComponentInputMap ComponentInputMapUIResource ComponentListener ComponentOrientation - ComponentSampleModel ComponentUI ComponentView Composite CompositeContext CompositeData - CompositeDataSupport CompositeName CompositeType CompositeView CompoundBorder CompoundControl - CompoundEdit CompoundName Compression ConcurrentHashMap ConcurrentLinkedQueue ConcurrentMap - ConcurrentModificationException Condition Configuration ConfigurationException ConfirmationCallback - ConnectException ConnectIOException Connection ConnectionEvent ConnectionEventListener - ConnectionPendingException ConnectionPoolDataSource ConsoleHandler Constructor Container - ContainerAdapter ContainerEvent ContainerListener ContainerOrderFocusTraversalPolicy ContentHandler - ContentHandlerFactory ContentModel Context ContextNotEmptyException ContextualRenderedImageFactory - Control ControlFactory ControllerEventListener ConvolveOp CookieHandler Copies CopiesSupported - CopyOnWriteArrayList CopyOnWriteArraySet CountDownLatch CounterMonitor CounterMonitorMBean CRC32 - CredentialException CredentialExpiredException CredentialNotFoundException CRL CRLException CRLSelector - CropImageFilter CSS CubicCurve2D Currency Cursor Customizer CyclicBarrier DatabaseMetaData DataBuffer - DataBufferByte DataBufferDouble DataBufferFloat DataBufferInt DataBufferShort DataBufferUShort - DataFlavor DataFormatException DatagramChannel DatagramPacket DatagramSocket DatagramSocketImpl - DatagramSocketImplFactory DataInput DataInputStream DataLine DataOutput DataOutputStream DataSource - DataTruncation DatatypeConfigurationException DatatypeConstants DatatypeFactory Date DateFormat - DateFormatSymbols DateFormatter DateTimeAtCompleted DateTimeAtCreation DateTimeAtProcessing - DateTimeSyntax DebugGraphics DecimalFormat DecimalFormatSymbols DefaultBoundedRangeModel - DefaultButtonModel DefaultCaret DefaultCellEditor DefaultColorSelectionModel DefaultComboBoxModel - DefaultDesktopManager DefaultEditorKit DefaultFocusManager DefaultFocusTraversalPolicy DefaultFormatter - DefaultFormatterFactory DefaultHighlighter DefaultKeyboardFocusManager DefaultListCellRenderer - DefaultListModel DefaultListSelectionModel DefaultLoaderRepository DefaultMenuLayout DefaultMetalTheme - DefaultMutableTreeNode DefaultPersistenceDelegate DefaultSingleSelectionModel DefaultStyledDocument - DefaultTableCellRenderer DefaultTableColumnModel DefaultTableModel DefaultTextUI DefaultTreeCellEditor - DefaultTreeCellRenderer DefaultTreeModel DefaultTreeSelectionModel Deflater DeflaterOutputStream Delayed - DelayQueue DelegationPermission Deprecated Descriptor DescriptorAccess DescriptorSupport DESedeKeySpec - DesignMode DESKeySpec DesktopIconUI DesktopManager DesktopPaneUI Destination Destroyable - DestroyFailedException DGC DHGenParameterSpec DHKey DHParameterSpec DHPrivateKey DHPrivateKeySpec - DHPublicKey DHPublicKeySpec Dialog Dictionary DigestException DigestInputStream DigestOutputStream - Dimension Dimension2D DimensionUIResource DirContext DirectColorModel DirectoryManager DirObjectFactory - DirStateFactory DisplayMode DnDConstants Doc DocAttribute DocAttributeSet DocFlavor DocPrintJob Document - DocumentBuilder DocumentBuilderFactory Documented DocumentEvent DocumentFilter DocumentListener - DocumentName DocumentParser DomainCombiner DOMLocator DOMResult DOMSource Double DoubleBuffer - DragGestureEvent DragGestureListener DragGestureRecognizer DragSource DragSourceAdapter - DragSourceContext DragSourceDragEvent DragSourceDropEvent DragSourceEvent DragSourceListener - DragSourceMotionListener Driver DriverManager DriverPropertyInfo DropTarget DropTargetAdapter - DropTargetContext DropTargetDragEvent DropTargetDropEvent DropTargetEvent DropTargetListener DSAKey - DSAKeyPairGenerator DSAParameterSpec DSAParams DSAPrivateKey DSAPrivateKeySpec DSAPublicKey - DSAPublicKeySpec DTD DTDConstants DuplicateFormatFlagsException Duration DynamicMBean ECField ECFieldF2m - ECFieldFp ECGenParameterSpec ECKey ECParameterSpec ECPoint ECPrivateKey ECPrivateKeySpec ECPublicKey - ECPublicKeySpec EditorKit Element ElementIterator ElementType Ellipse2D EllipticCurve EmptyBorder - EmptyStackException EncodedKeySpec Encoder EncryptedPrivateKeyInfo Entity Enum - EnumConstantNotPresentException EnumControl Enumeration EnumMap EnumSet EnumSyntax EOFException Error - ErrorListener ErrorManager EtchedBorder Event EventContext EventDirContext EventHandler EventListener - EventListenerList EventListenerProxy EventObject EventQueue EventSetDescriptor Exception - ExceptionInInitializerError ExceptionListener Exchanger ExecutionException Executor - ExecutorCompletionService Executors ExecutorService ExemptionMechanism ExemptionMechanismException - ExemptionMechanismSpi ExpandVetoException ExportException Expression ExtendedRequest ExtendedResponse - Externalizable FactoryConfigurationError FailedLoginException FeatureDescriptor Fidelity Field - FieldPosition FieldView File FileCacheImageInputStream FileCacheImageOutputStream FileChannel - FileChooserUI FileDescriptor FileDialog FileFilter FileHandler FileImageInputStream - FileImageOutputStream FileInputStream FileLock FileLockInterruptionException FilenameFilter FileNameMap - FileNotFoundException FileOutputStream FilePermission FileReader FileSystemView FileView FileWriter - Filter FilteredImageSource FilteredRowSet FilterInputStream FilterOutputStream FilterReader FilterWriter - Finishings FixedHeightLayoutCache FlatteningPathIterator FlavorEvent FlavorException FlavorListener - FlavorMap FlavorTable Float FloatBuffer FloatControl FlowLayout FlowView Flushable FocusAdapter - FocusEvent FocusListener FocusManager FocusTraversalPolicy Font FontFormatException FontMetrics - FontRenderContext FontUIResource Format FormatConversionProvider FormatFlagsConversionMismatchException - Formattable FormattableFlags Formatter FormatterClosedException FormSubmitEvent FormView Frame Future - FutureTask GapContent GarbageCollectorMXBean GatheringByteChannel GaugeMonitor GaugeMonitorMBean - GeneralPath GeneralSecurityException GenericArrayType GenericDeclaration GenericSignatureFormatError - GlyphJustificationInfo GlyphMetrics GlyphVector GlyphView GradientPaint GraphicAttribute Graphics - Graphics2D GraphicsConfigTemplate GraphicsConfiguration GraphicsDevice GraphicsEnvironment GrayFilter - GregorianCalendar GridBagConstraints GridBagLayout GridLayout Group Guard GuardedObject GZIPInputStream - GZIPOutputStream Handler HandshakeCompletedEvent HandshakeCompletedListener HasControls HashAttributeSet - HashDocAttributeSet HashMap HashPrintJobAttributeSet HashPrintRequestAttributeSet - HashPrintServiceAttributeSet HashSet Hashtable HeadlessException HierarchyBoundsAdapter - HierarchyBoundsListener HierarchyEvent HierarchyListener Highlighter HostnameVerifier HTML HTMLDocument - HTMLEditorKit HTMLFrameHyperlinkEvent HTMLWriter HttpRetryException HttpsURLConnection HttpURLConnection - HyperlinkEvent HyperlinkListener ICC_ColorSpace ICC_Profile ICC_ProfileGray ICC_ProfileRGB Icon - IconUIResource IconView Identity IdentityHashMap IdentityScope IIOByteBuffer IIOException IIOImage - IIOInvalidTreeException IIOMetadata IIOMetadataController IIOMetadataFormat IIOMetadataFormatImpl - IIOMetadataNode IIOParam IIOParamController IIOReadProgressListener IIOReadUpdateListener - IIOReadWarningListener IIORegistry IIOServiceProvider IIOWriteProgressListener IIOWriteWarningListener - IllegalAccessError IllegalAccessException IllegalArgumentException IllegalBlockingModeException - IllegalBlockSizeException IllegalCharsetNameException IllegalClassFormatException - IllegalComponentStateException IllegalFormatCodePointException IllegalFormatConversionException - IllegalFormatException IllegalFormatFlagsException IllegalFormatPrecisionException - IllegalFormatWidthException IllegalMonitorStateException IllegalPathStateException - IllegalSelectorException IllegalStateException IllegalThreadStateException Image ImageCapabilities - ImageConsumer ImageFilter ImageGraphicAttribute ImageIcon ImageInputStream ImageInputStreamImpl - ImageInputStreamSpi ImageIO ImageObserver ImageOutputStream ImageOutputStreamImpl ImageOutputStreamSpi - ImageProducer ImageReader ImageReaderSpi ImageReaderWriterSpi ImageReadParam ImageTranscoder - ImageTranscoderSpi ImageTypeSpecifier ImageView ImageWriteParam ImageWriter ImageWriterSpi - ImagingOpException IncompatibleClassChangeError IncompleteAnnotationException IndexColorModel - IndexedPropertyChangeEvent IndexedPropertyDescriptor IndexOutOfBoundsException Inet4Address Inet6Address - InetAddress InetSocketAddress Inflater InflaterInputStream InheritableThreadLocal Inherited - InitialContext InitialContextFactory InitialContextFactoryBuilder InitialDirContext InitialLdapContext - InlineView InputContext InputEvent InputMap InputMapUIResource InputMethod InputMethodContext - InputMethodDescriptor InputMethodEvent InputMethodHighlight InputMethodListener InputMethodRequests - InputMismatchException InputStream InputStreamReader InputSubset InputVerifier Insets InsetsUIResource - InstanceAlreadyExistsException InstanceNotFoundException InstantiationError InstantiationException - Instrument Instrumentation InsufficientResourcesException IntBuffer Integer IntegerSyntax InternalError - InternalFrameAdapter InternalFrameEvent InternalFrameFocusTraversalPolicy InternalFrameListener - InternalFrameUI InternationalFormatter InterruptedException InterruptedIOException - InterruptedNamingException InterruptibleChannel IntrospectionException Introspector - InvalidActivityException InvalidAlgorithmParameterException InvalidApplicationException - InvalidAttributeIdentifierException InvalidAttributesException InvalidAttributeValueException - InvalidClassException InvalidDnDOperationException InvalidKeyException InvalidKeySpecException - InvalidMarkException InvalidMidiDataException InvalidNameException InvalidObjectException - InvalidOpenTypeException InvalidParameterException InvalidParameterSpecException - InvalidPreferencesFormatException InvalidPropertiesFormatException InvalidRelationIdException - InvalidRelationServiceException InvalidRelationTypeException InvalidRoleInfoException - InvalidRoleValueException InvalidSearchControlsException InvalidSearchFilterException - InvalidTargetObjectTypeException InvalidTransactionException InvocationEvent InvocationHandler - InvocationTargetException IOException ItemEvent ItemListener ItemSelectable Iterable Iterator - IvParameterSpec JApplet JarEntry JarException JarFile JarInputStream JarOutputStream JarURLConnection - JButton JCheckBox JCheckBoxMenuItem JColorChooser JComboBox JComponent JdbcRowSet JDesktopPane JDialog - JEditorPane JFileChooser JFormattedTextField JFrame JInternalFrame JLabel JLayeredPane JList JMenu - JMenuBar JMenuItem JMException JMRuntimeException JMXAuthenticator JMXConnectionNotification - JMXConnector JMXConnectorFactory JMXConnectorProvider JMXConnectorServer JMXConnectorServerFactory - JMXConnectorServerMBean JMXConnectorServerProvider JMXPrincipal JMXProviderException - JMXServerErrorException JMXServiceURL JobAttributes JobHoldUntil JobImpressions JobImpressionsCompleted - JobImpressionsSupported JobKOctets JobKOctetsProcessed JobKOctetsSupported JobMediaSheets - JobMediaSheetsCompleted JobMediaSheetsSupported JobMessageFromOperator JobName JobOriginatingUserName - JobPriority JobPrioritySupported JobSheets JobState JobStateReason JobStateReasons Joinable JoinRowSet - JOptionPane JPanel JPasswordField JPEGHuffmanTable JPEGImageReadParam JPEGImageWriteParam JPEGQTable - JPopupMenu JProgressBar JRadioButton JRadioButtonMenuItem JRootPane JScrollBar JScrollPane JSeparator - JSlider JSpinner JSplitPane JTabbedPane JTable JTableHeader JTextArea JTextComponent JTextField - JTextPane JToggleButton JToolBar JToolTip JTree JViewport JWindow KerberosKey KerberosPrincipal - KerberosTicket Kernel Key KeyAdapter KeyAgreement KeyAgreementSpi KeyAlreadyExistsException - KeyboardFocusManager KeyEvent KeyEventDispatcher KeyEventPostProcessor KeyException KeyFactory - KeyFactorySpi KeyGenerator KeyGeneratorSpi KeyListener KeyManagementException KeyManager - KeyManagerFactory KeyManagerFactorySpi Keymap KeyPair KeyPairGenerator KeyPairGeneratorSpi KeyRep - KeySpec KeyStore KeyStoreBuilderParameters KeyStoreException KeyStoreSpi KeyStroke Label LabelUI - LabelView LanguageCallback LastOwnerException LayeredHighlighter LayoutFocusTraversalPolicy - LayoutManager LayoutManager2 LayoutQueue LDAPCertStoreParameters LdapContext LdapName - LdapReferralException Lease Level LimitExceededException Line Line2D LineBorder LineBreakMeasurer - LineEvent LineListener LineMetrics LineNumberInputStream LineNumberReader LineUnavailableException - LinkageError LinkedBlockingQueue LinkedHashMap LinkedHashSet LinkedList LinkException LinkLoopException - LinkRef List ListCellRenderer ListDataEvent ListDataListener ListenerNotFoundException ListIterator - ListModel ListResourceBundle ListSelectionEvent ListSelectionListener ListSelectionModel ListUI ListView - LoaderHandler Locale LocateRegistry Lock LockSupport Logger LoggingMXBean LoggingPermission LoginContext - LoginException LoginModule LogManager LogRecord LogStream Long LongBuffer LookAndFeel LookupOp - LookupTable Mac MacSpi MalformedInputException MalformedLinkException MalformedObjectNameException - MalformedParameterizedTypeException MalformedURLException ManagementFactory ManagementPermission - ManageReferralControl ManagerFactoryParameters Manifest Map MappedByteBuffer MarshalException - MarshalledObject MaskFormatter Matcher MatchResult Math MathContext MatteBorder MBeanAttributeInfo - MBeanConstructorInfo MBeanException MBeanFeatureInfo MBeanInfo MBeanNotificationInfo MBeanOperationInfo - MBeanParameterInfo MBeanPermission MBeanRegistration MBeanRegistrationException MBeanServer - MBeanServerBuilder MBeanServerConnection MBeanServerDelegate MBeanServerDelegateMBean MBeanServerFactory - MBeanServerForwarder MBeanServerInvocationHandler MBeanServerNotification MBeanServerNotificationFilter - MBeanServerPermission MBeanTrustPermission Media MediaName MediaPrintableArea MediaSize MediaSizeName - MediaTracker MediaTray Member MemoryCacheImageInputStream MemoryCacheImageOutputStream MemoryHandler - MemoryImageSource MemoryManagerMXBean MemoryMXBean MemoryNotificationInfo MemoryPoolMXBean MemoryType - MemoryUsage Menu MenuBar MenuBarUI MenuComponent MenuContainer MenuDragMouseEvent MenuDragMouseListener - MenuElement MenuEvent MenuItem MenuItemUI MenuKeyEvent MenuKeyListener MenuListener MenuSelectionManager - MenuShortcut MessageDigest MessageDigestSpi MessageFormat MetaEventListener MetalBorders MetalButtonUI - MetalCheckBoxIcon MetalCheckBoxUI MetalComboBoxButton MetalComboBoxEditor MetalComboBoxIcon - MetalComboBoxUI MetalDesktopIconUI MetalFileChooserUI MetalIconFactory MetalInternalFrameTitlePane - MetalInternalFrameUI MetalLabelUI MetalLookAndFeel MetalMenuBarUI MetalPopupMenuSeparatorUI - MetalProgressBarUI MetalRadioButtonUI MetalRootPaneUI MetalScrollBarUI MetalScrollButton - MetalScrollPaneUI MetalSeparatorUI MetalSliderUI MetalSplitPaneUI MetalTabbedPaneUI MetalTextFieldUI - MetalTheme MetalToggleButtonUI MetalToolBarUI MetalToolTipUI MetalTreeUI MetaMessage Method - MethodDescriptor MGF1ParameterSpec MidiChannel MidiDevice MidiDeviceProvider MidiEvent MidiFileFormat - MidiFileReader MidiFileWriter MidiMessage MidiSystem MidiUnavailableException MimeTypeParseException - MinimalHTMLWriter MissingFormatArgumentException MissingFormatWidthException MissingResourceException - Mixer MixerProvider MLet MLetMBean ModelMBean ModelMBeanAttributeInfo ModelMBeanConstructorInfo - ModelMBeanInfo ModelMBeanInfoSupport ModelMBeanNotificationBroadcaster ModelMBeanNotificationInfo - ModelMBeanOperationInfo ModificationItem Modifier Monitor MonitorMBean MonitorNotification - MonitorSettingException MouseAdapter MouseDragGestureRecognizer MouseEvent MouseInfo MouseInputAdapter - MouseInputListener MouseListener MouseMotionAdapter MouseMotionListener MouseWheelEvent - MouseWheelListener MultiButtonUI MulticastSocket MultiColorChooserUI MultiComboBoxUI MultiDesktopIconUI - MultiDesktopPaneUI MultiDoc MultiDocPrintJob MultiDocPrintService MultiFileChooserUI - MultiInternalFrameUI MultiLabelUI MultiListUI MultiLookAndFeel MultiMenuBarUI MultiMenuItemUI - MultiOptionPaneUI MultiPanelUI MultiPixelPackedSampleModel MultipleDocumentHandling MultipleMaster - MultiPopupMenuUI MultiProgressBarUI MultiRootPaneUI MultiScrollBarUI MultiScrollPaneUI MultiSeparatorUI - MultiSliderUI MultiSpinnerUI MultiSplitPaneUI MultiTabbedPaneUI MultiTableHeaderUI MultiTableUI - MultiTextUI MultiToolBarUI MultiToolTipUI MultiTreeUI MultiViewportUI MutableAttributeSet - MutableComboBoxModel MutableTreeNode Name NameAlreadyBoundException NameCallback NameClassPair - NameNotFoundException NameParser NamespaceChangeListener NamespaceContext Naming NamingEnumeration - NamingEvent NamingException NamingExceptionEvent NamingListener NamingManager NamingSecurityException - NavigationFilter NegativeArraySizeException NetPermission NetworkInterface NoClassDefFoundError - NoConnectionPendingException NodeChangeEvent NodeChangeListener NoInitialContextException - NoninvertibleTransformException NonReadableChannelException NonWritableChannelException - NoPermissionException NoRouteToHostException NoSuchAlgorithmException NoSuchAttributeException - NoSuchElementException NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException - NoSuchObjectException NoSuchPaddingException NoSuchProviderException NotActiveException - NotBoundException NotCompliantMBeanException NotContextException Notification NotificationBroadcaster - NotificationBroadcasterSupport NotificationEmitter NotificationFilter NotificationFilterSupport - NotificationListener NotificationResult NotOwnerException NotSerializableException NotYetBoundException - NotYetConnectedException NullCipher NullPointerException Number NumberFormat NumberFormatException - NumberFormatter NumberOfDocuments NumberOfInterveningJobs NumberUp NumberUpSupported NumericShaper - OAEPParameterSpec Object ObjectChangeListener ObjectFactory ObjectFactoryBuilder ObjectInput - ObjectInputStream ObjectInputValidation ObjectInstance ObjectName ObjectOutput ObjectOutputStream - ObjectStreamClass ObjectStreamConstants ObjectStreamException ObjectStreamField ObjectView ObjID - Observable Observer OceanTheme OpenDataException OpenMBeanAttributeInfo OpenMBeanAttributeInfoSupport - OpenMBeanConstructorInfo OpenMBeanConstructorInfoSupport OpenMBeanInfo OpenMBeanInfoSupport - OpenMBeanOperationInfo OpenMBeanOperationInfoSupport OpenMBeanParameterInfo - OpenMBeanParameterInfoSupport OpenType OperatingSystemMXBean Operation OperationNotSupportedException - OperationsException Option OptionalDataException OptionPaneUI OrientationRequested OutOfMemoryError - OutputDeviceAssigned OutputKeys OutputStream OutputStreamWriter OverlappingFileLockException - OverlayLayout Override Owner Pack200 Package PackedColorModel Pageable PageAttributes - PagedResultsControl PagedResultsResponseControl PageFormat PageRanges PagesPerMinute PagesPerMinuteColor - Paint PaintContext PaintEvent Panel PanelUI Paper ParagraphView ParameterBlock ParameterDescriptor - ParameterizedType ParameterMetaData ParseException ParsePosition Parser ParserConfigurationException - ParserDelegator PartialResultException PasswordAuthentication PasswordCallback PasswordView Patch - PathIterator Pattern PatternSyntaxException PBEKey PBEKeySpec PBEParameterSpec PDLOverrideSupported - Permission PermissionCollection Permissions PersistenceDelegate PersistentMBean PhantomReference Pipe - PipedInputStream PipedOutputStream PipedReader PipedWriter PixelGrabber PixelInterleavedSampleModel - PKCS8EncodedKeySpec PKIXBuilderParameters PKIXCertPathBuilderResult PKIXCertPathChecker - PKIXCertPathValidatorResult PKIXParameters PlainDocument PlainView Point Point2D PointerInfo Policy - PolicyNode PolicyQualifierInfo Polygon PooledConnection Popup PopupFactory PopupMenu PopupMenuEvent - PopupMenuListener PopupMenuUI Port PortableRemoteObject PortableRemoteObjectDelegate - PortUnreachableException Position Predicate PreferenceChangeEvent PreferenceChangeListener Preferences - PreferencesFactory PreparedStatement PresentationDirection Principal Printable PrinterAbortException - PrinterException PrinterGraphics PrinterInfo PrinterIOException PrinterIsAcceptingJobs PrinterJob - PrinterLocation PrinterMakeAndModel PrinterMessageFromOperator PrinterMoreInfo - PrinterMoreInfoManufacturer PrinterName PrinterResolution PrinterState PrinterStateReason - PrinterStateReasons PrinterURI PrintEvent PrintException PrintGraphics PrintJob PrintJobAdapter - PrintJobAttribute PrintJobAttributeEvent PrintJobAttributeListener PrintJobAttributeSet PrintJobEvent - PrintJobListener PrintQuality PrintRequestAttribute PrintRequestAttributeSet PrintService - PrintServiceAttribute PrintServiceAttributeEvent PrintServiceAttributeListener PrintServiceAttributeSet - PrintServiceLookup PrintStream PrintWriter PriorityBlockingQueue PriorityQueue PrivateClassLoader - PrivateCredentialPermission PrivateKey PrivateMLet PrivilegedAction PrivilegedActionException - PrivilegedExceptionAction Process ProcessBuilder ProfileDataException ProgressBarUI ProgressMonitor - ProgressMonitorInputStream Properties PropertyChangeEvent PropertyChangeListener - PropertyChangeListenerProxy PropertyChangeSupport PropertyDescriptor PropertyEditor - PropertyEditorManager PropertyEditorSupport PropertyPermission PropertyResourceBundle - PropertyVetoException ProtectionDomain ProtocolException Provider ProviderException Proxy ProxySelector - PSource PSSParameterSpec PublicKey PushbackInputStream PushbackReader QName QuadCurve2D Query QueryEval - QueryExp Queue QueuedJobCount Random RandomAccess RandomAccessFile Raster RasterFormatException RasterOp - RC2ParameterSpec RC5ParameterSpec Rdn Readable ReadableByteChannel Reader ReadOnlyBufferException - ReadWriteLock RealmCallback RealmChoiceCallback Receiver Rectangle Rectangle2D RectangularShape - ReentrantLock ReentrantReadWriteLock Ref RefAddr Reference Referenceable ReferenceQueue - ReferenceUriSchemesSupported ReferralException ReflectionException ReflectPermission Refreshable - RefreshFailedException Region RegisterableService Registry RegistryHandler RejectedExecutionException - RejectedExecutionHandler Relation RelationException RelationNotFoundException RelationNotification - RelationService RelationServiceMBean RelationServiceNotRegisteredException RelationSupport - RelationSupportMBean RelationType RelationTypeNotFoundException RelationTypeSupport Remote RemoteCall - RemoteException RemoteObject RemoteObjectInvocationHandler RemoteRef RemoteServer RemoteStub - RenderableImage RenderableImageOp RenderableImageProducer RenderContext RenderedImage - RenderedImageFactory Renderer RenderingHints RepaintManager ReplicateScaleFilter RequestingUserName - RequiredModelMBean RescaleOp ResolutionSyntax Resolver ResolveResult ResourceBundle ResponseCache Result - ResultSet ResultSetMetaData Retention RetentionPolicy ReverbType RGBImageFilter RMIClassLoader - RMIClassLoaderSpi RMIClientSocketFactory RMIConnection RMIConnectionImpl RMIConnectionImpl_Stub - RMIConnector RMIConnectorServer RMIFailureHandler RMIIIOPServerImpl RMIJRMPServerImpl - RMISecurityException RMISecurityManager RMIServer RMIServerImpl RMIServerImpl_Stub - RMIServerSocketFactory RMISocketFactory Robot Role RoleInfo RoleInfoNotFoundException RoleList - RoleNotFoundException RoleResult RoleStatus RoleUnresolved RoleUnresolvedList RootPaneContainer - RootPaneUI RoundingMode RoundRectangle2D RowMapper RowSet RowSetEvent RowSetInternal RowSetListener - RowSetMetaData RowSetMetaDataImpl RowSetReader RowSetWarning RowSetWriter RSAKey RSAKeyGenParameterSpec - RSAMultiPrimePrivateCrtKey RSAMultiPrimePrivateCrtKeySpec RSAOtherPrimeInfo RSAPrivateCrtKey - RSAPrivateCrtKeySpec RSAPrivateKey RSAPrivateKeySpec RSAPublicKey RSAPublicKeySpec RTFEditorKit - RuleBasedCollator Runnable Runtime RuntimeErrorException RuntimeException RuntimeMBeanException - RuntimeMXBean RuntimeOperationsException RuntimePermission SampleModel Sasl SaslClient SaslClientFactory - SaslException SaslServer SaslServerFactory Savepoint SAXParser SAXParserFactory SAXResult SAXSource - SAXTransformerFactory Scanner ScatteringByteChannel ScheduledExecutorService ScheduledFuture - ScheduledThreadPoolExecutor Schema SchemaFactory SchemaFactoryLoader SchemaViolationException Scrollable - Scrollbar ScrollBarUI ScrollPane ScrollPaneAdjustable ScrollPaneConstants ScrollPaneLayout ScrollPaneUI - SealedObject SearchControls SearchResult SecretKey SecretKeyFactory SecretKeyFactorySpi SecretKeySpec - SecureCacheResponse SecureClassLoader SecureRandom SecureRandomSpi Security SecurityException - SecurityManager SecurityPermission Segment SelectableChannel SelectionKey Selector SelectorProvider - Semaphore SeparatorUI Sequence SequenceInputStream Sequencer SerialArray SerialBlob SerialClob - SerialDatalink SerialException Serializable SerializablePermission SerialJavaObject SerialRef - SerialStruct ServerCloneException ServerError ServerException ServerNotActiveException ServerRef - ServerRuntimeException ServerSocket ServerSocketChannel ServerSocketFactory ServiceNotFoundException - ServicePermission ServiceRegistry ServiceUI ServiceUIFactory ServiceUnavailableException Set - SetOfIntegerSyntax Severity Shape ShapeGraphicAttribute SheetCollate Short ShortBuffer - ShortBufferException ShortLookupTable ShortMessage Sides Signature SignatureException SignatureSpi - SignedObject Signer SimpleAttributeSet SimpleBeanInfo SimpleDateFormat SimpleDoc SimpleFormatter - SimpleTimeZone SimpleType SinglePixelPackedSampleModel SingleSelectionModel Size2DSyntax - SizeLimitExceededException SizeRequirements SizeSequence Skeleton SkeletonMismatchException - SkeletonNotFoundException SliderUI Socket SocketAddress SocketChannel SocketException SocketFactory - SocketHandler SocketImpl SocketImplFactory SocketOptions SocketPermission SocketSecurityException - SocketTimeoutException SoftBevelBorder SoftReference SortControl SortedMap SortedSet - SortingFocusTraversalPolicy SortKey SortResponseControl Soundbank SoundbankReader SoundbankResource - Source SourceDataLine SourceLocator SpinnerDateModel SpinnerListModel SpinnerModel SpinnerNumberModel - SpinnerUI SplitPaneUI Spring SpringLayout SQLData SQLException SQLInput SQLInputImpl SQLOutput - SQLOutputImpl SQLPermission SQLWarning SSLContext SSLContextSpi SSLEngine SSLEngineResult SSLException - SSLHandshakeException SSLKeyException SSLPeerUnverifiedException SSLPermission SSLProtocolException - SslRMIClientSocketFactory SslRMIServerSocketFactory SSLServerSocket SSLServerSocketFactory SSLSession - SSLSessionBindingEvent SSLSessionBindingListener SSLSessionContext SSLSocket SSLSocketFactory Stack - StackOverflowError StackTraceElement StandardMBean StartTlsRequest StartTlsResponse StateEdit - StateEditable StateFactory Statement StreamCorruptedException StreamHandler StreamPrintService - StreamPrintServiceFactory StreamResult StreamSource StreamTokenizer StrictMath String StringBuffer - StringBufferInputStream StringBuilder StringCharacterIterator StringContent - StringIndexOutOfBoundsException StringMonitor StringMonitorMBean StringReader StringRefAddr - StringSelection StringTokenizer StringValueExp StringWriter Stroke Struct Stub StubDelegate - StubNotFoundException Style StyleConstants StyleContext StyledDocument StyledEditorKit StyleSheet - Subject SubjectDelegationPermission SubjectDomainCombiner SupportedValuesAttribute SuppressWarnings - SwingConstants SwingPropertyChangeSupport SwingUtilities SyncFactory SyncFactoryException - SyncFailedException SynchronousQueue SyncProvider SyncProviderException SyncResolver SynthConstants - SynthContext Synthesizer SynthGraphicsUtils SynthLookAndFeel SynthPainter SynthStyle SynthStyleFactory - SysexMessage System SystemColor SystemFlavorMap TabableView TabbedPaneUI TabExpander TableCellEditor - TableCellRenderer TableColumn TableColumnModel TableColumnModelEvent TableColumnModelListener - TableHeaderUI TableModel TableModelEvent TableModelListener TableUI TableView TabSet TabStop TabularData - TabularDataSupport TabularType TagElement Target TargetDataLine TargetedNotification Templates - TemplatesHandler TextAction TextArea TextAttribute TextComponent TextEvent TextField TextHitInfo - TextInputCallback TextLayout TextListener TextMeasurer TextOutputCallback TextSyntax TextUI TexturePaint - Thread ThreadDeath ThreadFactory ThreadGroup ThreadInfo ThreadLocal ThreadMXBean ThreadPoolExecutor - Throwable Tie TileObserver Time TimeLimitExceededException TimeoutException Timer - TimerAlarmClockNotification TimerMBean TimerNotification TimerTask Timestamp TimeUnit TimeZone - TitledBorder ToolBarUI Toolkit ToolTipManager ToolTipUI TooManyListenersException Track - TransactionalWriter TransactionRequiredException TransactionRolledbackException Transferable - TransferHandler TransformAttribute Transformer TransformerConfigurationException TransformerException - TransformerFactory TransformerFactoryConfigurationError TransformerHandler Transmitter Transparency - TreeCellEditor TreeCellRenderer TreeExpansionEvent TreeExpansionListener TreeMap TreeModel - TreeModelEvent TreeModelListener TreeNode TreePath TreeSelectionEvent TreeSelectionListener - TreeSelectionModel TreeSet TreeUI TreeWillExpandListener TrustAnchor TrustManager TrustManagerFactory - TrustManagerFactorySpi Type TypeInfoProvider TypeNotPresentException Types TypeVariable UID UIDefaults - UIManager UIResource UndeclaredThrowableException UndoableEdit UndoableEditEvent UndoableEditListener - UndoableEditSupport UndoManager UnexpectedException UnicastRemoteObject UnknownError - UnknownFormatConversionException UnknownFormatFlagsException UnknownGroupException UnknownHostException - UnknownObjectException UnknownServiceException UnmappableCharacterException UnmarshalException - UnmodifiableClassException UnmodifiableSetException UnrecoverableEntryException - UnrecoverableKeyException Unreferenced UnresolvedAddressException UnresolvedPermission - UnsatisfiedLinkError UnsolicitedNotification UnsolicitedNotificationEvent - UnsolicitedNotificationListener UnsupportedAddressTypeException UnsupportedAudioFileException - UnsupportedCallbackException UnsupportedCharsetException UnsupportedClassVersionError - UnsupportedEncodingException UnsupportedFlavorException UnsupportedLookAndFeelException - UnsupportedOperationException URI URIException URIResolver URISyntax URISyntaxException URL - URLClassLoader URLConnection URLDecoder URLEncoder URLStreamHandler URLStreamHandlerFactory - UTFDataFormatException Util UtilDelegate Utilities UUID Validator ValidatorHandler ValueExp ValueHandler - ValueHandlerMultiFormat VariableHeightLayoutCache Vector VerifyError VetoableChangeListener - VetoableChangeListenerProxy VetoableChangeSupport View ViewFactory ViewportLayout ViewportUI - VirtualMachineError Visibility VMID VoiceStatus Void VolatileImage WeakHashMap WeakReference WebRowSet - WildcardType Window WindowAdapter WindowConstants WindowEvent WindowFocusListener WindowListener - WindowStateListener WrappedPlainView WritableByteChannel WritableRaster WritableRenderedImage - WriteAbortedException Writer X500Principal X500PrivateCredential X509Certificate X509CertSelector - X509CRL X509CRLEntry X509CRLSelector X509EncodedKeySpec X509ExtendedKeyManager X509Extension - X509KeyManager X509TrustManager XAConnection XADataSource XAException XAResource Xid XMLConstants - XMLDecoder XMLEncoder XMLFormatter XMLGregorianCalendar XMLParseException XmlReader XmlWriter XPath - XPathConstants XPathException XPathExpression XPathExpressionException XPathFactory - XPathFactoryConfigurationException XPathFunction XPathFunctionException XPathFunctionResolver - XPathVariableResolver ZipEntry ZipException ZipFile ZipInputStream ZipOutputStream ZoneView - ] - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script-0.9.6.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script-0.9.6.rb deleted file mode 100644 index cb49b7af..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script-0.9.6.rb +++ /dev/null @@ -1,224 +0,0 @@ -module CodeRay -module Scanners - - class JavaScript < Scanner - - include Streamable - - register_for :java_script - file_extension 'js' - - # The actual JavaScript keywords. - KEYWORDS = %w[ - break case catch continue default delete do else - finally for function if in instanceof new - return switch throw try typeof var void while with - ] - PREDEFINED_CONSTANTS = %w[ - false null true undefined - ] - - MAGIC_VARIABLES = %w[ this arguments ] # arguments was introduced in JavaScript 1.4 - - KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ - case delete in instanceof new return throw typeof with - ] - - # Reserved for future use. - RESERVED_WORDS = %w[ - abstract boolean byte char class debugger double enum export extends - final float goto implements import int interface long native package - private protected public short static super synchronized throws transient - volatile - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_CONSTANTS, :pre_constant). - add(MAGIC_VARIABLES, :local_variable). - add(KEYWORDS, :keyword) - - ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - REGEXP_ESCAPE = / [bBdDsSwW] /x - STRING_CONTENT_PATTERN = { - "'" => /[^\\']+/, - '"' => /[^\\"]+/, - '/' => /[^\\\/]+/, - } - KEY_CHECK_PATTERN = { - "'" => / [^\\']* (?: \\.? [^\\']* )* '? \s* : /x, - '"' => / [^\\"]* (?: \\.? [^\\"]* )* "? \s* : /x, - } - - def scan_tokens tokens, options - - state = :initial - string_delimiter = nil - value_expected = true - key_expected = false - function_expected = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - value_expected = true if !value_expected && match.index(?\n) - tokens << [match, :space] - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - value_expected = true - kind = :comment - - elsif check(/\.?\d/) - key_expected = value_expected = false - if scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - elsif scan(/(?>0[0-7]+)(?![89.eEfF])/) - kind = :oct - elsif scan(/\d+[fF]|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - kind = :float - elsif scan(/\d+/) - kind = :integer - end - - elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim) - # FIXME: scan over nested tags - xml_scanner.tokenize match - value_expected = false - next - - elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x) - value_expected = true - last_operator = match[-1] - key_expected = (last_operator == ?{) || (last_operator == ?,) - function_expected = false - kind = :operator - - elsif scan(/ [)\]}]+ /x) - function_expected = key_expected = value_expected = false - kind = :operator - - elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x) - kind = IDENT_KIND[match] - value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] - # TODO: labels - if kind == :ident - if match.index(?$) # $ allowed inside an identifier - kind = :predefined - elsif function_expected - kind = :function - elsif check(/\s*[=:]\s*function\b/) - kind = :function - elsif key_expected && check(/\s*:/) - kind = :key - end - end - function_expected = (kind == :keyword) && (match == 'function') - key_expected = false - - elsif match = scan(/["']/) - if key_expected && check(KEY_CHECK_PATTERN[match]) - state = :key - else - state = :string - end - tokens << [:open, state] - string_delimiter = match - kind = :delimiter - - elsif value_expected && (match = scan(/\/(?=\S)/)) - tokens << [:open, :regexp] - state = :regexp - string_delimiter = '/' - kind = :delimiter - - elsif scan(/ \/ /x) - value_expected = true - key_expected = false - kind = :operator - - else - getch - kind = :error - - end - - when :string, :regexp, :key - if scan(STRING_CONTENT_PATTERN[string_delimiter]) - kind = :content - elsif match = scan(/["'\/]/) - tokens << [match, :delimiter] - if state == :regexp - modifiers = scan(/[gim]+/) - tokens << [modifiers, :modifier] if modifiers && !modifiers.empty? - end - tokens << [:close, state] - string_delimiter = nil - key_expected = value_expected = false - state = :initial - next - elsif state != :regexp && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) - if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") - kind = :content - else - kind = :char - end - elsif state == :regexp && scan(/ \\ (?: #{ESCAPE} | #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/\\./m) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, state] - kind = :error - key_expected = value_expected = false - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if [:string, :regexp].include? state - tokens << [:close, state] - end - - tokens - end - - protected - - def reset_instance - super - @xml_scanner.reset if defined? @xml_scanner - end - - def xml_scanner - @xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => false - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script.rb deleted file mode 100644 index 1f26348b..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/java_script.rb +++ /dev/null @@ -1,224 +0,0 @@ -module CodeRay -module Scanners - - class JavaScript < Scanner - - include Streamable - - register_for :java_script - file_extension 'js' - - # The actual JavaScript keywords. - KEYWORDS = %w[ - break case catch continue default delete do else - finally for function if in instanceof new - return switch throw try typeof var void while with - ] - PREDEFINED_CONSTANTS = %w[ - false null true undefined - ] - - MAGIC_VARIABLES = %w[ this arguments ] # arguments was introduced in JavaScript 1.4 - - KEYWORDS_EXPECTING_VALUE = WordList.new.add %w[ - case delete in instanceof new return throw typeof with - ] - - # Reserved for future use. - RESERVED_WORDS = %w[ - abstract boolean byte char class debugger double enum export extends - final float goto implements import int interface long native package - private protected public short static super synchronized throws transient - volatile - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_CONSTANTS, :pre_constant). - add(MAGIC_VARIABLES, :local_variable). - add(KEYWORDS, :keyword) - - ESCAPE = / [bfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - REGEXP_ESCAPE = / [bBdDsSwW] /x - STRING_CONTENT_PATTERN = { - "'" => /[^\\']+/, - '"' => /[^\\"]+/, - '/' => /[^\\\/]+/, - } - KEY_CHECK_PATTERN = { - "'" => / (?> [^\\']* (?: \\. [^\\']* )* ) ' \s* : /mx, - '"' => / (?> [^\\"]* (?: \\. [^\\"]* )* ) " \s* : /mx, - } - - def scan_tokens tokens, options - - state = :initial - string_delimiter = nil - value_expected = true - key_expected = false - function_expected = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if match = scan(/ \s+ | \\\n /x) - value_expected = true if !value_expected && match.index(?\n) - tokens << [match, :space] - next - - elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx) - value_expected = true - kind = :comment - - elsif check(/\.?\d/) - key_expected = value_expected = false - if scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - elsif scan(/(?>0[0-7]+)(?![89.eEfF])/) - kind = :oct - elsif scan(/\d+[fF]|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - kind = :float - elsif scan(/\d+/) - kind = :integer - end - - elsif value_expected && match = scan(/<([[:alpha:]]\w*) (?: [^\/>]*\/> | .*?<\/\1>)/xim) - # FIXME: scan over nested tags - xml_scanner.tokenize match - value_expected = false - next - - elsif match = scan(/ [-+*=<>?:;,!&^|(\[{~%]+ | \.(?!\d) /x) - value_expected = true - last_operator = match[-1] - key_expected = (last_operator == ?{) || (last_operator == ?,) - function_expected = false - kind = :operator - - elsif scan(/ [)\]}]+ /x) - function_expected = key_expected = value_expected = false - kind = :operator - - elsif match = scan(/ [$a-zA-Z_][A-Za-z_0-9$]* /x) - kind = IDENT_KIND[match] - value_expected = (kind == :keyword) && KEYWORDS_EXPECTING_VALUE[match] - # TODO: labels - if kind == :ident - if match.index(?$) # $ allowed inside an identifier - kind = :predefined - elsif function_expected - kind = :function - elsif check(/\s*[=:]\s*function\b/) - kind = :function - elsif key_expected && check(/\s*:/) - kind = :key - end - end - function_expected = (kind == :keyword) && (match == 'function') - key_expected = false - - elsif match = scan(/["']/) - if key_expected && check(KEY_CHECK_PATTERN[match]) - state = :key - else - state = :string - end - tokens << [:open, state] - string_delimiter = match - kind = :delimiter - - elsif value_expected && (match = scan(/\/(?=\S)/)) - tokens << [:open, :regexp] - state = :regexp - string_delimiter = '/' - kind = :delimiter - - elsif scan(/ \/ /x) - value_expected = true - key_expected = false - kind = :operator - - else - getch - kind = :error - - end - - when :string, :regexp, :key - if scan(STRING_CONTENT_PATTERN[string_delimiter]) - kind = :content - elsif match = scan(/["'\/]/) - tokens << [match, :delimiter] - if state == :regexp - modifiers = scan(/[gim]+/) - tokens << [modifiers, :modifier] if modifiers && !modifiers.empty? - end - tokens << [:close, state] - string_delimiter = nil - key_expected = value_expected = false - state = :initial - next - elsif state != :regexp && (match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)) - if string_delimiter == "'" && !(match == "\\\\" || match == "\\'") - kind = :content - else - kind = :char - end - elsif state == :regexp && scan(/ \\ (?: #{ESCAPE} | #{REGEXP_ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/\\./m) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, state] - kind = :error - key_expected = value_expected = false - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if [:string, :regexp].include? state - tokens << [:close, state] - end - - tokens - end - - protected - - def reset_instance - super - @xml_scanner.reset if defined? @xml_scanner - end - - def xml_scanner - @xml_scanner ||= CodeRay.scanner :xml, :tokens => @tokens, :keep_tokens => true, :keep_state => false - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/json.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/json.rb deleted file mode 100644 index abe24fb0..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/json.rb +++ /dev/null @@ -1,108 +0,0 @@ -module CodeRay -module Scanners - - class JSON < Scanner - - include Streamable - - register_for :json - file_extension 'json' - - KINDS_NOT_LOC = [ - :float, :char, :content, :delimiter, - :error, :integer, :operator, :value, - ] - - ESCAPE = / [bfnrt\\"\/] /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} /x - - def scan_tokens tokens, options - - state = :initial - stack = [] - key_expected = false - - until eos? - - kind = nil - match = nil - - case state - - when :initial - if match = scan(/ \s+ | \\\n /x) - tokens << [match, :space] - next - elsif match = scan(/ [:,\[{\]}] /x) - kind = :operator - case match - when '{' then stack << :object; key_expected = true - when '[' then stack << :array - when ':' then key_expected = false - when ',' then key_expected = true if stack.last == :object - when '}', ']' then stack.pop # no error recovery, but works for valid JSON - end - elsif match = scan(/ true | false | null /x) - kind = :value - elsif match = scan(/-?(?:0|[1-9]\d*)/) - kind = :integer - if scan(/\.\d+(?:[eE][-+]?\d+)?|[eE][-+]?\d+/) - match << matched - kind = :float - end - elsif match = scan(/"/) - state = key_expected ? :key : :string - tokens << [:open, state] - kind = :delimiter - else - getch - kind = :error - end - - when :string, :key - if scan(/[^\\"]+/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, state] - state = :initial - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/\\./m) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, state] - kind = :error - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if [:string, :key].include? state - tokens << [:close, state] - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/nitro_xhtml.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/nitro_xhtml.rb deleted file mode 100644 index 6eb1d3b8..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/nitro_xhtml.rb +++ /dev/null @@ -1,136 +0,0 @@ -module CodeRay -module Scanners - - load :html - load :ruby - - # Nitro XHTML Scanner - class NitroXHTML < Scanner - - include Streamable - register_for :nitro_xhtml - file_extension :xhtml - title 'Nitro XHTML' - - KINDS_NOT_LOC = HTML::KINDS_NOT_LOC - - NITRO_RUBY_BLOCK = / - <\?r - (?> - [^\?]* - (?> \?(?!>) [^\?]* )* - ) - (?: \?> )? - | - - (?> - [^<]* - (?> <(?!\/ruby>) [^<]* )* - ) - (?: <\/ruby> )? - | - <% - (?> - [^%]* - (?> %(?!>) [^%]* )* - ) - (?: %> )? - /mx - - NITRO_VALUE_BLOCK = / - \# - (?: - \{ - [^{}]* - (?> - \{ [^}]* \} - (?> [^{}]* ) - )* - \}? - | \| [^|]* \|? - | \( [^)]* \)? - | \[ [^\]]* \]? - | \\ [^\\]* \\? - ) - /x - - NITRO_ENTITY = / - % (?: \#\d+ | \w+ ) ; - / - - START_OF_RUBY = / - (?=[<\#%]) - < (?: \?r | % | ruby> ) - | \# [{(|] - | % (?: \#\d+ | \w+ ) ; - /x - - CLOSING_PAREN = Hash.new do |h, p| - h[p] = p - end.update( { - '(' => ')', - '[' => ']', - '{' => '}', - } ) - - private - - def setup - @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true - @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true - end - - def reset_instance - super - @html_scanner.reset - end - - def scan_tokens tokens, options - - until eos? - - if (match = scan_until(/(?=#{START_OF_RUBY})/o) || scan_until(/\z/)) and not match.empty? - @html_scanner.tokenize match - - elsif match = scan(/#{NITRO_VALUE_BLOCK}/o) - start_tag = match[0,2] - delimiter = CLOSING_PAREN[start_tag[1,1]] - end_tag = match[-1,1] == delimiter ? delimiter : '' - tokens << [:open, :inline] - tokens << [start_tag, :inline_delimiter] - code = match[start_tag.size .. -1 - end_tag.size] - @ruby_scanner.tokenize code - tokens << [end_tag, :inline_delimiter] unless end_tag.empty? - tokens << [:close, :inline] - - elsif match = scan(/#{NITRO_RUBY_BLOCK}/o) - start_tag = '' ? '?>' : '' - tokens << [:open, :inline] - tokens << [start_tag, :inline_delimiter] - code = match[start_tag.size .. -(end_tag.size)-1] - @ruby_scanner.tokenize code - tokens << [end_tag, :inline_delimiter] unless end_tag.empty? - tokens << [:close, :inline] - - elsif entity = scan(/#{NITRO_ENTITY}/o) - tokens << [entity, :entity] - - elsif scan(/%/) - tokens << [matched, :error] - - else - raise_inspect 'else-case reached!', tokens - - end - - end - - tokens - - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/php.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/php.rb deleted file mode 100644 index cb93264f..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/php.rb +++ /dev/null @@ -1,533 +0,0 @@ -module CodeRay -module Scanners - - load :html - - # Original by Stefan Walk. - class PHP < Scanner - - register_for :php - file_extension 'php' - - KINDS_NOT_LOC = HTML::KINDS_NOT_LOC - - def setup - @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true - end - - def reset_instance - super - @html_scanner.reset - end - - module Words - - # according to http://www.php.net/manual/en/reserved.keywords.php - KEYWORDS = %w[ - abstract and array as break case catch class clone const continue declare default do else elseif - enddeclare endfor endforeach endif endswitch endwhile extends final for foreach function global - goto if implements interface instanceof namespace new or private protected public static switch - throw try use var while xor - cfunction old_function - ] - - TYPES = %w[ int integer float double bool boolean string array object resource ] - - LANGUAGE_CONSTRUCTS = %w[ - die echo empty exit eval include include_once isset list - require require_once return print unset - ] - - CLASSES = %w[ Directory stdClass __PHP_Incomplete_Class exception php_user_filter Closure ] - - # according to http://php.net/quickref.php on 2009-04-21; - # all functions with _ excluded (module functions) and selected additional functions - BUILTIN_FUNCTIONS = %w[ - abs acos acosh addcslashes addslashes aggregate array arsort ascii2ebcdic asin asinh asort assert atan atan2 - atanh basename bcadd bccomp bcdiv bcmod bcmul bcpow bcpowmod bcscale bcsqrt bcsub bin2hex bindec - bindtextdomain bzclose bzcompress bzdecompress bzerrno bzerror bzerrstr bzflush bzopen bzread bzwrite - calculhmac ceil chdir checkdate checkdnsrr chgrp chmod chop chown chr chroot clearstatcache closedir closelog - compact constant copy cos cosh count crc32 crypt current date dcgettext dcngettext deaggregate decbin dechex - decoct define defined deg2rad delete dgettext die dirname diskfreespace dl dngettext doubleval each - ebcdic2ascii echo empty end ereg eregi escapeshellarg escapeshellcmd eval exec exit exp explode expm1 extract - fclose feof fflush fgetc fgetcsv fgets fgetss file fileatime filectime filegroup fileinode filemtime fileowner - fileperms filepro filesize filetype floatval flock floor flush fmod fnmatch fopen fpassthru fprintf fputcsv - fputs fread frenchtojd fscanf fseek fsockopen fstat ftell ftok ftruncate fwrite getallheaders getcwd getdate - getenv gethostbyaddr gethostbyname gethostbynamel getimagesize getlastmod getmxrr getmygid getmyinode getmypid - getmyuid getopt getprotobyname getprotobynumber getrandmax getrusage getservbyname getservbyport gettext - gettimeofday gettype glob gmdate gmmktime gmstrftime gregoriantojd gzclose gzcompress gzdecode gzdeflate - gzencode gzeof gzfile gzgetc gzgets gzgetss gzinflate gzopen gzpassthru gzputs gzread gzrewind gzseek gztell - gzuncompress gzwrite hash header hebrev hebrevc hexdec htmlentities htmlspecialchars hypot iconv idate - implode include intval ip2long iptcembed iptcparse isset - jddayofweek jdmonthname jdtofrench jdtogregorian jdtojewish jdtojulian jdtounix jewishtojd join jpeg2wbmp - juliantojd key krsort ksort lcfirst lchgrp lchown levenshtein link linkinfo list localeconv localtime log - log10 log1p long2ip lstat ltrim mail main max md5 metaphone mhash microtime min mkdir mktime msql natcasesort - natsort next ngettext nl2br nthmac octdec opendir openlog - ord overload pack passthru pathinfo pclose pfsockopen phpcredits phpinfo phpversion pi png2wbmp popen pos pow - prev print printf putenv quotemeta rad2deg rand range rawurldecode rawurlencode readdir readfile readgzfile - readline readlink realpath recode rename require reset rewind rewinddir rmdir round rsort rtrim scandir - serialize setcookie setlocale setrawcookie settype sha1 shuffle signeurlpaiement sin sinh sizeof sleep snmpget - snmpgetnext snmprealwalk snmpset snmpwalk snmpwalkoid sort soundex split spliti sprintf sqrt srand sscanf stat - strcasecmp strchr strcmp strcoll strcspn strftime stripcslashes stripos stripslashes stristr strlen - strnatcasecmp strnatcmp strncasecmp strncmp strpbrk strpos strptime strrchr strrev strripos strrpos strspn - strstr strtok strtolower strtotime strtoupper strtr strval substr symlink syslog system tan tanh tempnam - textdomain time tmpfile touch trim uasort ucfirst ucwords uksort umask uniqid unixtojd unlink unpack - unserialize unset urldecode urlencode usleep usort vfprintf virtual vprintf vsprintf wordwrap - array_change_key_case array_chunk array_combine array_count_values array_diff array_diff_assoc - array_diff_key array_diff_uassoc array_diff_ukey array_fill array_fill_keys array_filter array_flip - array_intersect array_intersect_assoc array_intersect_key array_intersect_uassoc array_intersect_ukey - array_key_exists array_keys array_map array_merge array_merge_recursive array_multisort array_pad - array_pop array_product array_push array_rand array_reduce array_reverse array_search array_shift - array_slice array_splice array_sum array_udiff array_udiff_assoc array_udiff_uassoc array_uintersect - array_uintersect_assoc array_uintersect_uassoc array_unique array_unshift array_values array_walk - array_walk_recursive - assert_options base_convert base64_decode base64_encode - chunk_split class_exists class_implements class_parents - count_chars debug_backtrace debug_print_backtrace debug_zval_dump - error_get_last error_log error_reporting extension_loaded - file_exists file_get_contents file_put_contents load_file - func_get_arg func_get_args func_num_args function_exists - get_browser get_called_class get_cfg_var get_class get_class_methods get_class_vars - get_current_user get_declared_classes get_declared_interfaces get_defined_constants - get_defined_functions get_defined_vars get_extension_funcs get_headers get_html_translation_table - get_include_path get_included_files get_loaded_extensions get_magic_quotes_gpc get_magic_quotes_runtime - get_meta_tags get_object_vars get_parent_class get_required_filesget_resource_type - gc_collect_cycles gc_disable gc_enable gc_enabled - halt_compiler headers_list headers_sent highlight_file highlight_string - html_entity_decode htmlspecialchars_decode - in_array include_once inclued_get_data - is_a is_array is_binary is_bool is_buffer is_callable is_dir is_double is_executable is_file is_finite - is_float is_infinite is_int is_integer is_link is_long is_nan is_null is_numeric is_object is_readable - is_real is_resource is_scalar is_soap_fault is_string is_subclass_of is_unicode is_uploaded_file - is_writable is_writeable - locale_get_default locale_set_default - number_format override_function parse_str parse_url - php_check_syntax php_ini_loaded_file php_ini_scanned_files php_logo_guid php_sapi_name - php_strip_whitespace php_uname - preg_filter preg_grep preg_last_error preg_match preg_match_all preg_quote preg_replace - preg_replace_callback preg_split print_r - require_once register_shutdown_function register_tick_function - set_error_handler set_exception_handler set_file_buffer set_include_path - set_magic_quotes_runtime set_time_limit shell_exec - str_getcsv str_ireplace str_pad str_repeat str_replace str_rot13 str_shuffle str_split str_word_count - strip_tags substr_compare substr_count substr_replace - time_nanosleep time_sleep_until - token_get_all token_name trigger_error - unregister_tick_function use_soap_error_handler user_error - utf8_decode utf8_encode var_dump var_export - version_compare - zend_logo_guid zend_thread_id zend_version - create_function call_user_func_array - posix_access posix_ctermid posix_get_last_error posix_getcwd posix_getegid - posix_geteuid posix_getgid posix_getgrgid posix_getgrnam posix_getgroups - posix_getlogin posix_getpgid posix_getpgrp posix_getpid posix_getppid - posix_getpwnam posix_getpwuid posix_getrlimit posix_getsid posix_getuid - posix_initgroups posix_isatty posix_kill posix_mkfifo posix_mknod - posix_setegid posix_seteuid posix_setgid posix_setpgid posix_setsid - posix_setuid posix_strerror posix_times posix_ttyname posix_uname - pcntl_alarm pcntl_exec pcntl_fork pcntl_getpriority pcntl_setpriority - pcntl_signal pcntl_signal_dispatch pcntl_sigprocmask pcntl_sigtimedwait - pcntl_sigwaitinfo pcntl_wait pcntl_waitpid pcntl_wexitstatus pcntl_wifexited - pcntl_wifsignaled pcntl_wifstopped pcntl_wstopsig pcntl_wtermsig - ] - # TODO: more built-in PHP functions? - - EXCEPTIONS = %w[ - E_ERROR E_WARNING E_PARSE E_NOTICE E_CORE_ERROR E_CORE_WARNING E_COMPILE_ERROR E_COMPILE_WARNING - E_USER_ERROR E_USER_WARNING E_USER_NOTICE E_DEPRECATED E_USER_DEPRECATED E_ALL E_STRICT - ] - - CONSTANTS = %w[ - null true false self parent - __LINE__ __DIR__ __FILE__ __LINE__ - __CLASS__ __NAMESPACE__ __METHOD__ __FUNCTION__ - PHP_VERSION PHP_MAJOR_VERSION PHP_MINOR_VERSION PHP_RELEASE_VERSION PHP_VERSION_ID PHP_EXTRA_VERSION PHP_ZTS - PHP_DEBUG PHP_MAXPATHLEN PHP_OS PHP_SAPI PHP_EOL PHP_INT_MAX PHP_INT_SIZE DEFAULT_INCLUDE_PATH - PEAR_INSTALL_DIR PEAR_EXTENSION_DIR PHP_EXTENSION_DIR PHP_PREFIX PHP_BINDIR PHP_LIBDIR PHP_DATADIR - PHP_SYSCONFDIR PHP_LOCALSTATEDIR PHP_CONFIG_FILE_PATH PHP_CONFIG_FILE_SCAN_DIR PHP_SHLIB_SUFFIX - PHP_OUTPUT_HANDLER_START PHP_OUTPUT_HANDLER_CONT PHP_OUTPUT_HANDLER_END - __COMPILER_HALT_OFFSET__ - EXTR_OVERWRITE EXTR_SKIP EXTR_PREFIX_SAME EXTR_PREFIX_ALL EXTR_PREFIX_INVALID EXTR_PREFIX_IF_EXISTS - EXTR_IF_EXISTS SORT_ASC SORT_DESC SORT_REGULAR SORT_NUMERIC SORT_STRING CASE_LOWER CASE_UPPER COUNT_NORMAL - COUNT_RECURSIVE ASSERT_ACTIVE ASSERT_CALLBACK ASSERT_BAIL ASSERT_WARNING ASSERT_QUIET_EVAL CONNECTION_ABORTED - CONNECTION_NORMAL CONNECTION_TIMEOUT INI_USER INI_PERDIR INI_SYSTEM INI_ALL M_E M_LOG2E M_LOG10E M_LN2 M_LN10 - M_PI M_PI_2 M_PI_4 M_1_PI M_2_PI M_2_SQRTPI M_SQRT2 M_SQRT1_2 CRYPT_SALT_LENGTH CRYPT_STD_DES CRYPT_EXT_DES - CRYPT_MD5 CRYPT_BLOWFISH DIRECTORY_SEPARATOR SEEK_SET SEEK_CUR SEEK_END LOCK_SH LOCK_EX LOCK_UN LOCK_NB - HTML_SPECIALCHARS HTML_ENTITIES ENT_COMPAT ENT_QUOTES ENT_NOQUOTES INFO_GENERAL INFO_CREDITS - INFO_CONFIGURATION INFO_MODULES INFO_ENVIRONMENT INFO_VARIABLES INFO_LICENSE INFO_ALL CREDITS_GROUP - CREDITS_GENERAL CREDITS_SAPI CREDITS_MODULES CREDITS_DOCS CREDITS_FULLPAGE CREDITS_QA CREDITS_ALL STR_PAD_LEFT - STR_PAD_RIGHT STR_PAD_BOTH PATHINFO_DIRNAME PATHINFO_BASENAME PATHINFO_EXTENSION PATH_SEPARATOR CHAR_MAX - LC_CTYPE LC_NUMERIC LC_TIME LC_COLLATE LC_MONETARY LC_ALL LC_MESSAGES ABDAY_1 ABDAY_2 ABDAY_3 ABDAY_4 ABDAY_5 - ABDAY_6 ABDAY_7 DAY_1 DAY_2 DAY_3 DAY_4 DAY_5 DAY_6 DAY_7 ABMON_1 ABMON_2 ABMON_3 ABMON_4 ABMON_5 ABMON_6 - ABMON_7 ABMON_8 ABMON_9 ABMON_10 ABMON_11 ABMON_12 MON_1 MON_2 MON_3 MON_4 MON_5 MON_6 MON_7 MON_8 MON_9 - MON_10 MON_11 MON_12 AM_STR PM_STR D_T_FMT D_FMT T_FMT T_FMT_AMPM ERA ERA_YEAR ERA_D_T_FMT ERA_D_FMT ERA_T_FMT - ALT_DIGITS INT_CURR_SYMBOL CURRENCY_SYMBOL CRNCYSTR MON_DECIMAL_POINT MON_THOUSANDS_SEP MON_GROUPING - POSITIVE_SIGN NEGATIVE_SIGN INT_FRAC_DIGITS FRAC_DIGITS P_CS_PRECEDES P_SEP_BY_SPACE N_CS_PRECEDES - N_SEP_BY_SPACE P_SIGN_POSN N_SIGN_POSN DECIMAL_POINT RADIXCHAR THOUSANDS_SEP THOUSEP GROUPING YESEXPR NOEXPR - YESSTR NOSTR CODESET LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG LOG_KERN - LOG_USER LOG_MAIL LOG_DAEMON LOG_AUTH LOG_SYSLOG LOG_LPR LOG_NEWS LOG_UUCP LOG_CRON LOG_AUTHPRIV LOG_LOCAL0 - LOG_LOCAL1 LOG_LOCAL2 LOG_LOCAL3 LOG_LOCAL4 LOG_LOCAL5 LOG_LOCAL6 LOG_LOCAL7 LOG_PID LOG_CONS LOG_ODELAY - LOG_NDELAY LOG_NOWAIT LOG_PERROR - ] - - PREDEFINED = %w[ - $GLOBALS $_SERVER $_GET $_POST $_FILES $_REQUEST $_SESSION $_ENV - $_COOKIE $php_errormsg $HTTP_RAW_POST_DATA $http_response_header - $argc $argv - ] - - IDENT_KIND = CaseIgnoringWordList.new(:ident). - add(KEYWORDS, :reserved). - add(TYPES, :pre_type). - add(LANGUAGE_CONSTRUCTS, :reserved). - add(BUILTIN_FUNCTIONS, :predefined). - add(CLASSES, :pre_constant). - add(EXCEPTIONS, :exception). - add(CONSTANTS, :pre_constant) - - VARIABLE_KIND = WordList.new(:local_variable). - add(PREDEFINED, :predefined) - end - - module RE - - PHP_START = / - ]*?language\s*=\s*"php"[^>]*?> | - ]*?language\s*=\s*'php'[^>]*?> | - <\?php\d? | - <\?(?!xml) - /xi - - PHP_END = %r! - | - \?> - !xi - - HTML_INDICATOR = / ]/i - - IDENTIFIER = /[a-z_\x7f-\xFF][a-z0-9_\x7f-\xFF]*/i - VARIABLE = /\$#{IDENTIFIER}/ - - OPERATOR = / - \.(?!\d)=? | # dot that is not decimal point, string concatenation - && | \|\| | # logic - :: | -> | => | # scope, member, dictionary - \\(?!\n) | # namespace - \+\+ | -- | # increment, decrement - [,;?:()\[\]{}] | # simple delimiters - [-+*\/%&|^]=? | # ordinary math, binary logic, assignment shortcuts - [~$] | # whatever - =& | # reference assignment - [=!]=?=? | <> | # comparison and assignment - <<=? | >>=? | [<>]=? # comparison and shift - /x - - end - - def scan_tokens tokens, options - if string.respond_to?(:encoding) - unless string.encoding == Encoding::ASCII_8BIT - self.string = string.encode Encoding::ASCII_8BIT, - :invalid => :replace, :undef => :replace, :replace => '?' - end - end - - if check(RE::PHP_START) || # starts with #{RE::IDENTIFIER}/o) - tokens << [:open, :inline] - tokens << [match, :local_variable] - tokens << [scan(/->/), :operator] - tokens << [scan(/#{RE::IDENTIFIER}/o), :ident] - tokens << [:close, :inline] - next - elsif check(/->/) - match << scan(/->/) - kind = :error - end - elsif match = scan(/\{/) - if check(/\$/) - kind = :delimiter - states[-1] = [states.last, delimiter] - delimiter = nil - states.push :php - tokens << [:open, :inline] - else - kind = :string - end - elsif scan(/\$\{#{RE::IDENTIFIER}\}/o) - kind = :local_variable - elsif scan(/\$/) - kind = :content - end - - when :class_expected - if scan(/\s+/) - kind = :space - elsif match = scan(/#{RE::IDENTIFIER}/o) - kind = :class - states.pop - else - states.pop - next - end - - when :function_expected - if scan(/\s+/) - kind = :space - elsif scan(/&/) - kind = :operator - elsif match = scan(/#{RE::IDENTIFIER}/o) - kind = :function - states.pop - else - states.pop - next - end - - else - raise_inspect 'Unknown state!', tokens, states - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, states - end - raise_inspect 'Empty token', tokens, states unless match - - tokens << [match, kind] - - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/plaintext.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/plaintext.rb deleted file mode 100644 index 6cbb1196..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/plaintext.rb +++ /dev/null @@ -1,21 +0,0 @@ -module CodeRay -module Scanners - - class Plaintext < Scanner - - register_for :plaintext, :plain - title 'Plain text' - - include Streamable - - KINDS_NOT_LOC = [:plain] - - def scan_tokens tokens, options - text = (scan_until(/\z/) || '') - tokens << [text, :plain] - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/python.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/python.rb deleted file mode 100644 index 1daa79fc..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/python.rb +++ /dev/null @@ -1,285 +0,0 @@ -module CodeRay -module Scanners - - # Bases on pygments' PythonLexer, see - # http://dev.pocoo.org/projects/pygments/browser/pygments/lexers/agile.py. - class Python < Scanner - - include Streamable - - register_for :python - file_extension 'py' - - KEYWORDS = [ - 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', - 'del', 'elif', 'else', 'except', 'finally', 'for', - 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', - 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield', - 'nonlocal', # new in Python 3 - ] - - OLD_KEYWORDS = [ - 'exec', 'print', # gone in Python 3 - ] - - PREDEFINED_METHODS_AND_TYPES = %w[ - __import__ abs all any apply basestring bin bool buffer - bytearray bytes callable chr classmethod cmp coerce compile - complex delattr dict dir divmod enumerate eval execfile exit - file filter float frozenset getattr globals hasattr hash hex id - input int intern isinstance issubclass iter len list locals - long map max min next object oct open ord pow property range - raw_input reduce reload repr reversed round set setattr slice - sorted staticmethod str sum super tuple type unichr unicode - vars xrange zip - ] - - PREDEFINED_EXCEPTIONS = %w[ - ArithmeticError AssertionError AttributeError - BaseException DeprecationWarning EOFError EnvironmentError - Exception FloatingPointError FutureWarning GeneratorExit IOError - ImportError ImportWarning IndentationError IndexError KeyError - KeyboardInterrupt LookupError MemoryError NameError - NotImplemented NotImplementedError OSError OverflowError - OverflowWarning PendingDeprecationWarning ReferenceError - RuntimeError RuntimeWarning StandardError StopIteration - SyntaxError SyntaxWarning SystemError SystemExit TabError - TypeError UnboundLocalError UnicodeDecodeError - UnicodeEncodeError UnicodeError UnicodeTranslateError - UnicodeWarning UserWarning ValueError Warning ZeroDivisionError - ] - - PREDEFINED_VARIABLES_AND_CONSTANTS = [ - 'False', 'True', 'None', # "keywords" since Python 3 - 'self', 'Ellipsis', 'NotImplemented', - ] - - IDENT_KIND = WordList.new(:ident). - add(KEYWORDS, :keyword). - add(OLD_KEYWORDS, :old_keyword). - add(PREDEFINED_METHODS_AND_TYPES, :predefined). - add(PREDEFINED_VARIABLES_AND_CONSTANTS, :pre_constant). - add(PREDEFINED_EXCEPTIONS, :exception) - - NAME = / [^\W\d] \w* /x - ESCAPE = / [abfnrtv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} | N\{[-\w ]+\} /x - - OPERATOR = / - \.\.\. | # ellipsis - \.(?!\d) | # dot but not decimal point - [,;:()\[\]{}] | # simple delimiters - \/\/=? | \*\*=? | # special math - [-+*\/%&|^]=? | # ordinary math and binary logic - [~`] | # binary complement and inspection - <<=? | >>=? | [<>=]=? | != # comparison and assignment - /x - - STRING_DELIMITER_REGEXP = Hash.new do |h, delimiter| - h[delimiter] = Regexp.union delimiter - end - - STRING_CONTENT_REGEXP = Hash.new do |h, delimiter| - h[delimiter] = / [^\\\n]+? (?= \\ | $ | #{Regexp.escape(delimiter)} ) /x - end - - DEF_NEW_STATE = WordList.new(:initial). - add(%w(def), :def_expected). - add(%w(import from), :include_expected). - add(%w(class), :class_expected) - - DESCRIPTOR = / - #{NAME} - (?: \. #{NAME} )* - | \* - /x - - def scan_tokens tokens, options - - state = :initial - string_delimiter = nil - string_raw = false - import_clause = class_name_follows = last_token_dot = false - unicode = string.respond_to?(:encoding) && string.encoding.name == 'UTF-8' - from_import_state = [] - - until eos? - - kind = nil - match = nil - - if state == :string - if scan(STRING_DELIMITER_REGEXP[string_delimiter]) - tokens << [matched, :delimiter] - tokens << [:close, :string] - state = :initial - next - elsif string_delimiter.size == 3 && scan(/\n/) - kind = :content - elsif scan(STRING_CONTENT_REGEXP[string_delimiter]) - kind = :content - elsif !string_raw && scan(/ \\ #{ESCAPE} /ox) - kind = :char - elsif scan(/ \\ #{UNICODE_ESCAPE} /ox) - kind = :char - elsif scan(/ \\ . /x) - kind = :content - elsif scan(/ \\ | $ /x) - tokens << [:close, :string] - kind = :error - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens, state - end - - elsif match = scan(/ [ \t]+ | \\\n /x) - tokens << [match, :space] - next - - elsif match = scan(/\n/) - tokens << [match, :space] - state = :initial if state == :include_expected - next - - elsif match = scan(/ \# [^\n]* /mx) - tokens << [match, :comment] - next - - elsif state == :initial - - if scan(/#{OPERATOR}/o) - kind = :operator - - elsif match = scan(/(u?r?|b)?("""|"|'''|')/i) - tokens << [:open, :string] - string_delimiter = self[2] - string_raw = false - modifiers = self[1] - unless modifiers.empty? - string_raw = !!modifiers.index(?r) - tokens << [modifiers, :modifier] - match = string_delimiter - end - state = :string - kind = :delimiter - - # TODO: backticks - - elsif match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) - kind = IDENT_KIND[match] - # TODO: keyword arguments - kind = :ident if last_token_dot - if kind == :old_keyword - kind = check(/\(/) ? :ident : :keyword - elsif kind == :predefined && check(/ *=/) - kind = :ident - elsif kind == :keyword - state = DEF_NEW_STATE[match] - from_import_state << match.to_sym if state == :include_expected - end - - elsif scan(/@[a-zA-Z0-9_.]+[lL]?/) - kind = :decorator - - elsif scan(/0[xX][0-9A-Fa-f]+[lL]?/) - kind = :hex - - elsif scan(/0[bB][01]+[lL]?/) - kind = :bin - - elsif match = scan(/(?:\d*\.\d+|\d+\.\d*)(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) - kind = :float - if scan(/[jJ]/) - match << matched - kind = :imaginary - end - - elsif scan(/0[oO][0-7]+|0[0-7]+(?![89.eE])[lL]?/) - kind = :oct - - elsif match = scan(/\d+([lL])?/) - kind = :integer - if self[1] == nil && scan(/[jJ]/) - match << matched - kind = :imaginary - end - - else - getch - kind = :error - - end - - elsif state == :def_expected - state = :initial - if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) - kind = :method - else - next - end - - elsif state == :class_expected - state = :initial - if match = scan(unicode ? /#{NAME}/uo : /#{NAME}/o) - kind = :class - else - next - end - - elsif state == :include_expected - if match = scan(unicode ? /#{DESCRIPTOR}/uo : /#{DESCRIPTOR}/o) - kind = :include - if match == 'as' - kind = :keyword - from_import_state << :as - elsif from_import_state.first == :from && match == 'import' - kind = :keyword - from_import_state << :import - elsif from_import_state.last == :as - # kind = match[0,1][unicode ? /[[:upper:]]/u : /[[:upper:]]/] ? :class : :method - kind = :ident - from_import_state.pop - elsif IDENT_KIND[match] == :keyword - unscan - match = nil - state = :initial - next - end - elsif match = scan(/,/) - from_import_state.pop if from_import_state.last == :as - kind = :operator - else - from_import_state = [] - state = :initial - next - end - - else - raise_inspect 'Unknown state', tokens, state - - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, state - end - raise_inspect 'Empty token', tokens, state unless match - - last_token_dot = match == '.' - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, :string] - end - - tokens - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/rhtml.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/rhtml.rb deleted file mode 100644 index 378d0786..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/rhtml.rb +++ /dev/null @@ -1,78 +0,0 @@ -module CodeRay -module Scanners - - load :html - load :ruby - - # RHTML Scanner - class RHTML < Scanner - - include Streamable - register_for :rhtml - title 'HTML ERB Template' - - KINDS_NOT_LOC = HTML::KINDS_NOT_LOC - - ERB_RUBY_BLOCK = / - <%(?!%)[=-]? - (?> - [^\-%]* # normal* - (?> # special - (?: %(?!>) | -(?!%>) ) - [^\-%]* # normal* - )* - ) - (?: -?%> )? - /x - - START_OF_ERB = / - <%(?!%) - /x - - private - - def setup - @ruby_scanner = CodeRay.scanner :ruby, :tokens => @tokens, :keep_tokens => true - @html_scanner = CodeRay.scanner :html, :tokens => @tokens, :keep_tokens => true, :keep_state => true - end - - def reset_instance - super - @html_scanner.reset - end - - def scan_tokens tokens, options - - until eos? - - if (match = scan_until(/(?=#{START_OF_ERB})/o) || scan_until(/\z/)) and not match.empty? - @html_scanner.tokenize match - - elsif match = scan(/#{ERB_RUBY_BLOCK}/o) - start_tag = match[/\A<%[-=#]?/] - end_tag = match[/-?%?>?\z/] - tokens << [:open, :inline] - tokens << [start_tag, :inline_delimiter] - code = match[start_tag.size .. -1 - end_tag.size] - if start_tag == '<%#' - tokens << [code, :comment] - else - @ruby_scanner.tokenize code - end - tokens << [end_tag, :inline_delimiter] unless end_tag.empty? - tokens << [:close, :inline] - - else - raise_inspect 'else-case reached!', tokens - end - - end - - tokens - - end - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby.rb deleted file mode 100644 index 3cadc64d..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby.rb +++ /dev/null @@ -1,444 +0,0 @@ -# encoding: utf-8 -module CodeRay -module Scanners - - # This scanner is really complex, since Ruby _is_ a complex language! - # - # It tries to highlight 100% of all common code, - # and 90% of strange codes. - # - # It is optimized for HTML highlighting, and is not very useful for - # parsing or pretty printing. - # - # For now, I think it's better than the scanners in VIM or Syntax, or - # any highlighter I was able to find, except Caleb's RubyLexer. - # - # I hope it's also better than the rdoc/irb lexer. - class Ruby < Scanner - - include Streamable - - register_for :ruby - file_extension 'rb' - - helper :patterns - - if not defined? EncodingError - EncodingError = Class.new Exception - end - - private - def scan_tokens tokens, options - if string.respond_to?(:encoding) - unless string.encoding == Encoding::UTF_8 - self.string = string.encode Encoding::UTF_8, - :invalid => :replace, :undef => :replace, :replace => '?' - end - unicode = false - else - unicode = exist?(/[^\x00-\x7f]/) - end - - last_token_dot = false - value_expected = true - heredocs = nil - last_state = nil - state = :initial - depth = nil - inline_block_stack = [] - - - patterns = Patterns # avoid constant lookup - - until eos? - match = nil - kind = nil - - if state.instance_of? patterns::StringState -# {{{ - match = scan_until(state.pattern) || scan_until(/\z/) - tokens << [match, :content] unless match.empty? - break if eos? - - if state.heredoc and self[1] # end of heredoc - match = getch.to_s - match << scan_until(/$/) unless eos? - tokens << [match, :delimiter] - tokens << [:close, state.type] - state = state.next_state - next - end - - case match = getch - - when state.delim - if state.paren - state.paren_depth -= 1 - if state.paren_depth > 0 - tokens << [match, :nesting_delimiter] - next - end - end - tokens << [match, :delimiter] - if state.type == :regexp and not eos? - modifiers = scan(/#{patterns::REGEXP_MODIFIERS}/ox) - tokens << [modifiers, :modifier] unless modifiers.empty? - end - tokens << [:close, state.type] - value_expected = false - state = state.next_state - - when '\\' - if state.interpreted - if esc = scan(/ #{patterns::ESCAPE} /ox) - tokens << [match + esc, :char] - else - tokens << [match, :error] - end - else - case m = getch - when state.delim, '\\' - tokens << [match + m, :char] - when nil - tokens << [match, :error] - else - tokens << [match + m, :content] - end - end - - when '#' - case peek(1) - when '{' - inline_block_stack << [state, depth, heredocs] - value_expected = true - state = :initial - depth = 1 - tokens << [:open, :inline] - tokens << [match + getch, :inline_delimiter] - when '$', '@' - tokens << [match, :escape] - last_state = state # scan one token as normal code, then return here - state = :initial - else - raise_inspect 'else-case # reached; #%p not handled' % peek(1), tokens - end - - when state.paren - state.paren_depth += 1 - tokens << [match, :nesting_delimiter] - - when /#{patterns::REGEXP_SYMBOLS}/ox - tokens << [match, :function] - - else - raise_inspect 'else-case " reached; %p not handled, state = %p' % [match, state], tokens - - end - next -# }}} - else -# {{{ - if match = scan(/[ \t\f]+/) - kind = :space - match << scan(/\s*/) unless eos? || heredocs - value_expected = true if match.index(?\n) - tokens << [match, kind] - next - - elsif match = scan(/\\?\n/) - kind = :space - if match == "\n" - value_expected = true - state = :initial if state == :undef_comma_expected - end - if heredocs - unscan # heredoc scanning needs \n at start - state = heredocs.shift - tokens << [:open, state.type] - heredocs = nil if heredocs.empty? - next - else - match << scan(/\s*/) unless eos? - end - tokens << [match, kind] - next - - elsif bol? && match = scan(/\#!.*/) - tokens << [match, :doctype] - next - - elsif match = scan(/\#.*/) or - ( bol? and match = scan(/#{patterns::RUBYDOC_OR_DATA}/o) ) - kind = :comment - tokens << [match, kind] - next - - elsif state == :initial - - # IDENTS # - if match = scan(unicode ? /#{patterns::METHOD_NAME}/uo : - /#{patterns::METHOD_NAME}/o) - if last_token_dot - kind = if match[/^[A-Z]/] and not match?(/\(/) then :constant else :ident end - else - if value_expected != :expect_colon && scan(/:(?= )/) - tokens << [match, :key] - match = ':' - kind = :operator - else - kind = patterns::IDENT_KIND[match] - if kind == :ident - if match[/\A[A-Z]/] and not match[/[!?]$/] and not match?(/\(/) - kind = :constant - end - elsif kind == :reserved - state = patterns::DEF_NEW_STATE[match] - value_expected = :set if patterns::KEYWORDS_EXPECTING_VALUE[match] - end - end - end - value_expected = :set if check(/#{patterns::VALUE_FOLLOWS}/o) - - elsif last_token_dot and match = scan(/#{patterns::METHOD_NAME_OPERATOR}|\(/o) - kind = :ident - value_expected = :set if check(unicode ? /#{patterns::VALUE_FOLLOWS}/uo : - /#{patterns::VALUE_FOLLOWS}/o) - - # OPERATORS # - elsif not last_token_dot and match = scan(/ \.\.\.? | (?:\.|::)() | [,\(\)\[\]\{\}] | ==?=? /x) - if match !~ / [.\)\]\}] /x or match =~ /\.\.\.?/ - value_expected = :set - end - last_token_dot = :set if self[1] - kind = :operator - unless inline_block_stack.empty? - case match - when '{' - depth += 1 - when '}' - depth -= 1 - if depth == 0 # closing brace of inline block reached - state, depth, heredocs = inline_block_stack.pop - heredocs = nil if heredocs && heredocs.empty? - tokens << [match, :inline_delimiter] - kind = :inline - match = :close - end - end - end - - elsif match = scan(/ ['"] /mx) - tokens << [:open, :string] - kind = :delimiter - state = patterns::StringState.new :string, match == '"', match # important for streaming - - elsif match = scan(unicode ? /#{patterns::INSTANCE_VARIABLE}/uo : - /#{patterns::INSTANCE_VARIABLE}/o) - kind = :instance_variable - - elsif value_expected and match = scan(/\//) - tokens << [:open, :regexp] - kind = :delimiter - interpreted = true - state = patterns::StringState.new :regexp, interpreted, match - - # elsif match = scan(/[-+]?#{patterns::NUMERIC}/o) - elsif match = value_expected ? scan(/[-+]?#{patterns::NUMERIC}/o) : scan(/#{patterns::NUMERIC}/o) - kind = self[1] ? :float : :integer - - elsif match = scan(unicode ? /#{patterns::SYMBOL}/uo : - /#{patterns::SYMBOL}/o) - case delim = match[1] - when ?', ?" - tokens << [:open, :symbol] - tokens << [':', :symbol] - match = delim.chr - kind = :delimiter - state = patterns::StringState.new :symbol, delim == ?", match - else - kind = :symbol - end - - elsif match = scan(/ -[>=]? | [+!~^]=? | [*|&]{1,2}=? | >>? /x) - value_expected = :set - kind = :operator - - elsif value_expected and match = scan(unicode ? /#{patterns::HEREDOC_OPEN}/uo : - /#{patterns::HEREDOC_OPEN}/o) - indented = self[1] == '-' - quote = self[3] - delim = self[quote ? 4 : 2] - kind = patterns::QUOTE_TO_TYPE[quote] - tokens << [:open, kind] - tokens << [match, :delimiter] - match = :close - heredoc = patterns::StringState.new kind, quote != '\'', delim, (indented ? :indented : :linestart ) - heredocs ||= [] # create heredocs if empty - heredocs << heredoc - - elsif value_expected and match = scan(/#{patterns::FANCY_START_CORRECT}/o) - kind, interpreted = *patterns::FancyStringType.fetch(self[1]) do - raise_inspect 'Unknown fancy string: %%%p' % k, tokens - end - tokens << [:open, kind] - state = patterns::StringState.new kind, interpreted, self[2] - kind = :delimiter - - elsif value_expected and match = scan(unicode ? /#{patterns::CHARACTER}/uo : - /#{patterns::CHARACTER}/o) - kind = :integer - - elsif match = scan(/ [\/%]=? | <(?:<|=>?)? | [?:;] /x) - value_expected = :set - kind = :operator - - elsif match = scan(/`/) - if last_token_dot - kind = :operator - else - tokens << [:open, :shell] - kind = :delimiter - state = patterns::StringState.new :shell, true, match - end - - elsif match = scan(unicode ? /#{patterns::GLOBAL_VARIABLE}/uo : - /#{patterns::GLOBAL_VARIABLE}/o) - kind = :global_variable - - elsif match = scan(unicode ? /#{patterns::CLASS_VARIABLE}/uo : - /#{patterns::CLASS_VARIABLE}/o) - kind = :class_variable - - else - if !unicode && !string.respond_to?(:encoding) - # check for unicode - debug, $DEBUG = $DEBUG, false - begin - if check(/./mu).size > 1 - # seems like we should try again with unicode - unicode = true - end - rescue - # bad unicode char; use getch - ensure - $DEBUG = debug - end - next if unicode - end - kind = :error - match = scan(unicode ? /./mu : /./m) - - end - - elsif state == :def_expected - state = :initial - if scan(/self\./) - tokens << ['self', :pre_constant] - tokens << ['.', :operator] - end - if match = scan(unicode ? /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/uo : - /(?>#{patterns::METHOD_NAME_EX})(?!\.|::)/o) - kind = :method - else - next - end - - elsif state == :module_expected - if match = scan(/< 1 - state = this_block.first - tokens << [:close, state.type] - end - - tokens - end - - end - -end -end - -# vim:fdm=marker diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby/patterns.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby/patterns.rb deleted file mode 100644 index ba3ac8a4..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/ruby/patterns.rb +++ /dev/null @@ -1,252 +0,0 @@ -# encoding: utf-8 -module CodeRay -module Scanners - - module Ruby::Patterns # :nodoc: - - RESERVED_WORDS = %w[ - and def end in or unless begin - defined? ensure module redo super until - BEGIN break do next rescue then - when END case else for retry - while alias class elsif if not return - undef yield - ] - - DEF_KEYWORDS = %w[ def ] - UNDEF_KEYWORDS = %w[ undef ] - ALIAS_KEYWORDS = %w[ alias ] - MODULE_KEYWORDS = %w[ class module ] - DEF_NEW_STATE = WordList.new(:initial). - add(DEF_KEYWORDS, :def_expected). - add(UNDEF_KEYWORDS, :undef_expected). - add(ALIAS_KEYWORDS, :alias_expected). - add(MODULE_KEYWORDS, :module_expected) - - PREDEFINED_CONSTANTS = %w[ - nil true false self - DATA ARGV ARGF - __FILE__ __LINE__ __ENCODING__ - ] - - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_CONSTANTS, :pre_constant) - - if /\w/u === '∑' - # MRI 1.8.6, 1.8.7 - IDENT = /[^\W\d]\w*/ - else - if //.respond_to? :encoding - # MRI 1.9.1, 1.9.2 - IDENT = Regexp.new '[\p{L}\p{M}\p{Pc}\p{Sm}&&[^\x00-\x40\x5b-\x5e\x60\x7b-\x7f]][\p{L}\p{M}\p{N}\p{Pc}\p{Sm}&&[^\x00-\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\x7f]]*' - else - # JRuby, Rubinius - IDENT = /[^\x00-\x40\x5b-\x5e\x60\x7b-\x7f][^\x00-\x2f\x3a-\x40\x5b-\x5e\x60\x7b-\x7f]*/ - end - end - - METHOD_NAME = / #{IDENT} [?!]? /ox - METHOD_NAME_OPERATOR = / - \*\*? # multiplication and power - | [-+~]@? # plus, minus, tilde with and without at sign - | [\/%&|^`] # division, modulo or format strings, and, or, xor, system - | \[\]=? # array getter and setter - | << | >> # append or shift left, shift right - | <=?>? | >=? # comparison, rocket operator - | ===? | =~ # simple equality, case equality, match - | ![~=@]? # negation with and without at sign, not-equal and not-match - /ox - METHOD_NAME_EX = / #{IDENT} (?:[?!]|=(?!>))? | #{METHOD_NAME_OPERATOR} /ox - INSTANCE_VARIABLE = / @ #{IDENT} /ox - CLASS_VARIABLE = / @@ #{IDENT} /ox - OBJECT_VARIABLE = / @@? #{IDENT} /ox - GLOBAL_VARIABLE = / \$ (?: #{IDENT} | [1-9]\d* | 0\w* | [~&+`'=\/,;_.<>!@$?*":\\] | -[a-zA-Z_0-9] ) /ox - PREFIX_VARIABLE = / #{GLOBAL_VARIABLE} | #{OBJECT_VARIABLE} /ox - VARIABLE = / @?@? #{IDENT} | #{GLOBAL_VARIABLE} /ox - - QUOTE_TO_TYPE = { - '`' => :shell, - '/'=> :regexp, - } - QUOTE_TO_TYPE.default = :string - - REGEXP_MODIFIERS = /[mixounse]*/ - REGEXP_SYMBOLS = /[|?*+(){}\[\].^$]/ - - DECIMAL = /\d+(?:_\d+)*/ - OCTAL = /0_?[0-7]+(?:_[0-7]+)*/ - HEXADECIMAL = /0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*/ - BINARY = /0b[01]+(?:_[01]+)*/ - - EXPONENT = / [eE] [+-]? #{DECIMAL} /ox - FLOAT_SUFFIX = / #{EXPONENT} | \. #{DECIMAL} #{EXPONENT}? /ox - FLOAT_OR_INT = / #{DECIMAL} (?: #{FLOAT_SUFFIX} () )? /ox - NUMERIC = / (?: (?=0) (?: #{OCTAL} | #{HEXADECIMAL} | #{BINARY} ) | #{FLOAT_OR_INT} ) /ox - - SYMBOL = / - : - (?: - #{METHOD_NAME_EX} - | #{PREFIX_VARIABLE} - | ['"] - ) - /ox - METHOD_NAME_OR_SYMBOL = / #{METHOD_NAME_EX} | #{SYMBOL} /ox - - SIMPLE_ESCAPE = / - [abefnrstv] - | [0-7]{1,3} - | x[0-9A-Fa-f]{1,2} - | .? - /mx - - CONTROL_META_ESCAPE = / - (?: M-|C-|c ) - (?: \\ (?: M-|C-|c ) )* - (?: [^\\] | \\ #{SIMPLE_ESCAPE} )? - /mox - - ESCAPE = / - #{CONTROL_META_ESCAPE} | #{SIMPLE_ESCAPE} - /mox - - CHARACTER = / - \? - (?: - [^\s\\] - | \\ #{ESCAPE} - ) - /mox - - # NOTE: This is not completely correct, but - # nobody needs heredoc delimiters ending with \n. - # Also, delimiters starting with numbers are allowed. - # but they are more often than not a false positive. - HEREDOC_OPEN = / - << (-)? # $1 = float - (?: - ( #{IDENT} ) # $2 = delim - | - ( ["'`\/] ) # $3 = quote, type - ( [^\n]*? ) \3 # $4 = delim - ) - /mx - - RUBYDOC = / - =begin (?!\S) - .*? - (?: \Z | ^=end (?!\S) [^\n]* ) - /mx - - DATA = / - __END__$ - .*? - (?: \Z | (?=^\#CODE) ) - /mx - - # Checks for a valid value to follow. This enables - # value_expected in method calls without parentheses. - VALUE_FOLLOWS = / - (?>[ \t\f\v]+) - (?: - [%\/][^\s=] - | <<-?\S - | [-+] \d - | #{CHARACTER} - ) - /x - KEYWORDS_EXPECTING_VALUE = WordList.new.add(%w[ - and end in or unless begin - defined? ensure redo super until - break do next rescue then - when case else for retry - while elsif if not return - yield - ]) - - RUBYDOC_OR_DATA = / #{RUBYDOC} | #{DATA} /xo - - RDOC_DATA_START = / ^=begin (?!\S) | ^__END__$ /x - - FANCY_START_CORRECT = / % ( [qQwWxsr] | (?![a-zA-Z0-9]) ) ([^a-zA-Z0-9]) /mx - - FancyStringType = { - 'q' => [:string, false], - 'Q' => [:string, true], - 'r' => [:regexp, true], - 's' => [:symbol, false], - 'x' => [:shell, true] - } - FancyStringType['w'] = FancyStringType['q'] - FancyStringType['W'] = FancyStringType[''] = FancyStringType['Q'] - - class StringState < Struct.new :type, :interpreted, :delim, :heredoc, - :paren, :paren_depth, :pattern, :next_state - - CLOSING_PAREN = Hash[ *%w[ - ( ) - [ ] - < > - { } - ] ] - - CLOSING_PAREN.each { |k,v| k.freeze; v.freeze } # debug, if I try to change it with << - OPENING_PAREN = CLOSING_PAREN.invert - - STRING_PATTERN = Hash.new do |h, k| - delim, interpreted = *k - delim_pattern = Regexp.escape(delim.dup) # dup: workaround for old Ruby - if closing_paren = CLOSING_PAREN[delim] - delim_pattern = delim_pattern[0..-1] if defined? JRUBY_VERSION # JRuby fix - delim_pattern << Regexp.escape(closing_paren) - end - delim_pattern << '\\\\' unless delim == '\\' - - special_escapes = - case interpreted - when :regexp_symbols - '| ' + REGEXP_SYMBOLS.source - when :words - '| \s' - end - - h[k] = - if interpreted and not delim == '#' - / (?= [#{delim_pattern}] | \# [{$@] #{special_escapes} ) /mx - else - / (?= [#{delim_pattern}] #{special_escapes} ) /mx - end - end - - HEREDOC_PATTERN = Hash.new do |h, k| - delim, interpreted, indented = *k - delim_pattern = Regexp.escape(delim.dup) # dup: workaround for old Ruby - delim_pattern = / \n #{ '(?>[\ \t]*)' if indented } #{ Regexp.new delim_pattern } $ /x - h[k] = - if interpreted - / (?= #{delim_pattern}() | \\ | \# [{$@] ) /mx # $1 set == end of heredoc - else - / (?= #{delim_pattern}() | \\ ) /mx - end - end - - def initialize kind, interpreted, delim, heredoc = false - if heredoc - pattern = HEREDOC_PATTERN[ [delim, interpreted, heredoc == :indented] ] - delim = nil - else - pattern = STRING_PATTERN[ [delim, interpreted] ] - if paren = CLOSING_PAREN[delim] - delim, paren = paren, delim - paren_depth = 1 - end - end - super kind, interpreted, delim, heredoc, paren, paren_depth, pattern, :initial - end - end unless defined? StringState - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/scheme.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/scheme.rb deleted file mode 100644 index ba22b80b..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/scheme.rb +++ /dev/null @@ -1,145 +0,0 @@ -module CodeRay - module Scanners - - # Scheme scanner for CodeRay (by closure). - # Thanks to murphy for putting CodeRay into public. - class Scheme < Scanner - - # TODO: function defs - # TODO: built-in functions - - register_for :scheme - file_extension 'scm' - - CORE_FORMS = %w[ - lambda let let* letrec syntax-case define-syntax let-syntax - letrec-syntax begin define quote if or and cond case do delay - quasiquote set! cons force call-with-current-continuation call/cc - ] - - IDENT_KIND = CaseIgnoringWordList.new(:ident). - add(CORE_FORMS, :reserved) - - #IDENTIFIER_INITIAL = /[a-z!@\$%&\*\/\:<=>\?~_\^]/i - #IDENTIFIER_SUBSEQUENT = /#{IDENTIFIER_INITIAL}|\d|\.|\+|-/ - #IDENTIFIER = /#{IDENTIFIER_INITIAL}#{IDENTIFIER_SUBSEQUENT}*|\+|-|\.{3}/ - IDENTIFIER = /[a-zA-Z!@$%&*\/:<=>?~_^][\w!@$%&*\/:<=>?~^.+\-]*|[+-]|\.\.\./ - DIGIT = /\d/ - DIGIT10 = DIGIT - DIGIT16 = /[0-9a-f]/i - DIGIT8 = /[0-7]/ - DIGIT2 = /[01]/ - RADIX16 = /\#x/i - RADIX8 = /\#o/i - RADIX2 = /\#b/i - RADIX10 = /\#d/i - EXACTNESS = /#i|#e/i - SIGN = /[\+-]?/ - EXP_MARK = /[esfdl]/i - EXP = /#{EXP_MARK}#{SIGN}#{DIGIT}+/ - SUFFIX = /#{EXP}?/ - PREFIX10 = /#{RADIX10}?#{EXACTNESS}?|#{EXACTNESS}?#{RADIX10}?/ - PREFIX16 = /#{RADIX16}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX16}/ - PREFIX8 = /#{RADIX8}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX8}/ - PREFIX2 = /#{RADIX2}#{EXACTNESS}?|#{EXACTNESS}?#{RADIX2}/ - UINT10 = /#{DIGIT10}+#*/ - UINT16 = /#{DIGIT16}+#*/ - UINT8 = /#{DIGIT8}+#*/ - UINT2 = /#{DIGIT2}+#*/ - DECIMAL = /#{DIGIT10}+#+\.#*#{SUFFIX}|#{DIGIT10}+\.#{DIGIT10}*#*#{SUFFIX}|\.#{DIGIT10}+#*#{SUFFIX}|#{UINT10}#{EXP}/ - UREAL10 = /#{UINT10}\/#{UINT10}|#{DECIMAL}|#{UINT10}/ - UREAL16 = /#{UINT16}\/#{UINT16}|#{UINT16}/ - UREAL8 = /#{UINT8}\/#{UINT8}|#{UINT8}/ - UREAL2 = /#{UINT2}\/#{UINT2}|#{UINT2}/ - REAL10 = /#{SIGN}#{UREAL10}/ - REAL16 = /#{SIGN}#{UREAL16}/ - REAL8 = /#{SIGN}#{UREAL8}/ - REAL2 = /#{SIGN}#{UREAL2}/ - IMAG10 = /i|#{UREAL10}i/ - IMAG16 = /i|#{UREAL16}i/ - IMAG8 = /i|#{UREAL8}i/ - IMAG2 = /i|#{UREAL2}i/ - COMPLEX10 = /#{REAL10}@#{REAL10}|#{REAL10}\+#{IMAG10}|#{REAL10}-#{IMAG10}|\+#{IMAG10}|-#{IMAG10}|#{REAL10}/ - COMPLEX16 = /#{REAL16}@#{REAL16}|#{REAL16}\+#{IMAG16}|#{REAL16}-#{IMAG16}|\+#{IMAG16}|-#{IMAG16}|#{REAL16}/ - COMPLEX8 = /#{REAL8}@#{REAL8}|#{REAL8}\+#{IMAG8}|#{REAL8}-#{IMAG8}|\+#{IMAG8}|-#{IMAG8}|#{REAL8}/ - COMPLEX2 = /#{REAL2}@#{REAL2}|#{REAL2}\+#{IMAG2}|#{REAL2}-#{IMAG2}|\+#{IMAG2}|-#{IMAG2}|#{REAL2}/ - NUM10 = /#{PREFIX10}?#{COMPLEX10}/ - NUM16 = /#{PREFIX16}#{COMPLEX16}/ - NUM8 = /#{PREFIX8}#{COMPLEX8}/ - NUM2 = /#{PREFIX2}#{COMPLEX2}/ - NUM = /#{NUM10}|#{NUM16}|#{NUM8}|#{NUM2}/ - - private - def scan_tokens tokens,options - - state = :initial - ident_kind = IDENT_KIND - - until eos? - kind = match = nil - - case state - when :initial - if scan(/ \s+ | \\\n /x) - kind = :space - elsif scan(/['\(\[\)\]]|#\(/) - kind = :operator_fat - elsif scan(/;.*/) - kind = :comment - elsif scan(/#\\(?:newline|space|.?)/) - kind = :char - elsif scan(/#[ft]/) - kind = :pre_constant - elsif scan(/#{IDENTIFIER}/o) - kind = ident_kind[matched] - elsif scan(/\./) - kind = :operator - elsif scan(/"/) - tokens << [:open, :string] - state = :string - tokens << ['"', :delimiter] - next - elsif scan(/#{NUM}/o) and not matched.empty? - kind = :integer - elsif getch - kind = :error - end - - when :string - if scan(/[^"\\]+/) or scan(/\\.?/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, :string] - state = :initial - next - else - raise_inspect "else case \" reached; %p not handled." % peek(1), - tokens, state - end - - else - raise "else case reached" - end - - match ||= matched - if $CODERAY_DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens, state unless match - - tokens << [match, kind] - - end # until eos - - if state == :string - tokens << [:close, :string] - end - - tokens - - end #scan_tokens - end #class - end #module scanners -end #module coderay \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/sql.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/sql.rb deleted file mode 100644 index 89075816..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/sql.rb +++ /dev/null @@ -1,162 +0,0 @@ -module CodeRay module Scanners - - # by Josh Goebel - class SQL < Scanner - - register_for :sql - - RESERVED_WORDS = %w( - create database table index trigger drop primary key set select - insert update delete replace into - on from values before and or if exists case when - then else as group order by avg where - join inner outer union engine not - like end using collate show columns begin - ) - - PREDEFINED_TYPES = %w( - char varchar enum binary text tinytext mediumtext - longtext blob tinyblob mediumblob longblob timestamp - date time datetime year double decimal float int - integer tinyint mediumint bigint smallint unsigned bit - bool boolean hex bin oct - ) - - PREDEFINED_FUNCTIONS = %w( sum cast abs pi count min max avg ) - - DIRECTIVES = %w( auto_increment unique default charset ) - - PREDEFINED_CONSTANTS = %w( null true false ) - - IDENT_KIND = CaseIgnoringWordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(PREDEFINED_CONSTANTS, :pre_constant). - add(PREDEFINED_FUNCTIONS, :predefined). - add(DIRECTIVES, :directive) - - ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - - STRING_PREFIXES = /[xnb]|_\w+/i - - def scan_tokens tokens, options - - state = :initial - string_type = nil - string_content = '' - - until eos? - - kind = nil - match = nil - - if state == :initial - - if scan(/ \s+ | \\\n /x) - kind = :space - - elsif scan(/(?:--\s?|#).*/) - kind = :comment - - elsif scan(%r! /\* (?: .*? \*/ | .* ) !mx) - kind = :comment - - elsif scan(/ [-+*\/=<>;,!&^|()\[\]{}~%] | \.(?!\d) /x) - kind = :operator - - elsif scan(/(#{STRING_PREFIXES})?([`"'])/o) - prefix = self[1] - string_type = self[2] - tokens << [:open, :string] - tokens << [prefix, :modifier] if prefix - match = string_type - state = :string - kind = :delimiter - - elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x) - kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase] - - elsif scan(/0[xX][0-9A-Fa-f]+/) - kind = :hex - - elsif scan(/0[0-7]+(?![89.eEfF])/) - kind = :oct - - elsif scan(/(?>\d+)(?![.eEfF])/) - kind = :integer - - elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) - kind = :float - - else - getch - kind = :error - - end - - elsif state == :string - if match = scan(/[^\\"'`]+/) - string_content << match - next - elsif match = scan(/["'`]/) - if string_type == match - if peek(1) == string_type # doubling means escape - string_content << string_type << getch - next - end - unless string_content.empty? - tokens << [string_content, :content] - string_content = '' - end - tokens << [matched, :delimiter] - tokens << [:close, :string] - state = :initial - string_type = nil - next - else - string_content << match - end - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - unless string_content.empty? - tokens << [string_content, :content] - string_content = '' - end - kind = :char - elsif match = scan(/ \\ . /mox) - string_content << match - next - elsif scan(/ \\ | $ /x) - unless string_content.empty? - tokens << [string_content, :content] - string_content = '' - end - kind = :error - state = :initial - else - raise "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise 'else-case reached', tokens - - end - - match ||= matched - unless kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens, state - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - tokens - - end - - end - -end end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/xml.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/xml.rb deleted file mode 100644 index aeabeca8..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/xml.rb +++ /dev/null @@ -1,17 +0,0 @@ -module CodeRay -module Scanners - - load :html - - # XML Scanner - # - # Currently this is the same scanner as Scanners::HTML. - class XML < HTML - - register_for :xml - file_extension 'xml' - - end - -end -end diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/yaml.rb b/vendor/gems/coderay-0.9.7/lib/coderay/scanners/yaml.rb deleted file mode 100644 index 7903ab97..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/scanners/yaml.rb +++ /dev/null @@ -1,140 +0,0 @@ -module CodeRay -module Scanners - - # YAML Scanner - # - # Based on the YAML scanner from Syntax by Jamis Buck. - class YAML < Scanner - - register_for :yaml - file_extension 'yml' - - KINDS_NOT_LOC = :all - - def scan_tokens tokens, options - - value_expected = nil - state = :initial - key_indent = indent = 0 - - until eos? - - kind = nil - match = nil - key_indent = nil if bol? - - if match = scan(/ +[\t ]*/) - kind = :space - - elsif match = scan(/\n+/) - kind = :space - state = :initial if match.index(?\n) - - elsif match = scan(/#.*/) - kind = :comment - - elsif bol? and case - when match = scan(/---|\.\.\./) - tokens << [:open, :head] - tokens << [match, :head] - tokens << [:close, :head] - next - when match = scan(/%.*/) - tokens << [match, :doctype] - next - end - - elsif state == :value and case - when !check(/(?:"[^"]*")(?=: |:$)/) && scan(/"/) - tokens << [:open, :string] - tokens << [matched, :delimiter] - tokens << [matched, :content] if scan(/ [^"\\]* (?: \\. [^"\\]* )* /mx) - tokens << [matched, :delimiter] if scan(/"/) - tokens << [:close, :string] - next - when match = scan(/[|>][-+]?/) - tokens << [:open, :string] - tokens << [match, :delimiter] - string_indent = key_indent || column(pos - match.size - 1) - tokens << [matched, :content] if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) - tokens << [:close, :string] - next - when match = scan(/(?![!"*&]).+?(?=$|\s+#)/) - tokens << [match, :string] - string_indent = key_indent || column(pos - match.size - 1) - tokens << [matched, :string] if scan(/(?:\n+ {#{string_indent + 1}}.*)+/) - next - end - - elsif case - when match = scan(/[-:](?= |$)/) - state = :value if state == :colon && (match == ':' || match == '-') - state = :value if state == :initial && match == '-' - kind = :operator - when match = scan(/[,{}\[\]]/) - kind = :operator - when state == :initial && match = scan(/[\w.() ]*\S(?=: |:$)/) - kind = :key - key_indent = column(pos - match.size - 1) - # tokens << [key_indent.inspect, :debug] - state = :colon - when match = scan(/(?:"[^"\n]*"|'[^'\n]*')(?=: |:$)/) - tokens << [:open, :key] - tokens << [match[0,1], :delimiter] - tokens << [match[1..-2], :content] - tokens << [match[-1,1], :delimiter] - tokens << [:close, :key] - key_indent = column(pos - match.size - 1) - # tokens << [key_indent.inspect, :debug] - state = :colon - next - when scan(/(![\w\/]+)(:([\w:]+))?/) - tokens << [self[1], :type] - if self[2] - tokens << [':', :operator] - tokens << [self[3], :class] - end - next - when scan(/&\S+/) - kind = :variable - when scan(/\*\w+/) - kind = :global_variable - when scan(/< 'at', - :attribute_name => 'an', - :attribute_name_fat => 'af', - :attribute_value => 'av', - :attribute_value_fat => 'aw', - :bin => 'bi', - :char => 'ch', - :class => 'cl', - :class_variable => 'cv', - :color => 'cr', - :comment => 'c', - :complex => 'cm', - :constant => 'co', - :content => 'k', - :decorator => 'de', - :definition => 'df', - :delimiter => 'dl', - :directive => 'di', - :doc => 'do', - :doctype => 'dt', - :doc_string => 'ds', - :entity => 'en', - :error => 'er', - :escape => 'e', - :exception => 'ex', - :float => 'fl', - :function => 'fu', - :global_variable => 'gv', - :hex => 'hx', - :imaginary => 'cm', - :important => 'im', - :include => 'ic', - :inline => 'il', - :inline_delimiter => 'idl', - :instance_variable => 'iv', - :integer => 'i', - :interpreted => 'in', - :keyword => 'kw', - :key => 'ke', - :label => 'la', - :local_variable => 'lv', - :modifier => 'mod', - :oct => 'oc', - :operator_fat => 'of', - :pre_constant => 'pc', - :pre_type => 'pt', - :predefined => 'pd', - :preprocessor => 'pp', - :pseudo_class => 'ps', - :regexp => 'rx', - :reserved => 'r', - :shell => 'sh', - :string => 's', - :symbol => 'sy', - :tag => 'ta', - :tag_fat => 'tf', - :tag_special => 'ts', - :type => 'ty', - :variable => 'v', - :value => 'vl', - :xml_text => 'xt', - - :insert => 'ins', - :delete => 'del', - :change => 'chg', - :head => 'head', - - :ident => :NO_HIGHLIGHT, # 'id' - #:operator => 'op', - :operator => :NO_HIGHLIGHT, # 'op' - :space => :NO_HIGHLIGHT, # 'sp' - :plain => :NO_HIGHLIGHT, - } - ClassOfKind[:method] = ClassOfKind[:function] - ClassOfKind[:open] = ClassOfKind[:close] = ClassOfKind[:delimiter] - ClassOfKind[:nesting_delimiter] = ClassOfKind[:delimiter] - ClassOfKind[:escape] = ClassOfKind[:delimiter] - #ClassOfKind.default = ClassOfKind[:error] or raise 'no class found for :error!' - end -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/lib/coderay/tokens.rb b/vendor/gems/coderay-0.9.7/lib/coderay/tokens.rb deleted file mode 100644 index 6ac5f440..00000000 --- a/vendor/gems/coderay-0.9.7/lib/coderay/tokens.rb +++ /dev/null @@ -1,390 +0,0 @@ -module CodeRay - - # = Tokens - # - # The Tokens class represents a list of tokens returnd from - # a Scanner. - # - # A token is not a special object, just a two-element Array - # consisting of - # * the _token_ _text_ (the original source of the token in a String) or - # a _token_ _action_ (:open, :close, :begin_line, :end_line) - # * the _token_ _kind_ (a Symbol representing the type of the token) - # - # A token looks like this: - # - # ['# It looks like this', :comment] - # ['3.1415926', :float] - # ['$^', :error] - # - # Some scanners also yield sub-tokens, represented by special - # token actions, namely :open and :close. - # - # The Ruby scanner, for example, splits "a string" into: - # - # [ - # [:open, :string], - # ['"', :delimiter], - # ['a string', :content], - # ['"', :delimiter], - # [:close, :string] - # ] - # - # Tokens is the interface between Scanners and Encoders: - # The input is split and saved into a Tokens object. The Encoder - # then builds the output from this object. - # - # Thus, the syntax below becomes clear: - # - # CodeRay.scan('price = 2.59', :ruby).html - # # the Tokens object is here -------^ - # - # See how small it is? ;) - # - # Tokens gives you the power to handle pre-scanned code very easily: - # You can convert it to a webpage, a YAML file, or dump it into a gzip'ed string - # that you put in your DB. - # - # It also allows you to generate tokens directly (without using a scanner), - # to load them from a file, and still use any Encoder that CodeRay provides. - # - # Tokens' subclass TokenStream allows streaming to save memory. - class Tokens < Array - - # The Scanner instance that created the tokens. - attr_accessor :scanner - - # Whether the object is a TokenStream. - # - # Returns false. - def stream? - false - end - - # Iterates over all tokens. - # - # If a filter is given, only tokens of that kind are yielded. - def each kind_filter = nil, &block - unless kind_filter - super(&block) - else - super() do |text, kind| - next unless kind == kind_filter - yield text, kind - end - end - end - - # Iterates over all text tokens. - # Range tokens like [:open, :string] are left out. - # - # Example: - # tokens.each_text_token { |text, kind| text.replace html_escape(text) } - def each_text_token - each do |text, kind| - next unless text.is_a? ::String - yield text, kind - end - end - - # Encode the tokens using encoder. - # - # encoder can be - # * a symbol like :html oder :statistic - # * an Encoder class - # * an Encoder object - # - # options are passed to the encoder. - def encode encoder, options = {} - unless encoder.is_a? Encoders::Encoder - unless encoder.is_a? Class - encoder_class = Encoders[encoder] - end - encoder = encoder_class.new options - end - encoder.encode_tokens self, options - end - - - # Turn into a string using Encoders::Text. - # - # +options+ are passed to the encoder if given. - def to_s options = {} - encode :text, options - end - - # Redirects unknown methods to encoder calls. - # - # For example, if you call +tokens.html+, the HTML encoder - # is used to highlight the tokens. - def method_missing meth, options = {} - Encoders[meth].new(options).encode_tokens self - end - - # Returns the tokens compressed by joining consecutive - # tokens of the same kind. - # - # This can not be undone, but should yield the same output - # in most Encoders. It basically makes the output smaller. - # - # Combined with dump, it saves space for the cost of time. - # - # If the scanner is written carefully, this is not required - - # for example, consecutive //-comment lines could already be - # joined in one comment token by the Scanner. - def optimize - last_kind = last_text = nil - new = self.class.new - for text, kind in self - if text.is_a? String - if kind == last_kind - last_text << text - else - new << [last_text, last_kind] if last_kind - last_text = text - last_kind = kind - end - else - new << [last_text, last_kind] if last_kind - last_kind = last_text = nil - new << [text, kind] - end - end - new << [last_text, last_kind] if last_kind - new - end - - # Compact the object itself; see optimize. - def optimize! - replace optimize - end - - # Ensure that all :open tokens have a correspondent :close one. - # - # TODO: Test this! - def fix - tokens = self.class.new - # Check token nesting using a stack of kinds. - opened = [] - for type, kind in self - case type - when :open - opened.push [:close, kind] - when :begin_line - opened.push [:end_line, kind] - when :close, :end_line - expected = opened.pop - if [type, kind] != expected - # Unexpected :close; decide what to do based on the kind: - # - token was never opened: delete the :close (just skip it) - next unless opened.rindex expected - # - token was opened earlier: also close tokens in between - tokens << token until (token = opened.pop) == expected - end - end - tokens << [type, kind] - end - # Close remaining opened tokens - tokens << token while token = opened.pop - tokens - end - - def fix! - replace fix - end - - # TODO: Scanner#split_into_lines - # - # Makes sure that: - # - newlines are single tokens - # (which means all other token are single-line) - # - there are no open tokens at the end the line - # - # This makes it simple for encoders that work line-oriented, - # like HTML with list-style numeration. - def split_into_lines - raise NotImplementedError - end - - def split_into_lines! - replace split_into_lines - end - - # Dumps the object into a String that can be saved - # in files or databases. - # - # The dump is created with Marshal.dump; - # In addition, it is gzipped using GZip.gzip. - # - # The returned String object includes Undumping - # so it has an #undump method. See Tokens.load. - # - # You can configure the level of compression, - # but the default value 7 should be what you want - # in most cases as it is a good compromise between - # speed and compression rate. - # - # See GZip module. - def dump gzip_level = 7 - require 'coderay/helpers/gzip_simple' - dump = Marshal.dump self - dump = dump.gzip gzip_level - dump.extend Undumping - end - - # The total size of the tokens. - # Should be equal to the input size before - # scanning. - def text_size - size = 0 - each_text_token do |t, k| - size + t.size - end - size - end - - # Return all text tokens joined into a single string. - def text - map { |t, k| t if t.is_a? ::String }.join - end - - # Include this module to give an object an #undump - # method. - # - # The string returned by Tokens.dump includes Undumping. - module Undumping - # Calls Tokens.load with itself. - def undump - Tokens.load self - end - end - - # Undump the object using Marshal.load, then - # unzip it using GZip.gunzip. - # - # The result is commonly a Tokens object, but - # this is not guaranteed. - def Tokens.load dump - require 'coderay/helpers/gzip_simple' - dump = dump.gunzip - @dump = Marshal.load dump - end - - end - - - # = TokenStream - # - # The TokenStream class is a fake Array without elements. - # - # It redirects the method << to a block given at creation. - # - # This allows scanners and Encoders to use streaming (no - # tokens are saved, the input is highlighted the same time it - # is scanned) with the same code. - # - # See CodeRay.encode_stream and CodeRay.scan_stream - class TokenStream < Tokens - - # Whether the object is a TokenStream. - # - # Returns true. - def stream? - true - end - - # The Array is empty, but size counts the tokens given by <<. - attr_reader :size - - # Creates a new TokenStream that calls +block+ whenever - # its << method is called. - # - # Example: - # - # require 'coderay' - # - # token_stream = CodeRay::TokenStream.new do |text, kind| - # puts 'kind: %s, text size: %d.' % [kind, text.size] - # end - # - # token_stream << ['/\d+/', :regexp] - # #-> kind: rexpexp, text size: 5. - # - def initialize &block - raise ArgumentError, 'Block expected for streaming.' unless block - @callback = block - @size = 0 - end - - # Calls +block+ with +token+ and increments size. - # - # Returns self. - def << token - @callback.call(*token) - @size += 1 - self - end - - # This method is not implemented due to speed reasons. Use Tokens. - def text_size - raise NotImplementedError, - 'This method is not implemented due to speed reasons.' - end - - # A TokenStream cannot be dumped. Use Tokens. - def dump - raise NotImplementedError, 'A TokenStream cannot be dumped.' - end - - # A TokenStream cannot be optimized. Use Tokens. - def optimize - raise NotImplementedError, 'A TokenStream cannot be optimized.' - end - - end - -end - -if $0 == __FILE__ - $VERBOSE = true - $: << File.join(File.dirname(__FILE__), '..') - eval DATA.read, nil, $0, __LINE__ + 4 -end - -__END__ -require 'test/unit' - -class TokensTest < Test::Unit::TestCase - - def test_creation - assert CodeRay::Tokens < Array - tokens = nil - assert_nothing_raised do - tokens = CodeRay::Tokens.new - end - assert_kind_of Array, tokens - end - - def test_adding_tokens - tokens = CodeRay::Tokens.new - assert_nothing_raised do - tokens << ['string', :type] - tokens << ['()', :operator] - end - assert_equal tokens.size, 2 - end - - def test_dump_undump - tokens = CodeRay::Tokens.new - assert_nothing_raised do - tokens << ['string', :type] - tokens << ['()', :operator] - end - tokens2 = nil - assert_nothing_raised do - tokens2 = tokens.dump.undump - end - assert_equal tokens, tokens2 - end - -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/test/functional/basic.rb b/vendor/gems/coderay-0.9.7/test/functional/basic.rb deleted file mode 100644 index 8ecd3d35..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/basic.rb +++ /dev/null @@ -1,122 +0,0 @@ -require 'test/unit' -require 'coderay' - -class BasicTest < Test::Unit::TestCase - - def test_version - assert_nothing_raised do - assert_match(/\A\d\.\d\.\d\z/, CodeRay::VERSION) - end - end - - RUBY_TEST_CODE = 'puts "Hello, World!"' - - RUBY_TEST_TOKENS = [ - ['puts', :ident], - [' ', :space], - [:open, :string], - ['"', :delimiter], - ['Hello, World!', :content], - ['"', :delimiter], - [:close, :string] - ] - def test_simple_scan - assert_nothing_raised do - assert_equal RUBY_TEST_TOKENS, CodeRay.scan(RUBY_TEST_CODE, :ruby).to_ary - end - end - - RUBY_TEST_HTML = 'puts "' + - 'Hello, World!"' - def test_simple_highlight - assert_nothing_raised do - assert_equal RUBY_TEST_HTML, CodeRay.scan(RUBY_TEST_CODE, :ruby).html - end - end - - def test_duo - assert_equal(RUBY_TEST_CODE, - CodeRay::Duo[:plain, :plain].highlight(RUBY_TEST_CODE)) - assert_equal(RUBY_TEST_CODE, - CodeRay::Duo[:plain => :plain].highlight(RUBY_TEST_CODE)) - end - - def test_duo_stream - assert_equal(RUBY_TEST_CODE, - CodeRay::Duo[:plain, :plain].highlight(RUBY_TEST_CODE, :stream => true)) - end - - def test_comment_filter - assert_equal <<-EXPECTED, CodeRay.scan(<<-INPUT, :ruby).comment_filter.text -#!/usr/bin/env ruby - -code - -more code - EXPECTED -#!/usr/bin/env ruby -=begin -A multi-line comment. -=end -code -# A single-line comment. -more code # and another comment, in-line. - INPUT - end - - def test_lines_of_code - assert_equal 2, CodeRay.scan(<<-INPUT, :ruby).lines_of_code -#!/usr/bin/env ruby -=begin -A multi-line comment. -=end -code -# A single-line comment. -more code # and another comment, in-line. - INPUT - rHTML = <<-RHTML - - - - - - <%= controller.controller_name.titleize %>: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

    <%= flash[:notice] %>

    - -
    - <%= yield %> -
    - - - - RHTML - assert_equal 0, CodeRay.scan(rHTML, :html).lines_of_code - assert_equal 0, CodeRay.scan(rHTML, :php).lines_of_code - assert_equal 0, CodeRay.scan(rHTML, :yaml).lines_of_code - assert_equal 4, CodeRay.scan(rHTML, :rhtml).lines_of_code - end - - def test_rubygems_not_loaded - assert_equal nil, defined? Gem - end if ENV['check_rubygems'] && RUBY_VERSION < '1.9' - - def test_list_of_encoders - assert_kind_of(Array, CodeRay::Encoders.list) - assert CodeRay::Encoders.list.include?('count') - end - - def test_list_of_scanners - assert_kind_of(Array, CodeRay::Scanners.list) - assert CodeRay::Scanners.list.include?('plaintext') - end - - def test_scan_a_frozen_string - CodeRay.scan RUBY_VERSION, :ruby - end - -end diff --git a/vendor/gems/coderay-0.9.7/test/functional/basic.rbc b/vendor/gems/coderay-0.9.7/test/functional/basic.rbc deleted file mode 100644 index 1e114cf7..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/basic.rbc +++ /dev/null @@ -1,2022 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -53 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -47 -49 -1 -1 -15 -99 -7 -3 -45 -4 -5 -43 -6 -43 -7 -65 -49 -8 -3 -13 -99 -12 -7 -9 -12 -7 -10 -12 -65 -12 -49 -11 -4 -15 -49 -9 -0 -15 -2 -11 -I -6 -I -0 -I -0 -I -0 -n -p -12 -s -9 -test/unit -x -7 -require -s -7 -coderay -x -9 -BasicTest -x -4 -Test -n -x -4 -Unit -x -8 -TestCase -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -9 -BasicTest -i -263 -5 -66 -99 -7 -0 -7 -1 -65 -67 -49 -2 -0 -49 -3 -4 -15 -65 -7 -4 -7 -5 -64 -49 -6 -2 -15 -65 -7 -7 -7 -8 -64 -7 -9 -35 -2 -7 -10 -64 -7 -11 -35 -2 -7 -12 -7 -13 -35 -2 -7 -14 -64 -7 -15 -35 -2 -7 -16 -64 -7 -17 -35 -2 -7 -14 -64 -7 -15 -35 -2 -7 -18 -7 -13 -35 -2 -35 -7 -49 -6 -2 -15 -99 -7 -19 -7 -20 -65 -67 -49 -2 -0 -49 -3 -4 -15 -65 -7 -21 -7 -22 -64 -7 -23 -64 -81 -24 -49 -6 -2 -15 -99 -7 -25 -7 -26 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -27 -7 -28 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -29 -7 -30 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -31 -7 -32 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -33 -7 -34 -65 -67 -49 -2 -0 -49 -3 -4 -15 -45 -35 -36 -7 -37 -64 -49 -38 -1 -13 -9 -202 -15 -45 -39 -40 -7 -41 -64 -84 -42 -9 -219 -99 -7 -43 -7 -44 -65 -67 -49 -2 -0 -49 -3 -4 -8 -220 -1 -15 -99 -7 -45 -7 -46 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -47 -7 -48 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -49 -7 -50 -65 -67 -49 -2 -0 -49 -3 -4 -11 -I -a -I -0 -I -0 -I -0 -n -p -51 -x -12 -test_version -M -1 -n -n -x -12 -test_version -i -8 -5 -56 -0 -47 -50 -1 -0 -11 -I -2 -I -0 -I -0 -I -0 -n -p -2 -M -1 -p -2 -x -9 -for_block -t -n -x -12 -test_version -i -29 -5 -7 -0 -13 -70 -9 -19 -15 -44 -43 -1 -7 -2 -78 -49 -3 -2 -6 -0 -45 -4 -5 -43 -6 -47 -49 -7 -2 -11 -I -5 -I -0 -I -0 -I -0 -I --2 -p -8 -n -x -6 -Regexp -s -14 -\A\d\.\d\.\d\z -x -3 -new -x -7 -CodeRay -n -x -7 -VERSION -x -12 -assert_match -p -5 -I -0 -I -7 -I -0 -I -8 -I -1d -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -assert_nothing_raised -p -5 -I -0 -I -6 -I -0 -I -7 -I -8 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -17 -method_visibility -x -15 -add_defn_method -x -14 -RUBY_TEST_CODE -s -20 -puts "Hello, World!" -x -9 -const_set -x -16 -RUBY_TEST_TOKENS -s -4 -puts -x -5 -ident -s -1 - -x -5 -space -x -4 -open -x -6 -string -s -1 -" -x -9 -delimiter -s -13 -Hello, World! -x -7 -content -x -5 -close -x -16 -test_simple_scan -M -1 -n -n -x -16 -test_simple_scan -i -8 -5 -56 -0 -47 -50 -1 -0 -11 -I -2 -I -0 -I -0 -I -0 -n -p -2 -M -1 -p -2 -x -9 -for_block -t -n -x -16 -test_simple_scan -i -23 -5 -45 -0 -1 -45 -2 -3 -45 -4 -5 -7 -6 -49 -7 -2 -49 -8 -0 -47 -49 -9 -2 -11 -I -6 -I -0 -I -0 -I -0 -I --2 -p -10 -x -16 -RUBY_TEST_TOKENS -n -x -7 -CodeRay -n -x -14 -RUBY_TEST_CODE -n -x -4 -ruby -x -4 -scan -x -6 -to_ary -x -12 -assert_equal -p -5 -I -0 -I -18 -I -0 -I -19 -I -17 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -assert_nothing_raised -p -5 -I -0 -I -17 -I -0 -I -18 -I -8 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -14 -RUBY_TEST_HTML -s -51 -puts " -s -73 -Hello, World!" -x -1 -+ -x -21 -test_simple_highlight -M -1 -n -n -x -21 -test_simple_highlight -i -8 -5 -56 -0 -47 -50 -1 -0 -11 -I -2 -I -0 -I -0 -I -0 -n -p -2 -M -1 -p -2 -x -9 -for_block -t -n -x -21 -test_simple_highlight -i -23 -5 -45 -0 -1 -45 -2 -3 -45 -4 -5 -7 -6 -49 -7 -2 -49 -8 -0 -47 -49 -9 -2 -11 -I -6 -I -0 -I -0 -I -0 -I --2 -p -10 -x -14 -RUBY_TEST_HTML -n -x -7 -CodeRay -n -x -14 -RUBY_TEST_CODE -n -x -4 -ruby -x -4 -scan -x -4 -html -x -12 -assert_equal -p -5 -I -0 -I -20 -I -0 -I -21 -I -17 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -assert_nothing_raised -p -5 -I -0 -I -1f -I -0 -I -20 -I -8 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -8 -test_duo -M -1 -n -n -x -8 -test_duo -i -66 -5 -45 -0 -1 -45 -2 -3 -43 -4 -7 -5 -7 -5 -49 -6 -2 -45 -0 -7 -49 -8 -1 -47 -49 -9 -2 -15 -5 -45 -0 -10 -45 -2 -11 -43 -4 -44 -43 -12 -79 -49 -13 -1 -13 -7 -5 -7 -5 -49 -14 -2 -15 -49 -6 -1 -45 -0 -15 -49 -8 -1 -47 -49 -9 -2 -11 -I -7 -I -0 -I -0 -I -0 -n -p -16 -x -14 -RUBY_TEST_CODE -n -x -7 -CodeRay -n -x -3 -Duo -x -5 -plain -x -2 -[] -n -x -9 -highlight -x -12 -assert_equal -n -n -x -4 -Hash -x -16 -new_from_literal -x -3 -[]= -n -p -15 -I -0 -I -25 -I -0 -I -26 -I -4 -I -27 -I -16 -I -26 -I -1b -I -28 -I -1f -I -29 -I -3d -I -28 -I -42 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -15 -test_duo_stream -M -1 -n -n -x -15 -test_duo_stream -i -42 -5 -45 -0 -1 -45 -2 -3 -43 -4 -7 -5 -7 -5 -49 -6 -2 -45 -0 -7 -44 -43 -8 -79 -49 -9 -1 -13 -7 -10 -2 -49 -11 -2 -15 -49 -12 -2 -47 -49 -13 -2 -11 -I -8 -I -0 -I -0 -I -0 -n -p -14 -x -14 -RUBY_TEST_CODE -n -x -7 -CodeRay -n -x -3 -Duo -x -5 -plain -x -2 -[] -n -x -4 -Hash -x -16 -new_from_literal -x -6 -stream -x -3 -[]= -x -9 -highlight -x -12 -assert_equal -p -9 -I -0 -I -2c -I -0 -I -2d -I -4 -I -2e -I -25 -I -2d -I -2a -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -19 -test_comment_filter -M -1 -n -n -x -19 -test_comment_filter -i -26 -5 -7 -0 -64 -45 -1 -2 -7 -3 -64 -7 -4 -49 -5 -2 -49 -6 -0 -49 -7 -0 -47 -49 -8 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -9 -s -39 -#!/usr/bin/env ruby - -code - -more code - -x -7 -CodeRay -n -s -127 -#!/usr/bin/env ruby -=begin -A multi-line comment. -=end -code -# A single-line comment. -more code # and another comment, in-line. - -x -4 -ruby -x -4 -scan -x -14 -comment_filter -x -4 -text -x -12 -assert_equal -p -5 -I -0 -I -31 -I -0 -I -32 -I -1a -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -18 -test_lines_of_code -M -1 -n -n -x -18 -test_lines_of_code -i -108 -5 -80 -45 -0 -1 -7 -2 -64 -7 -3 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -15 -7 -7 -64 -19 -0 -15 -5 -78 -45 -0 -8 -20 -0 -7 -9 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -15 -5 -78 -45 -0 -10 -20 -0 -7 -11 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -15 -5 -78 -45 -0 -12 -20 -0 -7 -13 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -15 -5 -4 -4 -45 -0 -14 -20 -0 -7 -15 -49 -4 -2 -49 -5 -0 -47 -49 -6 -2 -11 -I -6 -I -1 -I -0 -I -0 -n -p -16 -x -7 -CodeRay -n -s -127 -#!/usr/bin/env ruby -=begin -A multi-line comment. -=end -code -# A single-line comment. -more code # and another comment, in-line. - -x -4 -ruby -x -4 -scan -x -13 -lines_of_code -x -12 -assert_equal -s -514 - - - - - - <%= controller.controller_name.titleize %>: <%= controller.action_name %> - <%= stylesheet_link_tag 'scaffold' %> - - - -

    <%= flash[:notice] %>

    - -
    - <%= yield %> -
    - - - - -n -x -4 -html -n -x -3 -php -n -x -4 -yaml -n -x -5 -rhtml -p -15 -I -0 -I -43 -I -0 -I -44 -I -15 -I -4d -I -1b -I -62 -I -2f -I -63 -I -43 -I -64 -I -57 -I -65 -I -6c -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -1 -x -5 -rHTML -x -3 -ENV -n -s -14 -check_rubygems -x -2 -[] -x -12 -RUBY_VERSION -n -s -3 -1.9 -x -1 -< -x -24 -test_rubygems_not_loaded -M -1 -n -n -x -24 -test_rubygems_not_loaded -i -34 -5 -1 -26 -93 -0 -15 -29 -17 -0 -7 -0 -98 -1 -1 -30 -8 -23 -25 -92 -0 -27 -8 -28 -15 -7 -2 -8 -29 -1 -47 -49 -3 -2 -11 -I -4 -I -0 -I -0 -I -0 -n -p -4 -x -3 -Gem -x -16 -vm_const_defined -s -8 -constant -x -12 -assert_equal -p -5 -I -0 -I -68 -I -0 -I -69 -I -22 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -test_list_of_encoders -M -1 -n -n -x -21 -test_list_of_encoders -i -37 -5 -45 -0 -1 -45 -2 -3 -43 -4 -49 -5 -0 -47 -49 -6 -2 -15 -5 -45 -2 -7 -43 -4 -49 -5 -0 -7 -8 -64 -49 -9 -1 -47 -49 -10 -1 -11 -I -3 -I -0 -I -0 -I -0 -n -p -11 -x -5 -Array -n -x -7 -CodeRay -n -x -8 -Encoders -x -4 -list -x -14 -assert_kind_of -n -s -5 -count -x -8 -include? -x -6 -assert -p -7 -I -0 -I -6c -I -0 -I -6d -I -11 -I -6e -I -25 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -21 -test_list_of_scanners -M -1 -n -n -x -21 -test_list_of_scanners -i -37 -5 -45 -0 -1 -45 -2 -3 -43 -4 -49 -5 -0 -47 -49 -6 -2 -15 -5 -45 -2 -7 -43 -4 -49 -5 -0 -7 -8 -64 -49 -9 -1 -47 -49 -10 -1 -11 -I -3 -I -0 -I -0 -I -0 -n -p -11 -x -5 -Array -n -x -7 -CodeRay -n -x -8 -Scanners -x -4 -list -x -14 -assert_kind_of -n -s -9 -plaintext -x -8 -include? -x -6 -assert -p -7 -I -0 -I -71 -I -0 -I -72 -I -11 -I -73 -I -25 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -25 -test_scan_a_frozen_string -M -1 -n -n -x -25 -test_scan_a_frozen_string -i -12 -45 -0 -1 -45 -2 -3 -7 -4 -49 -5 -2 -11 -I -3 -I -0 -I -0 -I -0 -n -p -6 -x -7 -CodeRay -n -x -12 -RUBY_VERSION -n -x -4 -ruby -x -4 -scan -p -5 -I -0 -I -76 -I -0 -I -77 -I -c -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -p -51 -I -2 -I -6 -I -10 -I -c -I -1a -I -e -I -1d -I -f -I -24 -I -10 -I -2b -I -11 -I -31 -I -12 -I -38 -I -13 -I -3f -I -14 -I -46 -I -15 -I -52 -I -17 -I -60 -I -1d -I -63 -I -1d -I -66 -I -1e -I -6f -I -1f -I -7d -I -25 -I -8b -I -2c -I -99 -I -31 -I -a7 -I -43 -I -b5 -I -6a -I -cc -I -68 -I -db -I -6a -I -dd -I -6c -I -eb -I -71 -I -f9 -I -76 -I -107 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 -x -13 -attach_method -p -7 -I -0 -I -1 -I -9 -I -2 -I -12 -I -4 -I -35 -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/basic.rb -p -0 diff --git a/vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rb b/vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rb deleted file mode 100644 index efd05782..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rb +++ /dev/null @@ -1,77 +0,0 @@ -require 'test/unit' -$:.unshift 'lib' -require 'coderay' - -begin - require 'rubygems' unless defined? Gem - gem 'RedCloth', '>= 4.0.3' rescue nil - require 'redcloth' -rescue LoadError - warn 'RedCloth not found - skipping for_redcloth tests.' -end - -class BasicTest < Test::Unit::TestCase - - def test_for_redcloth - require 'coderay/for_redcloth' - assert_equal "

    puts "Hello, World!"

    ", - RedCloth.new('@[ruby]puts "Hello, World!"@').to_html - assert_equal <<-BLOCKCODE.chomp, -
    -
    puts "Hello, World!"
    -
    - BLOCKCODE - RedCloth.new('bc[ruby]. puts "Hello, World!"').to_html - end - - def test_for_redcloth_no_lang - require 'coderay/for_redcloth' - assert_equal "

    puts \"Hello, World!\"

    ", - RedCloth.new('@puts "Hello, World!"@').to_html - assert_equal <<-BLOCKCODE.chomp, -
    puts \"Hello, World!\"
    - BLOCKCODE - RedCloth.new('bc. puts "Hello, World!"').to_html - end - - def test_for_redcloth_style - require 'coderay/for_redcloth' - assert_equal <<-BLOCKCODE.chomp, -
    puts \"Hello, World!\"
    - BLOCKCODE - RedCloth.new('bc{color: red}. puts "Hello, World!"').to_html - end - - def test_for_redcloth_escapes - require 'coderay/for_redcloth' - assert_equal '

    >

    ', - RedCloth.new('@[ruby]>@').to_html - assert_equal <<-BLOCKCODE.chomp, -
    -
    &
    -
    - BLOCKCODE - RedCloth.new('bc[ruby]. &').to_html - end - - def test_for_redcloth_escapes2 - require 'coderay/for_redcloth' - assert_equal "

    #include <test.h>

    ", - RedCloth.new('@[c]#include @').to_html - end - - # See http://jgarber.lighthouseapp.com/projects/13054/tickets/124-code-markup-does-not-allow-brackets. - def test_for_redcloth_false_positive - require 'coderay/for_redcloth' - assert_equal '

    [project]_dff.skjd

    ', - RedCloth.new('@[project]_dff.skjd@').to_html - # false positive, but expected behavior / known issue - assert_equal "

    _dff.skjd

    ", - RedCloth.new('@[ruby]_dff.skjd@').to_html - assert_equal <<-BLOCKCODE.chomp, -
    [project]_dff.skjd
    - BLOCKCODE - RedCloth.new('bc. [project]_dff.skjd').to_html - end - -end if defined? RedCloth \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rbc b/vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rbc deleted file mode 100644 index 09a7fc84..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/for_redcloth.rbc +++ /dev/null @@ -1,1708 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -249 -5 -7 -0 -64 -47 -49 -1 -1 -15 -99 -43 -2 -7 -3 -49 -4 -1 -7 -5 -64 -49 -6 -1 -15 -5 -7 -7 -64 -47 -49 -1 -1 -15 -26 -93 -0 -15 -29 -144 -0 -26 -93 -1 -15 -29 -55 -0 -7 -8 -98 -9 -1 -30 -8 -61 -25 -92 -1 -27 -8 -66 -15 -7 -10 -8 -67 -1 -9 -72 -1 -8 -80 -5 -7 -11 -64 -47 -49 -1 -1 -15 -26 -93 -2 -15 -29 -102 -0 -5 -7 -12 -64 -7 -13 -64 -47 -49 -14 -2 -30 -8 -129 -26 -93 -3 -15 -24 -13 -45 -15 -16 -12 -49 -17 -1 -10 -119 -8 -124 -15 -1 -25 -8 -129 -15 -92 -3 -27 -34 -92 -2 -27 -15 -5 -7 -18 -64 -47 -49 -1 -1 -30 -8 -178 -26 -93 -4 -15 -24 -13 -45 -19 -20 -12 -49 -17 -1 -10 -161 -8 -173 -15 -5 -7 -21 -64 -47 -49 -22 -1 -25 -8 -178 -15 -92 -4 -27 -34 -92 -0 -27 -15 -26 -93 -5 -15 -29 -197 -0 -7 -23 -98 -9 -1 -30 -8 -203 -25 -92 -5 -27 -8 -208 -15 -7 -10 -8 -209 -1 -9 -245 -99 -7 -24 -45 -25 -26 -43 -27 -43 -28 -65 -49 -29 -3 -13 -99 -12 -7 -30 -12 -7 -31 -12 -65 -12 -49 -32 -4 -15 -49 -30 -0 -8 -246 -1 -15 -2 -11 -I -c -I -0 -I -0 -I -0 -n -p -33 -s -9 -test/unit -x -7 -require -x -7 -Globals -x -2 -$: -x -2 -[] -s -3 -lib -x -2 -<< -s -7 -coderay -x -3 -Gem -x -16 -vm_const_defined -s -8 -constant -s -8 -rubygems -s -8 -RedCloth -s -8 ->= 4.0.3 -x -3 -gem -x -13 -StandardError -n -x -3 -=== -s -8 -redcloth -x -9 -LoadError -n -s -49 -RedCloth not found - skipping for_redcloth tests. -x -4 -warn -x -8 -RedCloth -x -9 -BasicTest -x -4 -Test -n -x -4 -Unit -x -8 -TestCase -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -9 -BasicTest -i -86 -5 -66 -99 -7 -0 -7 -1 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -4 -7 -5 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -6 -7 -7 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -8 -7 -9 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -10 -7 -11 -65 -67 -49 -2 -0 -49 -3 -4 -15 -99 -7 -12 -7 -13 -65 -67 -49 -2 -0 -49 -3 -4 -11 -I -5 -I -0 -I -0 -I -0 -n -p -14 -x -17 -test_for_redcloth -M -1 -n -n -x -17 -test_for_redcloth -i -96 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -11 -64 -49 -12 -0 -45 -3 -13 -13 -71 -5 -47 -9 -82 -47 -49 -6 -0 -13 -7 -14 -64 -47 -49 -8 -1 -15 -8 -88 -7 -14 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -15 -s -20 -coderay/for_redcloth -x -7 -require -s -221 -

    puts "Hello, World!"

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -28 -@[ruby]puts "Hello, World!"@ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -s -252 -
    -
    puts "Hello, World!"
    -
    - -x -5 -chomp -n -s -30 -bc[ruby]. puts "Hello, World!" -p -17 -I -0 -I -f -I -0 -I -10 -I -9 -I -11 -I -d -I -12 -I -2e -I -11 -I -33 -I -13 -I -3a -I -18 -I -5b -I -13 -I -60 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -17 -method_visibility -x -15 -add_defn_method -x -25 -test_for_redcloth_no_lang -M -1 -n -n -x -25 -test_for_redcloth_no_lang -i -96 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -11 -64 -49 -12 -0 -45 -3 -13 -13 -71 -5 -47 -9 -82 -47 -49 -6 -0 -13 -7 -14 -64 -47 -49 -8 -1 -15 -8 -88 -7 -14 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -15 -s -20 -coderay/for_redcloth -x -7 -require -s -40 -

    puts "Hello, World!"

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -22 -@puts "Hello, World!"@ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -s -45 -
    puts "Hello, World!"
    - -x -5 -chomp -n -s -24 -bc. puts "Hello, World!" -p -17 -I -0 -I -1b -I -0 -I -1c -I -9 -I -1d -I -d -I -1e -I -2e -I -1d -I -33 -I -1f -I -3a -I -22 -I -5b -I -1f -I -60 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -23 -test_for_redcloth_style -M -1 -n -n -x -23 -test_for_redcloth_style -i -54 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -49 -3 -0 -45 -4 -5 -13 -71 -6 -47 -9 -40 -47 -49 -7 -0 -13 -7 -8 -64 -47 -49 -9 -1 -15 -8 -46 -7 -8 -64 -49 -6 -1 -49 -10 -0 -47 -49 -11 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -12 -s -20 -coderay/for_redcloth -x -7 -require -s -85 -
    puts "Hello, World!"
    - -x -5 -chomp -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -36 -bc{color: red}. puts "Hello, World!" -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -p -11 -I -0 -I -25 -I -0 -I -26 -I -9 -I -27 -I -10 -I -2a -I -31 -I -27 -I -36 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -25 -test_for_redcloth_escapes -M -1 -n -n -x -25 -test_for_redcloth_escapes -i -96 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -11 -64 -49 -12 -0 -45 -3 -13 -13 -71 -5 -47 -9 -82 -47 -49 -6 -0 -13 -7 -14 -64 -47 -49 -8 -1 -15 -8 -88 -7 -14 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -15 -s -20 -coderay/for_redcloth -x -7 -require -s -52 -

    >

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -9 -@[ruby]>@ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -s -84 -
    -
    &
    -
    - -x -5 -chomp -n -s -11 -bc[ruby]. & -p -17 -I -0 -I -2d -I -0 -I -2e -I -9 -I -2f -I -d -I -30 -I -2e -I -2f -I -33 -I -31 -I -3a -I -36 -I -5b -I -31 -I -60 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -26 -test_for_redcloth_escapes2 -M -1 -n -n -x -26 -test_for_redcloth_escapes2 -i -51 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -11 -s -20 -coderay/for_redcloth -x -7 -require -s -149 -

    #include <test.h>

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -22 -@[c]#include @ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -p -11 -I -0 -I -39 -I -0 -I -3a -I -9 -I -3b -I -d -I -3c -I -2e -I -3b -I -33 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -32 -test_for_redcloth_false_positive -M -1 -n -n -x -32 -test_for_redcloth_false_positive -i -138 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -45 -3 -4 -13 -71 -5 -47 -9 -37 -47 -49 -6 -0 -13 -7 -7 -64 -47 -49 -8 -1 -15 -8 -43 -7 -7 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -11 -64 -45 -3 -12 -13 -71 -5 -47 -9 -79 -47 -49 -6 -0 -13 -7 -13 -64 -47 -49 -8 -1 -15 -8 -85 -7 -13 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -15 -5 -7 -14 -64 -49 -15 -0 -45 -3 -16 -13 -71 -5 -47 -9 -124 -47 -49 -6 -0 -13 -7 -17 -64 -47 -49 -8 -1 -15 -8 -130 -7 -17 -64 -49 -5 -1 -49 -9 -0 -47 -49 -10 -2 -11 -I -5 -I -0 -I -0 -I -0 -n -p -18 -s -20 -coderay/for_redcloth -x -7 -require -s -38 -

    [project]_dff.skjd

    -x -8 -RedCloth -n -x -3 -new -x -8 -allocate -s -20 -@[project]_dff.skjd@ -x -10 -initialize -x -7 -to_html -x -12 -assert_equal -s -57 -

    _dff.skjd

    -n -s -17 -@[ruby]_dff.skjd@ -s -43 -
    [project]_dff.skjd
    - -x -5 -chomp -n -s -22 -bc. [project]_dff.skjd -p -23 -I -0 -I -40 -I -0 -I -41 -I -9 -I -42 -I -d -I -43 -I -2e -I -42 -I -33 -I -45 -I -37 -I -46 -I -58 -I -45 -I -5d -I -47 -I -64 -I -4a -I -85 -I -47 -I -8a -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -p -13 -I -2 -I -f -I -10 -I -1b -I -1e -I -25 -I -2c -I -2d -I -3a -I -39 -I -48 -I -40 -I -56 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 -x -13 -attach_method -p -23 -I -0 -I -1 -I -9 -I -2 -I -18 -I -3 -I -21 -I -6 -I -51 -I -7 -I -85 -I -8 -I -95 -I -9 -I -a2 -I -a -I -b6 -I -4d -I -d3 -I -d -I -f5 -I -4d -I -f9 -x -62 -/Users/murphy/ruby/coderay-0.9/test/functional/for_redcloth.rb -p -0 diff --git a/vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rb b/vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rb deleted file mode 100644 index 25bbc93a..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'test/unit' -require 'coderay' - -class PluginScannerTest < Test::Unit::TestCase - - def test_load - require File.join(File.dirname(__FILE__), 'vhdl') - assert_equal 'VHDL', CodeRay.scanner(:vhdl).class.name - end - -end diff --git a/vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rbc b/vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rbc deleted file mode 100644 index ef61d340..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/load_plugin_scanner.rbc +++ /dev/null @@ -1,317 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -53 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -47 -49 -1 -1 -15 -99 -7 -3 -45 -4 -5 -43 -6 -43 -7 -65 -49 -8 -3 -13 -99 -12 -7 -9 -12 -7 -10 -12 -65 -12 -49 -11 -4 -15 -49 -9 -0 -15 -2 -11 -I -6 -I -0 -I -0 -I -0 -n -p -12 -s -9 -test/unit -x -7 -require -s -7 -coderay -x -17 -PluginScannerTest -x -4 -Test -n -x -4 -Unit -x -8 -TestCase -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -17 -PluginScannerTest -i -16 -5 -66 -99 -7 -0 -7 -1 -65 -67 -49 -2 -0 -49 -3 -4 -11 -I -5 -I -0 -I -0 -I -0 -n -p -4 -x -9 -test_load -M -1 -n -n -x -9 -test_load -i -48 -5 -45 -0 -1 -45 -0 -2 -65 -49 -3 -0 -49 -4 -1 -7 -5 -64 -49 -6 -2 -47 -49 -7 -1 -15 -5 -7 -8 -64 -45 -9 -10 -7 -11 -49 -12 -1 -49 -13 -0 -49 -14 -0 -47 -49 -15 -2 -11 -I -4 -I -0 -I -0 -I -0 -n -p -16 -x -4 -File -n -n -x -11 -active_path -x -7 -dirname -s -4 -vhdl -x -4 -join -x -7 -require -s -4 -VHDL -x -7 -CodeRay -n -x -4 -vhdl -x -7 -scanner -x -5 -class -x -4 -name -x -12 -assert_equal -p -7 -I -0 -I -6 -I -0 -I -7 -I -19 -I -8 -I -30 -x -69 -/Users/murphy/ruby/coderay-0.9/test/functional/load_plugin_scanner.rb -p -0 -x -17 -method_visibility -x -15 -add_defn_method -p -3 -I -2 -I -6 -I -10 -x -69 -/Users/murphy/ruby/coderay-0.9/test/functional/load_plugin_scanner.rb -p -0 -x -13 -attach_method -p -7 -I -0 -I -1 -I -9 -I -2 -I -12 -I -4 -I -35 -x -69 -/Users/murphy/ruby/coderay-0.9/test/functional/load_plugin_scanner.rb -p -0 diff --git a/vendor/gems/coderay-0.9.7/test/functional/suite.rb b/vendor/gems/coderay-0.9.7/test/functional/suite.rb deleted file mode 100644 index 97dd330d..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/suite.rb +++ /dev/null @@ -1,12 +0,0 @@ -require 'test/unit' - -MYDIR = File.dirname(__FILE__) - -$:.unshift 'lib' -require 'coderay' -puts "Running basic CodeRay #{CodeRay::VERSION} tests..." - -suite = %w(basic load_plugin_scanner word_list) -for test_case in suite - load File.join(MYDIR, test_case + '.rb') -end diff --git a/vendor/gems/coderay-0.9.7/test/functional/suite.rbc b/vendor/gems/coderay-0.9.7/test/functional/suite.rbc deleted file mode 100644 index 977354ae..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/suite.rbc +++ /dev/null @@ -1,322 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -95 -5 -7 -0 -64 -47 -49 -1 -1 -15 -65 -7 -2 -45 -3 -4 -65 -49 -5 -0 -49 -6 -1 -49 -7 -2 -15 -99 -43 -8 -7 -9 -49 -10 -1 -7 -11 -64 -49 -12 -1 -15 -5 -7 -13 -64 -47 -49 -1 -1 -15 -5 -7 -14 -45 -15 -16 -43 -17 -47 -49 -18 -0 -7 -19 -63 -3 -47 -49 -20 -1 -15 -7 -21 -64 -7 -22 -64 -7 -23 -64 -35 -3 -19 -0 -15 -20 -0 -56 -24 -50 -25 -0 -15 -2 -11 -I -6 -I -2 -I -0 -I -0 -n -p -26 -s -9 -test/unit -x -7 -require -x -5 -MYDIR -x -4 -File -n -x -11 -active_path -x -7 -dirname -x -9 -const_set -x -7 -Globals -x -2 -$: -x -2 -[] -s -3 -lib -x -2 -<< -s -7 -coderay -s -22 -Running basic CodeRay -x -7 -CodeRay -n -x -7 -VERSION -x -4 -to_s -s -9 - tests... -x -4 -puts -s -5 -basic -s -19 -load_plugin_scanner -s -9 -word_list -M -1 -p -2 -x -9 -for_block -t -n -x -9 -__block__ -i -28 -57 -22 -1 -1 -15 -5 -45 -0 -1 -45 -2 -3 -21 -1 -1 -7 -4 -64 -81 -5 -49 -6 -2 -47 -49 -7 -1 -11 -I -6 -I -0 -I -1 -I -1 -n -p -8 -x -4 -File -n -x -5 -MYDIR -n -s -3 -.rb -x -1 -+ -x -4 -join -x -4 -load -p -5 -I -0 -I -a -I -5 -I -b -I -1c -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/suite.rb -p -0 -x -4 -each -p -15 -I -0 -I -1 -I -9 -I -3 -I -1a -I -5 -I -29 -I -6 -I -32 -I -7 -I -47 -I -9 -I -55 -I -a -I -5f -x -55 -/Users/murphy/ruby/coderay-0.9/test/functional/suite.rb -p -2 -x -5 -suite -x -9 -test_case diff --git a/vendor/gems/coderay-0.9.7/test/functional/vhdl.rb b/vendor/gems/coderay-0.9.7/test/functional/vhdl.rb deleted file mode 100644 index c7e38243..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/vhdl.rb +++ /dev/null @@ -1,126 +0,0 @@ -class VHDL < CodeRay::Scanners::Scanner - - register_for :vhdl - - RESERVED_WORDS = [ - 'access','after','alias','all','assert','architecture','begin', - 'block','body','buffer','bus','case','component','configuration','constant', - 'disconnect','downto','else','elsif','end','entity','exit','file','for', - 'function','generate','generic','group','guarded','if','impure','in', - 'inertial','inout','is','label','library','linkage','literal','loop', - 'map','new','next','null','of','on','open','others','out','package', - 'port','postponed','procedure','process','pure','range','record','register', - 'reject','report','return','select','severity','signal','shared','subtype', - 'then','to','transport','type','unaffected','units','until','use','variable', - 'wait','when','while','with','note','warning','error','failure','and', - 'or','xor','not','nor', - 'array' - ] - - PREDEFINED_TYPES = [ - 'bit','bit_vector','character','boolean','integer','real','time','string', - 'severity_level','positive','natural','signed','unsigned','line','text', - 'std_logic','std_logic_vector','std_ulogic','std_ulogic_vector','qsim_state', - 'qsim_state_vector','qsim_12state','qsim_12state_vector','qsim_strength', - 'mux_bit','mux_vector','reg_bit','reg_vector','wor_bit','wor_vector' - ] - - PREDEFINED_CONSTANTS = [ - - ] - - IDENT_KIND = CodeRay::CaseIgnoringWordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(PREDEFINED_CONSTANTS, :pre_constant) - - ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x - UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x - - def scan_tokens tokens, options - - state = :initial - - until eos? - - kind = nil - match = nil - - case state - - when :initial - - if scan(/ \s+ | \\\n /x) - kind = :space - - elsif scan(/-- .*/x) - kind = :comment - - elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) /x) - kind = :operator - - elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x) - kind = IDENT_KIND[match.downcase] - - elsif match = scan(/[a-z]?"/i) - tokens << [:open, :string] - state = :string - kind = :delimiter - - elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox) - kind = :char - - elsif scan(/(?:\d+)(?![.eEfF])/) - kind = :integer - - elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/) - kind = :float - - else - getch - kind = :error - - end - - when :string - if scan(/[^\\\n"]+/) - kind = :content - elsif scan(/"/) - tokens << ['"', :delimiter] - tokens << [:close, :string] - state = :initial - next - elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) - kind = :char - elsif scan(/ \\ | $ /x) - tokens << [:close, :string] - kind = :error - state = :initial - else - raise_inspect "else case \" reached; %p not handled." % peek(1), tokens - end - - else - raise_inspect 'Unknown state', tokens - - end - - match ||= matched - if $DEBUG and not kind - raise_inspect 'Error token %p in line %d' % - [[match, kind], line], tokens - end - raise_inspect 'Empty token', tokens unless match - - tokens << [match, kind] - - end - - if state == :string - tokens << [:close, :string] - end - - tokens - end - -end diff --git a/vendor/gems/coderay-0.9.7/test/functional/vhdl.rbc b/vendor/gems/coderay-0.9.7/test/functional/vhdl.rbc deleted file mode 100644 index 80d01bf6..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/vhdl.rbc +++ /dev/null @@ -1,2334 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -35 -99 -7 -0 -45 -1 -2 -43 -3 -43 -4 -65 -49 -5 -3 -13 -99 -12 -7 -6 -12 -7 -7 -12 -65 -12 -49 -8 -4 -15 -49 -6 -0 -15 -2 -11 -I -6 -I -0 -I -0 -I -0 -n -p -9 -x -4 -VHDL -x -7 -CodeRay -n -x -8 -Scanners -x -7 -Scanner -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -4 -VHDL -i -519 -5 -66 -5 -7 -0 -47 -49 -1 -1 -15 -65 -7 -2 -7 -3 -64 -7 -4 -64 -7 -5 -64 -7 -6 -64 -7 -7 -64 -7 -8 -64 -7 -9 -64 -7 -10 -64 -7 -11 -64 -7 -12 -64 -7 -13 -64 -7 -14 -64 -7 -15 -64 -7 -16 -64 -7 -17 -64 -7 -18 -64 -7 -19 -64 -7 -20 -64 -7 -21 -64 -7 -22 -64 -7 -23 -64 -7 -24 -64 -7 -25 -64 -7 -26 -64 -7 -27 -64 -7 -28 -64 -7 -29 -64 -7 -30 -64 -7 -31 -64 -7 -32 -64 -7 -33 -64 -7 -34 -64 -7 -35 -64 -7 -36 -64 -7 -37 -64 -7 -38 -64 -7 -39 -64 -7 -40 -64 -7 -41 -64 -7 -42 -64 -7 -43 -64 -7 -44 -64 -7 -45 -64 -7 -46 -64 -7 -47 -64 -7 -48 -64 -7 -49 -64 -7 -50 -64 -7 -51 -64 -7 -52 -64 -7 -53 -64 -7 -54 -64 -7 -55 -64 -7 -56 -64 -7 -57 -64 -7 -58 -64 -7 -59 -64 -7 -60 -64 -7 -61 -64 -7 -62 -64 -7 -63 -64 -7 -64 -64 -7 -65 -64 -7 -66 -64 -7 -67 -64 -7 -68 -64 -7 -69 -64 -7 -70 -64 -7 -71 -64 -7 -72 -64 -7 -73 -64 -7 -74 -64 -7 -75 -64 -7 -76 -64 -7 -77 -64 -7 -78 -64 -7 -79 -64 -7 -80 -64 -7 -81 -64 -7 -82 -64 -7 -83 -64 -7 -84 -64 -7 -85 -64 -7 -86 -64 -7 -87 -64 -7 -88 -64 -7 -89 -64 -7 -90 -64 -7 -91 -64 -35 -89 -49 -92 -2 -15 -65 -7 -93 -7 -94 -64 -7 -95 -64 -7 -96 -64 -7 -97 -64 -7 -98 -64 -7 -99 -64 -7 -100 -64 -7 -101 -64 -7 -102 -64 -7 -103 -64 -7 -104 -64 -7 -105 -64 -7 -106 -64 -7 -107 -64 -7 -108 -64 -7 -109 -64 -7 -110 -64 -7 -111 -64 -7 -112 -64 -7 -113 -64 -7 -114 -64 -7 -115 -64 -7 -116 -64 -7 -117 -64 -7 -118 -64 -7 -119 -64 -7 -120 -64 -7 -121 -64 -7 -122 -64 -7 -123 -64 -35 -30 -49 -92 -2 -15 -65 -7 -124 -35 -0 -49 -92 -2 -15 -65 -7 -125 -45 -126 -127 -43 -128 -13 -71 -129 -47 -9 -422 -47 -49 -130 -0 -13 -7 -131 -47 -49 -132 -1 -15 -8 -427 -7 -131 -49 -129 -1 -45 -2 -133 -7 -134 -49 -135 -2 -45 -93 -136 -7 -137 -49 -135 -2 -45 -124 -138 -7 -139 -49 -135 -2 -49 -92 -2 -15 -65 -7 -140 -7 -141 -13 -70 -9 -476 -15 -44 -43 -142 -7 -143 -80 -49 -129 -2 -6 -141 -49 -92 -2 -15 -65 -7 -144 -7 -145 -13 -70 -9 -501 -15 -44 -43 -142 -7 -146 -80 -49 -129 -2 -6 -145 -49 -92 -2 -15 -99 -7 -147 -7 -148 -65 -67 -49 -149 -0 -49 -150 -4 -11 -I -5b -I -0 -I -0 -I -0 -n -p -151 -x -4 -vhdl -x -12 -register_for -x -14 -RESERVED_WORDS -s -6 -access -s -5 -after -s -5 -alias -s -3 -all -s -6 -assert -s -12 -architecture -s -5 -begin -s -5 -block -s -4 -body -s -6 -buffer -s -3 -bus -s -4 -case -s -9 -component -s -13 -configuration -s -8 -constant -s -10 -disconnect -s -6 -downto -s -4 -else -s -5 -elsif -s -3 -end -s -6 -entity -s -4 -exit -s -4 -file -s -3 -for -s -8 -function -s -8 -generate -s -7 -generic -s -5 -group -s -7 -guarded -s -2 -if -s -6 -impure -s -2 -in -s -8 -inertial -s -5 -inout -s -2 -is -s -5 -label -s -7 -library -s -7 -linkage -s -7 -literal -s -4 -loop -s -3 -map -s -3 -new -s -4 -next -s -4 -null -s -2 -of -s -2 -on -s -4 -open -s -6 -others -s -3 -out -s -7 -package -s -4 -port -s -9 -postponed -s -9 -procedure -s -7 -process -s -4 -pure -s -5 -range -s -6 -record -s -8 -register -s -6 -reject -s -6 -report -s -6 -return -s -6 -select -s -8 -severity -s -6 -signal -s -6 -shared -s -7 -subtype -s -4 -then -s -2 -to -s -9 -transport -s -4 -type -s -10 -unaffected -s -5 -units -s -5 -until -s -3 -use -s -8 -variable -s -4 -wait -s -4 -when -s -5 -while -s -4 -with -s -4 -note -s -7 -warning -s -5 -error -s -7 -failure -s -3 -and -s -2 -or -s -3 -xor -s -3 -not -s -3 -nor -s -5 -array -x -9 -const_set -x -16 -PREDEFINED_TYPES -s -3 -bit -s -10 -bit_vector -s -9 -character -s -7 -boolean -s -7 -integer -s -4 -real -s -4 -time -s -6 -string -s -14 -severity_level -s -8 -positive -s -7 -natural -s -6 -signed -s -8 -unsigned -s -4 -line -s -4 -text -s -9 -std_logic -s -16 -std_logic_vector -s -10 -std_ulogic -s -17 -std_ulogic_vector -s -10 -qsim_state -s -17 -qsim_state_vector -s -12 -qsim_12state -s -19 -qsim_12state_vector -s -13 -qsim_strength -s -7 -mux_bit -s -10 -mux_vector -s -7 -reg_bit -s -10 -reg_vector -s -7 -wor_bit -s -10 -wor_vector -x -20 -PREDEFINED_CONSTANTS -x -10 -IDENT_KIND -x -7 -CodeRay -n -x -20 -CaseIgnoringWordList -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -n -x -8 -reserved -x -3 -add -n -x -8 -pre_type -n -x -12 -pre_constant -x -6 -ESCAPE -n -x -6 -Regexp -s -49 - [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} -x -14 -UNICODE_ESCAPE -n -s -35 - u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} -x -11 -scan_tokens -M -1 -n -n -x -11 -scan_tokens -i -688 -7 -0 -19 -2 -15 -5 -47 -49 -1 -0 -10 -660 -1 -19 -3 -15 -1 -19 -4 -15 -20 -2 -13 -7 -0 -12 -49 -2 -1 -9 -331 -15 -5 -7 -3 -13 -70 -9 -51 -15 -44 -43 -4 -7 -5 -80 -49 -6 -2 -6 -3 -47 -49 -7 -1 -9 -63 -7 -8 -19 -3 -8 -329 -5 -7 -9 -13 -70 -9 -82 -15 -44 -43 -4 -7 -10 -80 -49 -6 -2 -6 -9 -47 -49 -7 -1 -9 -94 -7 -11 -19 -3 -8 -329 -5 -7 -12 -13 -70 -9 -113 -15 -44 -43 -4 -7 -13 -80 -49 -6 -2 -6 -12 -47 -49 -7 -1 -9 -125 -7 -14 -19 -3 -8 -329 -5 -7 -15 -13 -70 -9 -144 -15 -44 -43 -4 -7 -16 -80 -49 -6 -2 -6 -15 -47 -49 -7 -1 -19 -4 -9 -167 -45 -17 -18 -20 -4 -49 -19 -0 -49 -20 -1 -19 -3 -8 -329 -5 -7 -21 -13 -70 -9 -186 -15 -44 -43 -4 -7 -22 -79 -49 -6 -2 -6 -21 -47 -49 -7 -1 -19 -4 -9 -217 -20 -0 -7 -23 -7 -24 -35 -2 -49 -25 -1 -15 -7 -24 -19 -2 -15 -7 -26 -19 -3 -8 -329 -5 -7 -27 -13 -70 -9 -247 -15 -44 -43 -4 -7 -28 -45 -29 -30 -47 -49 -31 -0 -7 -32 -63 -3 -80 -49 -6 -2 -6 -27 -47 -49 -7 -1 -9 -259 -7 -33 -19 -3 -8 -329 -5 -7 -34 -13 -70 -9 -278 -15 -44 -43 -4 -7 -35 -78 -49 -6 -2 -6 -34 -47 -49 -7 -1 -9 -290 -7 -36 -19 -3 -8 -329 -5 -7 -37 -13 -70 -9 -309 -15 -44 -43 -4 -7 -38 -78 -49 -6 -2 -6 -37 -47 -49 -7 -1 -9 -321 -7 -39 -19 -3 -8 -329 -5 -48 -40 -15 -7 -41 -19 -3 -8 -564 -13 -7 -24 -12 -49 -2 -1 -9 -553 -15 -5 -7 -42 -13 -70 -9 -360 -15 -44 -43 -4 -7 -43 -78 -49 -6 -2 -6 -42 -47 -49 -7 -1 -9 -372 -7 -44 -19 -3 -8 -551 -5 -7 -45 -13 -70 -9 -391 -15 -44 -43 -4 -7 -46 -78 -49 -6 -2 -6 -45 -47 -49 -7 -1 -9 -432 -20 -0 -7 -46 -64 -7 -26 -35 -2 -49 -25 -1 -15 -20 -0 -7 -47 -7 -24 -35 -2 -49 -25 -1 -15 -7 -0 -19 -2 -15 -1 -8 -656 -8 -551 -5 -7 -48 -13 -70 -9 -472 -15 -44 -43 -4 -7 -49 -45 -29 -50 -47 -49 -31 -0 -7 -51 -45 -52 -53 -47 -49 -31 -0 -7 -54 -63 -5 -4 -6 -49 -6 -2 -6 -48 -47 -49 -7 -1 -9 -484 -7 -33 -19 -3 -8 -551 -5 -7 -55 -13 -70 -9 -503 -15 -44 -43 -4 -7 -56 -80 -49 -6 -2 -6 -55 -47 -49 -7 -1 -9 -532 -20 -0 -7 -47 -7 -24 -35 -2 -49 -25 -1 -15 -7 -41 -19 -3 -15 -7 -0 -19 -2 -8 -551 -5 -7 -57 -64 -5 -79 -47 -49 -58 -1 -49 -59 -1 -20 -0 -47 -49 -60 -2 -8 -564 -15 -5 -7 -61 -64 -20 -0 -47 -49 -60 -2 -15 -20 -4 -13 -10 -576 -15 -5 -48 -62 -19 -4 -15 -99 -43 -63 -7 -64 -49 -20 -1 -13 -9 -597 -15 -20 -3 -10 -596 -2 -8 -597 -3 -9 -625 -5 -7 -65 -64 -20 -4 -20 -3 -35 -2 -5 -48 -66 -35 -2 -49 -59 -1 -20 -0 -47 -49 -60 -2 -8 -626 -1 -15 -20 -4 -9 -634 -1 -8 -644 -5 -7 -67 -64 -20 -0 -47 -49 -60 -2 -15 -20 -0 -20 -4 -20 -3 -35 -2 -49 -25 -1 -15 -68 -8 -5 -1 -15 -20 -2 -7 -24 -83 -68 -9 -683 -20 -0 -7 -47 -7 -24 -35 -2 -49 -25 -1 -8 -684 -1 -15 -20 -0 -11 -I -c -I -5 -I -2 -I -2 -n -p -69 -x -7 -initial -x -4 -eos? -x -3 -=== -n -x -6 -Regexp -s -12 - \s+ | \\\n -x -3 -new -x -4 -scan -x -5 -space -n -s -5 --- .* -x -7 -comment -n -s -42 - [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) -x -8 -operator -n -s -24 - [A-Za-z_][A-Za-z_0-9]* -x -10 -IDENT_KIND -n -x -8 -downcase -x -2 -[] -n -s -7 -[a-z]?" -x -4 -open -x -6 -string -x -2 -<< -x -9 -delimiter -n -s -24 - L?' (?: [^\'\n\\] | \\ -x -6 -ESCAPE -n -x -4 -to_s -s -7 - )? '? -x -4 -char -n -s -18 -(?:\d+)(?![.eEfF]) -x -7 -integer -n -s -59 -\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]? -x -5 -float -x -5 -getch -x -5 -error -n -s -9 -[^\\\n"]+ -x -7 -content -n -s -1 -" -x -5 -close -n -s -8 - \\ (?: -n -s -3 - | -x -14 -UNICODE_ESCAPE -n -s -3 - ) -n -s -8 - \\ | $ -s -36 -else case " reached; %p not handled. -x -4 -peek -x -1 -% -x -13 -raise_inspect -s -13 -Unknown state -x -7 -matched -x -7 -Globals -x -6 -$DEBUG -s -25 -Error token %p in line %d -x -4 -line -s -11 -Empty token -x -2 -== -p -111 -I -0 -I -28 -I -0 -I -2a -I -5 -I -2c -I -c -I -2e -I -10 -I -2f -I -14 -I -31 -I -17 -I -33 -I -20 -I -35 -I -39 -I -36 -I -3f -I -38 -I -58 -I -39 -I -5e -I -3b -I -77 -I -3c -I -7d -I -3e -I -98 -I -3f -I -a7 -I -41 -I -c2 -I -42 -I -ce -I -43 -I -d3 -I -44 -I -d9 -I -46 -I -fd -I -47 -I -103 -I -49 -I -11c -I -4a -I -122 -I -4c -I -13b -I -4d -I -141 -I -50 -I -145 -I -51 -I -14c -I -55 -I -155 -I -56 -I -16e -I -57 -I -174 -I -58 -I -18d -I -59 -I -19a -I -5a -I -1a6 -I -5b -I -1ab -I -5c -I -1b0 -I -5d -I -1de -I -5e -I -1e4 -I -5f -I -1fd -I -60 -I -209 -I -61 -I -20e -I -62 -I -214 -I -64 -I -22a -I -68 -I -235 -I -6c -I -241 -I -6d -I -257 -I -6f -I -258 -I -6e -I -25b -I -6f -I -271 -I -6d -I -273 -I -71 -I -285 -I -73 -I -296 -I -77 -I -29e -I -78 -I -2ab -I -77 -I -2ad -I -7b -I -2b0 -x -54 -/Users/murphy/ruby/coderay-0.9/test/functional/vhdl.rb -p -5 -x -6 -tokens -x -7 -options -x -5 -state -x -4 -kind -x -5 -match -x -17 -method_visibility -x -15 -add_defn_method -p -65 -I -2 -I -3 -I -a -I -5 -I -d -I -6 -I -22 -I -7 -I -3a -I -8 -I -55 -I -9 -I -6d -I -a -I -85 -I -b -I -a3 -I -c -I -bb -I -d -I -d3 -I -e -I -ee -I -f -I -109 -I -10 -I -115 -I -11 -I -11e -I -14 -I -121 -I -15 -I -139 -I -16 -I -14e -I -17 -I -15d -I -18 -I -169 -I -19 -I -181 -I -1c -I -184 -I -1e -I -18a -I -20 -I -1ab -I -21 -I -1b0 -I -20 -I -1b3 -I -22 -I -1b8 -I -20 -I -1bb -I -23 -I -1c0 -I -20 -I -1c7 -I -25 -I -1e0 -I -26 -I -1f9 -I -28 -I -207 -x -54 -/Users/murphy/ruby/coderay-0.9/test/functional/vhdl.rb -p -0 -x -13 -attach_method -p -3 -I -0 -I -1 -I -23 -x -54 -/Users/murphy/ruby/coderay-0.9/test/functional/vhdl.rb -p -0 diff --git a/vendor/gems/coderay-0.9.7/test/functional/word_list.rb b/vendor/gems/coderay-0.9.7/test/functional/word_list.rb deleted file mode 100644 index 84d6e9e7..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/word_list.rb +++ /dev/null @@ -1,79 +0,0 @@ -require 'test/unit' -require 'coderay' - -class WordListTest < Test::Unit::TestCase - - include CodeRay - - # define word arrays - RESERVED_WORDS = %w[ - asm break case continue default do else - ... - ] - - PREDEFINED_TYPES = %w[ - int long short char void - ... - ] - - PREDEFINED_CONSTANTS = %w[ - EOF NULL ... - ] - - # make a WordList - IDENT_KIND = WordList.new(:ident). - add(RESERVED_WORDS, :reserved). - add(PREDEFINED_TYPES, :pre_type). - add(PREDEFINED_CONSTANTS, :pre_constant) - - def test_word_list_example - assert_equal :pre_type, IDENT_KIND['void'] - # assert_equal :pre_constant, IDENT_KIND['...'] # not specified - end - - def test_word_list - list = WordList.new(:ident).add(['foobar'], :reserved) - assert_equal :reserved, list['foobar'] - assert_equal :ident, list['FooBar'] - end - - def test_word_list_cached - list = WordList.new(:ident, true).add(['foobar'], :reserved) - assert_equal :reserved, list['foobar'] - assert_equal :ident, list['FooBar'] - end - - def test_case_ignoring_word_list - list = CaseIgnoringWordList.new(:ident).add(['foobar'], :reserved) - assert_equal :ident, list['foo'] - assert_equal :reserved, list['foobar'] - assert_equal :reserved, list['FooBar'] - - list = CaseIgnoringWordList.new(:ident).add(['FooBar'], :reserved) - assert_equal :ident, list['foo'] - assert_equal :reserved, list['foobar'] - assert_equal :reserved, list['FooBar'] - end - - def test_case_ignoring_word_list_cached - list = CaseIgnoringWordList.new(:ident, true).add(['foobar'], :reserved) - assert_equal :ident, list['foo'] - assert_equal :reserved, list['foobar'] - assert_equal :reserved, list['FooBar'] - - list = CaseIgnoringWordList.new(:ident, true).add(['FooBar'], :reserved) - assert_equal :ident, list['foo'] - assert_equal :reserved, list['foobar'] - assert_equal :reserved, list['FooBar'] - end - - def test_dup - list = WordList.new(:ident).add(['foobar'], :reserved) - assert_equal :reserved, list['foobar'] - list2 = list.dup - list2.add(%w[foobar], :keyword) - assert_equal :keyword, list2['foobar'] - assert_equal :reserved, list['foobar'] - end - -end \ No newline at end of file diff --git a/vendor/gems/coderay-0.9.7/test/functional/word_list.rbc b/vendor/gems/coderay-0.9.7/test/functional/word_list.rbc deleted file mode 100644 index 37bcdd28..00000000 --- a/vendor/gems/coderay-0.9.7/test/functional/word_list.rbc +++ /dev/null @@ -1,1763 +0,0 @@ -!RBIX -0 -x -M -1 -n -n -x -10 -__script__ -i -53 -5 -7 -0 -64 -47 -49 -1 -1 -15 -5 -7 -2 -64 -47 -49 -1 -1 -15 -99 -7 -3 -45 -4 -5 -43 -6 -43 -7 -65 -49 -8 -3 -13 -99 -12 -7 -9 -12 -7 -10 -12 -65 -12 -49 -11 -4 -15 -49 -9 -0 -15 -2 -11 -I -6 -I -0 -I -0 -I -0 -n -p -12 -s -9 -test/unit -x -7 -require -s -7 -coderay -x -12 -WordListTest -x -4 -Test -n -x -4 -Unit -x -8 -TestCase -x -10 -open_class -x -14 -__class_init__ -M -1 -n -n -x -12 -WordListTest -i -232 -5 -66 -5 -45 -0 -1 -47 -49 -2 -1 -15 -65 -7 -3 -7 -4 -64 -7 -5 -64 -7 -6 -64 -7 -7 -64 -7 -8 -64 -7 -9 -64 -7 -10 -64 -7 -11 -64 -35 -8 -49 -12 -2 -15 -65 -7 -13 -7 -14 -64 -7 -15 -64 -7 -16 -64 -7 -17 -64 -7 -18 -64 -7 -11 -64 -35 -6 -49 -12 -2 -15 -65 -7 -19 -7 -20 -64 -7 -21 -64 -7 -11 -64 -35 -3 -49 -12 -2 -15 -65 -7 -22 -45 -23 -24 -13 -71 -25 -47 -9 -115 -47 -49 -26 -0 -13 -7 -27 -47 -49 -28 -1 -15 -8 -120 -7 -27 -49 -25 -1 -45 -3 -29 -7 -30 -49 -31 -2 -45 -13 -32 -7 -33 -49 -31 -2 -45 -19 -34 -7 -35 -49 -31 -2 -49 -12 -2 -15 -99 -7 -36 -7 -37 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -40 -7 -41 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -42 -7 -43 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -44 -7 -45 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -46 -7 -47 -65 -67 -49 -38 -0 -49 -39 -4 -15 -99 -7 -48 -7 -49 -65 -67 -49 -38 -0 -49 -39 -4 -11 -I -a -I -0 -I -0 -I -0 -n -p -50 -x -7 -CodeRay -n -x -7 -include -x -14 -RESERVED_WORDS -s -3 -asm -s -5 -break -s -4 -case -s -8 -continue -s -7 -default -s -2 -do -s -4 -else -s -3 -... -x -9 -const_set -x -16 -PREDEFINED_TYPES -s -3 -int -s -4 -long -s -5 -short -s -4 -char -s -4 -void -x -20 -PREDEFINED_CONSTANTS -s -3 -EOF -s -4 -NULL -x -10 -IDENT_KIND -x -8 -WordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -n -x -8 -reserved -x -3 -add -n -x -8 -pre_type -n -x -12 -pre_constant -x -22 -test_word_list_example -M -1 -n -n -x -22 -test_word_list_example -i -17 -5 -7 -0 -45 -1 -2 -7 -3 -64 -49 -4 -1 -47 -49 -5 -2 -11 -I -4 -I -0 -I -0 -I -0 -n -p -6 -x -8 -pre_type -x -10 -IDENT_KIND -n -s -4 -void -x -2 -[] -x -12 -assert_equal -p -5 -I -0 -I -1d -I -0 -I -1e -I -11 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -0 -x -17 -method_visibility -x -15 -add_defn_method -x -14 -test_word_list -M -1 -n -n -x -14 -test_word_list -i -73 -45 -0 -1 -13 -71 -2 -47 -9 -23 -47 -49 -3 -0 -13 -7 -4 -47 -49 -5 -1 -15 -8 -28 -7 -4 -49 -2 -1 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -15 -5 -7 -4 -20 -0 -7 -11 -64 -49 -9 -1 -47 -49 -10 -2 -11 -I -5 -I -1 -I -0 -I -0 -n -p -12 -x -8 -WordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -x -2 -[] -x -12 -assert_equal -s -6 -FooBar -p -9 -I -0 -I -22 -I -0 -I -23 -I -29 -I -24 -I -39 -I -25 -I -49 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -1 -x -4 -list -x -21 -test_word_list_cached -M -1 -n -n -x -21 -test_word_list_cached -i -75 -45 -0 -1 -13 -71 -2 -47 -9 -24 -47 -49 -3 -0 -13 -7 -4 -2 -47 -49 -5 -2 -15 -8 -30 -7 -4 -2 -49 -2 -2 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -15 -5 -7 -4 -20 -0 -7 -11 -64 -49 -9 -1 -47 -49 -10 -2 -11 -I -5 -I -1 -I -0 -I -0 -n -p -12 -x -8 -WordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -x -2 -[] -x -12 -assert_equal -s -6 -FooBar -p -9 -I -0 -I -28 -I -0 -I -29 -I -2b -I -2a -I -3b -I -2b -I -4b -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -1 -x -4 -list -x -28 -test_case_ignoring_word_list -M -1 -n -n -x -28 -test_case_ignoring_word_list -i -178 -45 -0 -1 -13 -71 -2 -47 -9 -23 -47 -49 -3 -0 -13 -7 -4 -47 -49 -5 -1 -15 -8 -28 -7 -4 -49 -2 -1 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -4 -20 -0 -7 -9 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -12 -64 -49 -10 -1 -47 -49 -11 -2 -15 -45 -0 -13 -13 -71 -2 -47 -9 -112 -47 -49 -3 -0 -13 -7 -4 -47 -49 -5 -1 -15 -8 -117 -7 -4 -49 -2 -1 -7 -12 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -4 -20 -0 -7 -9 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -12 -64 -49 -10 -1 -47 -49 -11 -2 -11 -I -5 -I -1 -I -0 -I -0 -n -p -14 -x -20 -CaseIgnoringWordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -s -3 -foo -x -2 -[] -x -12 -assert_equal -s -6 -FooBar -n -p -19 -I -0 -I -2e -I -0 -I -2f -I -29 -I -30 -I -39 -I -31 -I -49 -I -32 -I -59 -I -34 -I -82 -I -35 -I -92 -I -36 -I -a2 -I -37 -I -b2 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -1 -x -4 -list -x -35 -test_case_ignoring_word_list_cached -M -1 -n -n -x -35 -test_case_ignoring_word_list_cached -i -182 -45 -0 -1 -13 -71 -2 -47 -9 -24 -47 -49 -3 -0 -13 -7 -4 -2 -47 -49 -5 -2 -15 -8 -30 -7 -4 -2 -49 -2 -2 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -4 -20 -0 -7 -9 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -12 -64 -49 -10 -1 -47 -49 -11 -2 -15 -45 -0 -13 -13 -71 -2 -47 -9 -115 -47 -49 -3 -0 -13 -7 -4 -2 -47 -49 -5 -2 -15 -8 -121 -7 -4 -2 -49 -2 -2 -7 -12 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -4 -20 -0 -7 -9 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -10 -1 -47 -49 -11 -2 -15 -5 -7 -7 -20 -0 -7 -12 -64 -49 -10 -1 -47 -49 -11 -2 -11 -I -5 -I -1 -I -0 -I -0 -n -p -14 -x -20 -CaseIgnoringWordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -s -3 -foo -x -2 -[] -x -12 -assert_equal -s -6 -FooBar -n -p -19 -I -0 -I -3a -I -0 -I -3b -I -2b -I -3c -I -3b -I -3d -I -4b -I -3e -I -5b -I -40 -I -86 -I -41 -I -96 -I -42 -I -a6 -I -43 -I -b6 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -1 -x -4 -list -x -8 -test_dup -M -1 -n -n -x -8 -test_dup -i -110 -45 -0 -1 -13 -71 -2 -47 -9 -23 -47 -49 -3 -0 -13 -7 -4 -47 -49 -5 -1 -15 -8 -28 -7 -4 -49 -2 -1 -7 -6 -64 -35 -1 -7 -7 -49 -8 -2 -19 -0 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -15 -20 -0 -49 -11 -0 -19 -1 -15 -20 -1 -7 -6 -64 -35 -1 -7 -12 -49 -8 -2 -15 -5 -7 -12 -20 -1 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -15 -5 -7 -7 -20 -0 -7 -6 -64 -49 -9 -1 -47 -49 -10 -2 -11 -I -6 -I -2 -I -0 -I -0 -n -p -13 -x -8 -WordList -n -x -3 -new -x -8 -allocate -x -5 -ident -x -10 -initialize -s -6 -foobar -x -8 -reserved -x -3 -add -x -2 -[] -x -12 -assert_equal -x -3 -dup -x -7 -keyword -p -15 -I -0 -I -46 -I -0 -I -47 -I -29 -I -48 -I -39 -I -49 -I -41 -I -4a -I -4e -I -4b -I -5e -I -4c -I -6e -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -2 -x -4 -list -x -5 -list2 -p -45 -I -2 -I -6 -I -b -I -9 -I -e -I -a -I -23 -I -b -I -2c -I -e -I -2f -I -f -I -3e -I -10 -I -47 -I -13 -I -4a -I -14 -I -59 -I -18 -I -78 -I -19 -I -7d -I -18 -I -80 -I -1a -I -85 -I -18 -I -88 -I -1b -I -8d -I -18 -I -94 -I -1d -I -a2 -I -22 -I -b0 -I -28 -I -be -I -2e -I -cc -I -3a -I -da -I -46 -I -e8 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -0 -x -13 -attach_method -p -7 -I -0 -I -1 -I -9 -I -2 -I -12 -I -4 -I -35 -x -59 -/Users/murphy/ruby/coderay-0.9/test/functional/word_list.rb -p -0 diff --git a/vendor/gems/rubytree-0.5.2/.specification b/vendor/gems/rubytree-0.5.2/.specification deleted file mode 100644 index 2f5d9807..00000000 --- a/vendor/gems/rubytree-0.5.2/.specification +++ /dev/null @@ -1,80 +0,0 @@ ---- !ruby/object:Gem::Specification -name: rubytree -version: !ruby/object:Gem::Version - version: 0.5.2 -platform: ruby -authors: -- Anupam Sengupta -autorequire: tree -bindir: bin -cert_chain: [] - -date: 2007-12-20 00:00:00 -08:00 -default_executable: -dependencies: -- !ruby/object:Gem::Dependency - name: hoe - type: :runtime - version_requirement: - version_requirements: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: 1.3.0 - version: -description: "Provides a generic tree data-structure with ability to store keyed node-elements in the tree. The implementation mixes in the Enumerable module. Website: http://rubytree.rubyforge.org/" -email: anupamsg@gmail.com -executables: [] - -extensions: [] - -extra_rdoc_files: -- README -- COPYING -- ChangeLog -- History.txt -files: -- COPYING -- ChangeLog -- History.txt -- Manifest.txt -- README -- Rakefile -- TODO -- lib/tree.rb -- lib/tree/binarytree.rb -- setup.rb -- test/test_binarytree.rb -- test/test_tree.rb -has_rdoc: true -homepage: http://rubytree.rubyforge.org/ -licenses: [] - -post_install_message: -rdoc_options: -- --main -- README -require_paths: -- lib -required_ruby_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -required_rubygems_version: !ruby/object:Gem::Requirement - requirements: - - - ">=" - - !ruby/object:Gem::Version - version: "0" - version: -requirements: [] - -rubyforge_project: rubytree -rubygems_version: 1.3.5 -signing_key: -specification_version: 2 -summary: Ruby implementation of the Tree data structure. -test_files: -- test/test_binarytree.rb -- test/test_tree.rb diff --git a/vendor/gems/rubytree-0.5.2/COPYING b/vendor/gems/rubytree-0.5.2/COPYING deleted file mode 100644 index 09e7768f..00000000 --- a/vendor/gems/rubytree-0.5.2/COPYING +++ /dev/null @@ -1,31 +0,0 @@ -RUBYTREE - http://rubytree.rubyforge.org -======================================== - -Copyright (c) 2006, 2007 Anupam Sengupta - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - -- Neither the name of the organization nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/gems/rubytree-0.5.2/ChangeLog b/vendor/gems/rubytree-0.5.2/ChangeLog deleted file mode 100644 index bea9d786..00000000 --- a/vendor/gems/rubytree-0.5.2/ChangeLog +++ /dev/null @@ -1,163 +0,0 @@ -2007-12-21 Anupam Sengupta - - * Rakefile: Added the rcov option to exclude rcov itself from - coverage reports. - - * lib/tree.rb: Minor comment changes. - - * test/test_tree.rb: Added the TestTree enclosing module, and - renamed tests to meet ZenTest requirements. Also added a few - missing test cases. - - * test/test_binarytree.rb: Added the TestTree enclosing Module, - and renamed the tests to meet ZenTest requirements. - -2007-12-19 Anupam Sengupta - - * README (Module): Modified the install instructions from source. - - * lib/tree.rb (Tree::TreeNode::initialize): Removed the - unnecessary self_initialize method. - (Tree::TreeNode): Removed the spurious self_initialize from the - protected list. - (Module): Updated the minor version number. - - * Rakefile: Fixed a problem with reading the Tree::VERSION for the - gem packaging, if any prior version of the gem is already installed. - -2007-12-18 Anupam Sengupta - - * lib/tree.rb: Updated the marshalling logic to correctly handle - non-string content. - (Tree::TreeNode::createDumpRep): Minor code change to use symbols - instead of string key names. - (Tree): Version number change to 0.5.0 - (Tree::TreeNode::hasContent): Minor fix to the comments. - - * test/test_tree.rb (TC_TreeTest::test_breadth_each): Updated test - cases for the marshalling logic. - -2007-11-12 Anupam Sengupta - - * test/test_binarytree.rb: Minor documentation correction. - - * lib/tree/binarytree.rb (Tree::BinaryTreeNode::isRightChild): - Minor documentation change. - -2007-10-10 Anupam Sengupta - - * README: Restructured the format. - - * Rakefile: Added Hoe related logic. If not present, the Rakefile - will default to old behavior. - -2007-10-09 Anupam Sengupta - - * Rakefile: Added setup.rb related tasks. Also added the setup.rb in the PKG_FILES list. - -2007-10-01 Anupam Sengupta - - * Rakefile: Added an optional task for rcov code coverage. - Added a dependency for rake in the Gem Specification. - - * test/test_binarytree.rb: Removed the unnecessary dependency on "Person" class. - - * test/test_tree.rb: Removed dependency on the redundant "Person" class. - (TC_TreeTest::test_comparator): Added a new test for the spaceship operator. - (TC_TreeTest::test_hasContent): Added tests for hasContent? and length methods. - -2007-08-30 Anupam Sengupta - - * test/test_tree.rb (TC_TreeTest::test_preordered_each, TC_TreeTest::test_breadth_each, TC_TreeTest::test_detached_copy): - Added new tests for the new functions added to tree.rb. - - * lib/tree.rb (Tree::TreeNode::detached_copy, Tree::TreeNode::preordered_each, Tree::TreeNode::breadth_each): - Added new functions for returning a detached copy of the node and - for performing breadth first traversal. Also added the pre-ordered - traversal function which is an alias of the existing 'each' method. - - * test/test_binarytree.rb (TC_BinaryTreeTest::test_swap_children): - Added a test case for the children swap function. - - * lib/tree/binarytree.rb (Tree::BinaryTreeNode::swap_children): - Added new function to swap the children. Other minor changes in - comments and code. - -2007-07-18 Anupam Sengupta - - * lib/tree/binarytree.rb (Tree::BinaryTreeNode::leftChild / - rightChild): Minor cosmetic change on the parameter name. - - * test/testbinarytree.rb (TC_BinaryTreeTest::test_isLeftChild): - Minor syntax correction. - - * lib/tree.rb (Tree::TreeNode::depth): Added a tree depth - computation method. - (Tree::TreeNode::breadth): Added a tree breadth method. - - * test/testtree.rb (TC_TreeTest::test_depth/test_breadth): Added a - test for the depth and breadth method. - - * lib/tree/binarytree.rb (Tree::BinaryTreeNode::is*Child): - Added tests for determining whether a node is a left or right - child. - - * test/testbinarytree.rb: Added the test cases for the binary tree - implementation. - (TC_BinaryTreeTest::test_is*Child): Added tests for right or left - childs. - - * lib/tree/binarytree.rb: Added the binary tree implementation. - -2007-07-17 Anupam Sengupta - - * lib/tree.rb (Tree::TreeNode::parentage): Renamed 'ancestors' - method to 'parentage' to avoid clobbering Module.ancestors - -2007-07-16 Anupam Sengupta - - * Rakefile: Added an optional rtags task to generate TAGS file for - Emacs. - - * lib/tree.rb (Tree::TreeNode): Added navigation methods for - siblings and children. Also added some convenience methods. - -2007-07-08 Anupam Sengupta - - * Rakefile: Added a developer target for generating rdoc for the - website. - -2007-06-24 Anupam Sengupta - - * test/testtree.rb, lib/tree.rb: Added the each_leaf traversal method. - - * README: Replaced all occurrances of LICENSE with COPYING - and lowercased all instances of the word 'RubyTree'. - - * Rakefile: Replaced all occurrances of LICENSE with COPYING - -2007-06-23 Anupam Sengupta - - * lib/tree.rb (Tree::TreeNode::isLeaf): Added a isLeaf? method. - - * test/testtree.rb (TC_TreeTest::test_removeFromParent): Added - test for isLeaf? method - - * Rakefile: Added the LICENSE and ChangeLog to the extra RDoc files. - - * lib/tree.rb: Minor updates to the comments. - - * test/testtree.rb: Added the Copyright and License header. - - * test/person.rb: Added the Copyright and License header. - - * lib/tree.rb: Added the Copyright and License header. - - * Rakefile: Added the LICENSE and Changelog to be part of the RDoc task. - - * README: Added documentation in the README, including install - instructions and an example. - - * LICENSE: Added the BSD LICENSE file. - - * Changelog: Added the Changelog file. diff --git a/vendor/gems/rubytree-0.5.2/History.txt b/vendor/gems/rubytree-0.5.2/History.txt deleted file mode 100644 index c43831c9..00000000 --- a/vendor/gems/rubytree-0.5.2/History.txt +++ /dev/null @@ -1,20 +0,0 @@ -= 0.5.2 / 2007-12-21 - -* Added more test cases and enabled ZenTest compatibility for the test case - names. - -= 0.5.1 / 2007-12-20 - -* Minor code refactoring. - -= 0.5.0 / 2007-12-18 - -* Fixed the marshalling code to correctly handle non-string content. - -= 0.4.3 / 2007-10-09 - -* Changes to the build mechanism (now uses Hoe). - -= 0.4.2 / 2007-10-01 - -* Minor code refactoring. Changes in the Rakefile. diff --git a/vendor/gems/rubytree-0.5.2/Manifest.txt b/vendor/gems/rubytree-0.5.2/Manifest.txt deleted file mode 100644 index 171ec7cc..00000000 --- a/vendor/gems/rubytree-0.5.2/Manifest.txt +++ /dev/null @@ -1,12 +0,0 @@ -COPYING -ChangeLog -History.txt -Manifest.txt -README -Rakefile -TODO -lib/tree.rb -lib/tree/binarytree.rb -setup.rb -test/test_binarytree.rb -test/test_tree.rb diff --git a/vendor/gems/rubytree-0.5.2/README b/vendor/gems/rubytree-0.5.2/README deleted file mode 100644 index db690c95..00000000 --- a/vendor/gems/rubytree-0.5.2/README +++ /dev/null @@ -1,147 +0,0 @@ - - __ _ _ - /__\_ _| |__ _ _| |_ _ __ ___ ___ - / \// | | | '_ \| | | | __| '__/ _ \/ _ \ - / _ \ |_| | |_) | |_| | |_| | | __/ __/ - \/ \_/\__,_|_.__/ \__, |\__|_| \___|\___| - |___/ - - (c) 2006, 2007 Anupam Sengupta - http://rubytree.rubyforge.org - -Rubytree is a simple implementation of the generic Tree data structure. This -implementation is node-centric, where the individual nodes on the tree are the -primary objects and drive the structure. - -== INSTALL: - -Rubytree is an open source project and is hosted at: - - http://rubytree.rubyforge.org - -Rubytree can be downloaded as a Rubygem or as a tar/zip file from: - - http://rubyforge.org/frs/?group_id=1215&release_id=8817 - -The file-name is one of: - - rubytree-.gem - The Rubygem - rubytree-.tgz - GZipped source files - rubytree-.zip - Zipped source files - -Download the appropriate file-type for your system. - -It is recommended to install Rubytree as a Ruby Gem, as this is an easy way to -keep the version updated, and keep multiple versions of the library available on -your system. - -=== Installing the Gem - -To Install the Gem, from a Terminal/CLI command prompt, issue the command: - - gem install rubytree - -This should install the gem file for Rubytree. Note that you may need to be a -super-user (root) to successfully install the gem. - -=== Installing from the tgz/zip file - -Extract the archive file (tgz or zip) and run the following command from the -top-level source directory: - - ruby ./setup.rb - -You may need administrator/super-user privileges to complete the setup using -this method. - -== DOCUMENTATION: - -The primary class for this implementation is Tree::TreeNode. See the -class documentation for an usage example. - -From a command line/terminal prompt, you can issue the following command to view -the text mode ri documentation: - - ri Tree::TreeNode - -Documentation on the web is available at: - -http://rubytree.rubyforge.org/rdoc - -== EXAMPLE: - -The following code-snippet implements this tree structure: - - +------------+ - | ROOT | - +-----+------+ - +-------------+------------+ - | | - +-------+-------+ +-------+-------+ - | CHILD 1 | | CHILD 2 | - +-------+-------+ +---------------+ - | - | - +-------+-------+ - | GRANDCHILD 1 | - +---------------+ - - require 'tree' - - myTreeRoot = Tree::TreeNode.new("ROOT", "Root Content") - - myTreeRoot << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content") - - myTreeRoot << Tree::TreeNode.new("CHILD2", "Child2 Content") - - myTreeRoot.printTree - - child1 = myTreeRoot["CHILD1"] - - grandChild1 = myTreeRoot["CHILD1"]["GRANDCHILD1"] - - siblingsOfChild1Array = child1.siblings - - immediateChildrenArray = myTreeRoot.children - - # Process all nodes - - myTreeRoot.each { |node| node.content.reverse } - - myTreeRoot.remove!(child1) # Remove the child - -== LICENSE: - -Rubytree is licensed under BSD license. - -Copyright (c) 2006, 2007 Anupam Sengupta - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -- Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright notice, this - list of conditions and the following disclaimer in the documentation and/or - other materials provided with the distribution. - -- Neither the name of the organization nor the names of its contributors may - be used to endorse or promote products derived from this software without - specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -(Document Revision: $Revision: 1.16 $ by $Author: anupamsg $) diff --git a/vendor/gems/rubytree-0.5.2/Rakefile b/vendor/gems/rubytree-0.5.2/Rakefile deleted file mode 100644 index 814fb026..00000000 --- a/vendor/gems/rubytree-0.5.2/Rakefile +++ /dev/null @@ -1,212 +0,0 @@ -# Rakefile -# -# $Revision: 1.27 $ by $Author: anupamsg $ -# $Name: $ -# -# Copyright (c) 2006, 2007 Anupam Sengupta -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# - Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright notice, this -# list of conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. -# -# - Neither the name of the organization nor the names of its contributors may -# be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -require 'rubygems' -require 'rake/gempackagetask' - -require 'rake/clean' -require 'rake/packagetask' -require 'rake/testtask' -require 'rake/rdoctask' - -require 'fileutils' - -# General Stuff #################################################### - -$:.insert 0, File.expand_path( File.join( File.dirname(__FILE__), 'lib' ) ) -require 'tree' # To read the version information. - -PKG_NAME = "rubytree" -PKG_VERSION = Tree::VERSION -PKG_FULLNAME = PKG_NAME + "-" + PKG_VERSION -PKG_SUMMARY = "Ruby implementation of the Tree data structure." -PKG_DESCRIPTION = <<-END - Provides a generic tree data-structure with ability to - store keyed node-elements in the tree. The implementation - mixes in the Enumerable module. - - Website: http://rubytree.rubyforge.org/ - END - -PKG_FILES = FileList[ - '[A-Z]*', - '*.rb', - 'lib/**/*.rb', - 'test/**/*.rb' - ] - -# Default is to create a rubygem. -desc "Default Task" -task :default => :gem - -begin # Try loading hoe - require 'hoe' - # If Hoe is found, use it to define tasks - # ======================================= - Hoe.new(PKG_NAME, PKG_VERSION) do |p| - p.rubyforge_name = PKG_NAME - p.author = "Anupam Sengupta" - p.email = "anupamsg@gmail.com" - p.summary = PKG_SUMMARY - p.description = PKG_DESCRIPTION - p.url = "http://rubytree.rubyforge.org/" - p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n") - p.remote_rdoc_dir = 'rdoc' - p.need_tar = true - p.need_zip = true - p.test_globs = ['test/test_*.rb'] - p.spec_extras = { - :has_rdoc => true, - :platform => Gem::Platform::RUBY, - :has_rdoc => true, - :extra_rdoc_files => ['README', 'COPYING', 'ChangeLog', 'History.txt'], - :rdoc_options => ['--main', 'README'], - :autorequire => 'tree' - } - end - -rescue LoadError # If Hoe is not found - # If Hoe is not found, then use the usual Gemspec based Rake tasks - # ================================================================ - spec = Gem::Specification.new do |s| - s.name = PKG_NAME - s.version = PKG_VERSION - s.platform = Gem::Platform::RUBY - s.author = "Anupam Sengupta" - s.email = "anupamsg@gmail.com" - s.homepage = "http://rubytree.rubyforge.org/" - s.rubyforge_project = 'rubytree' - s.summary = PKG_SUMMARY - s.add_dependency('rake', '>= 0.7.2') - s.description = PKG_DESCRIPTION - s.has_rdoc = true - s.extra_rdoc_files = ['README', 'COPYING', 'ChangeLog'] - s.autorequire = "tree" - s.files = PKG_FILES.to_a - s.test_files = Dir.glob('test/test*.rb') - end - - desc "Prepares for installation" - task :prepare do - ruby "setup.rb config" - ruby "setup.rb setup" - end - - desc "Installs the package #{PKG_NAME}" - task :install => [:prepare] do - ruby "setup.rb install" - end - - Rake::GemPackageTask.new(spec) do |pkg| - pkg.need_zip = true - pkg.need_tar = true - end - - Rake::TestTask.new do |t| - t.libs << "test" - t.test_files = FileList['test/test*.rb'] - t.verbose = true - end - -end # End loading Hoerc -# ================================================================ - - -# The following tasks are loaded independently of Hoe - -# Hoe's rdoc task is ugly. -Rake::RDocTask.new(:docs) do |rd| - rd.rdoc_files.include("README", "COPYING", "ChangeLog", "lib/**/*.rb") - rd.rdoc_dir = 'doc' - rd.title = "#{PKG_FULLNAME} Documentation" - - # Use the template only if it is present, otherwise, the standard template is - # used. - template = "../allison/allison.rb" - rd.template = template if File.file?(template) - - rd.options << '--line-numbers' << '--inline-source' -end - -# Optional TAGS Task. -# Needs https://rubyforge.org/projects/rtagstask/ -begin - require 'rtagstask' - RTagsTask.new do |rd| - rd.vi = false - end -rescue LoadError -end - -# Optional RCOV Task -# Needs http://eigenclass.org/hiki/rcov -begin - require 'rcov/rcovtask' - Rcov::RcovTask.new do |t| - t.test_files = FileList['test/test*.rb'] - t.rcov_opts << "--exclude 'rcov.rb'" # rcov itself should not be profiled - # t.verbose = true # uncomment to see the executed commands - end -rescue LoadError -end - -#Rakefile,v $ -# Revision 1.21 2007/07/21 05:14:43 anupamsg -# Added a VERSION constant to the Tree module, -# and using the same in the Rakefile. -# -# Revision 1.20 2007/07/21 03:24:25 anupamsg -# Minor edits to parameter names. User visible functionality does not change. -# -# Revision 1.19 2007/07/19 02:16:01 anupamsg -# Release 0.4.0 (and minor fix in Rakefile). -# -# Revision 1.18 2007/07/18 20:15:06 anupamsg -# Added two predicate methods in BinaryTreeNode to determine whether a node -# is a left or a right node. -# -# Revision 1.17 2007/07/18 07:17:34 anupamsg -# Fixed a issue where TreeNode.ancestors was shadowing Module.ancestors. This method -# has been renamed to TreeNode.parentage. -# -# Revision 1.16 2007/07/17 05:34:03 anupamsg -# Added an optional tags Rake-task for generating the TAGS file for Emacs. -# -# Revision 1.15 2007/07/17 04:42:45 anupamsg -# Minor fixes to the Rakefile. -# -# Revision 1.14 2007/07/17 03:39:28 anupamsg -# Moved the CVS Log keyword to end of the files. -# diff --git a/vendor/gems/rubytree-0.5.2/TODO b/vendor/gems/rubytree-0.5.2/TODO deleted file mode 100644 index ae4e74c3..00000000 --- a/vendor/gems/rubytree-0.5.2/TODO +++ /dev/null @@ -1,7 +0,0 @@ -# -*- mode: outline; coding: utf-8-unix; -*- - -* Add logic in Rakefile to read the file list from Manifest.txt file. - -* Add a YAML export method to the TreeNode class. - - diff --git a/vendor/gems/rubytree-0.5.2/lib/tree.rb b/vendor/gems/rubytree-0.5.2/lib/tree.rb deleted file mode 100644 index 9b5062aa..00000000 --- a/vendor/gems/rubytree-0.5.2/lib/tree.rb +++ /dev/null @@ -1,539 +0,0 @@ -# tree.rb -# -# $Revision: 1.29 $ by $Author: anupamsg $ -# $Name: $ -# -# = tree.rb - Generic Multi-way Tree implementation -# -# Provides a generic tree data structure with ability to -# store keyed node elements in the tree. The implementation -# mixes in the Enumerable module. -# -# Author:: Anupam Sengupta (anupamsg@gmail.com) -# - -# Copyright (c) 2006, 2007 Anupam Sengupta -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# - Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright notice, this -# list of conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. -# -# - Neither the name of the organization nor the names of its contributors may -# be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -# This module provides a TreeNode class which is the primary class for all -# nodes represented in the Tree. -# This module mixes in the Enumerable module. -module Tree - - # Rubytree Package Version - VERSION = '0.5.2' - - # == TreeNode Class Description - # - # The node class for the tree representation. the nodes are named and have a - # place-holder for the node data (i.e., the `content' of the node). The node - # names are expected to be unique. In addition, the node provides navigation - # methods to traverse the tree. - # - # The nodes can have any number of child nodes attached to it. Note that while - # this implementation does not support directed graphs, the class itself makes - # no restrictions on associating a node's CONTENT with multiple parent nodes. - # - # - # == Example - # - # The following code-snippet implements this tree structure: - # - # +------------+ - # | ROOT | - # +-----+------+ - # +-------------+------------+ - # | | - # +-------+-------+ +-------+-------+ - # | CHILD 1 | | CHILD 2 | - # +-------+-------+ +---------------+ - # | - # | - # +-------+-------+ - # | GRANDCHILD 1 | - # +---------------+ - # - # require 'tree' - # - # myTreeRoot = Tree::TreeNode.new("ROOT", "Root Content") - # - # myTreeRoot << Tree::TreeNode.new("CHILD1", "Child1 Content") << Tree::TreeNode.new("GRANDCHILD1", "GrandChild1 Content") - # - # myTreeRoot << Tree::TreeNode.new("CHILD2", "Child2 Content") - # - # myTreeRoot.printTree - # - # child1 = myTreeRoot["CHILD1"] - # - # grandChild1 = myTreeRoot["CHILD1"]["GRANDCHILD1"] - # - # siblingsOfChild1Array = child1.siblings - # - # immediateChildrenArray = myTreeRoot.children - # - # # Process all nodes - # - # myTreeRoot.each { |node| node.content.reverse } - # - # myTreeRoot.remove!(child1) # Remove the child - class TreeNode - include Enumerable - - attr_reader :content, :name, :parent - attr_writer :content - - # Constructor which expects the name of the node - # - # Name of the node is expected to be unique across the - # tree. - # - # The content can be of any type, and is defaulted to _nil_. - def initialize(name, content = nil) - raise "Node name HAS to be provided" if name == nil - @name = name - @content = content - self.setAsRoot! - - @childrenHash = Hash.new - @children = [] - end - - # Returns a copy of this node, with the parent and children links removed. - def detached_copy - Tree::TreeNode.new(@name, @content ? @content.clone : nil) - end - - # Print the string representation of this node. - def to_s - "Node Name: #{@name}" + - " Content: " + (@content || "") + - " Parent: " + (isRoot?() ? "" : @parent.name) + - " Children: #{@children.length}" + - " Total Nodes: #{size()}" - end - - # Returns an array of ancestors in reversed order (the first element is the - # immediate parent). Returns nil if this is a root node. - def parentage - return nil if isRoot? - - parentageArray = [] - prevParent = self.parent - while (prevParent) - parentageArray << prevParent - prevParent = prevParent.parent - end - - parentageArray - end - - # Protected method to set the parent node. - # This method should NOT be invoked by client code. - def parent=(parent) - @parent = parent - end - - # Convenience synonym for TreeNode#add method. This method allows a convenient - # method to add children hierarchies in the tree. - # - # E.g. root << child << grand_child - def <<(child) - add(child) - end - - # Adds the specified child node to the receiver node. The child node's - # parent is set to be the receiver. The child is added as the last child in - # the current list of children for the receiver node. - def add(child) - raise "Child already added" if @childrenHash.has_key?(child.name) - - @childrenHash[child.name] = child - @children << child - child.parent = self - return child - - end - - # Removes the specified child node from the receiver node. The removed - # children nodes are orphaned but available if an alternate reference - # exists. - # - # Returns the child node. - def remove!(child) - @childrenHash.delete(child.name) - @children.delete(child) - child.setAsRoot! unless child == nil - return child - end - - # Removes this node from its parent. If this is the root node, then does - # nothing. - def removeFromParent! - @parent.remove!(self) unless isRoot? - end - - # Removes all children from the receiver node. - def removeAll! - for child in @children - child.setAsRoot! - end - @childrenHash.clear - @children.clear - self - end - - # Indicates whether this node has any associated content. - def hasContent? - @content != nil - end - - # Protected method which sets this node as a root node. - def setAsRoot! - @parent = nil - end - - # Indicates whether this node is a root node. Note that - # orphaned children will also be reported as root nodes. - def isRoot? - @parent == nil - end - - # Indicates whether this node has any immediate child nodes. - def hasChildren? - @children.length != 0 - end - - # Indicates whether this node is a 'leaf' - i.e., one without - # any children - def isLeaf? - !hasChildren? - end - - # Returns an array of all the immediate children. If a block is given, - # yields each child node to the block. - def children - if block_given? - @children.each {|child| yield child} - else - @children - end - end - - # Returns the first child of this node. Will return nil if no children are - # present. - def firstChild - children.first - end - - # Returns the last child of this node. Will return nil if no children are - # present. - def lastChild - children.last - end - - # Returns every node (including the receiver node) from the tree to the - # specified block. The traversal is depth first and from left to right in - # pre-ordered sequence. - def each &block - yield self - children { |child| child.each(&block) } - end - - # Traverses the tree in a pre-ordered sequence. This is equivalent to - # TreeNode#each - def preordered_each &block - each(&block) - end - - # Performs breadth first traversal of the tree rooted at this node. The - # traversal in a given level is from left to right. - def breadth_each &block - node_queue = [self] # Create a queue with self as the initial entry - - # Use a queue to do breadth traversal - until node_queue.empty? - node_to_traverse = node_queue.shift - yield node_to_traverse - # Enqueue the children from left to right. - node_to_traverse.children { |child| node_queue.push child } - end - end - - # Yields all leaf nodes from this node to the specified block. May yield - # this node as well if this is a leaf node. Leaf traversal depth first and - # left to right. - def each_leaf &block - self.each { |node| yield(node) if node.isLeaf? } - end - - # Returns the requested node from the set of immediate children. - # - # If the parameter is _numeric_, then the in-sequence array of children is - # accessed (see Tree#children). If the parameter is not _numeric_, then it - # is assumed to be the *name* of the child node to be returned. - def [](name_or_index) - raise "Name_or_index needs to be provided" if name_or_index == nil - - if name_or_index.kind_of?(Integer) - @children[name_or_index] - else - @childrenHash[name_or_index] - end - end - - # Returns the total number of nodes in this tree, rooted at the receiver - # node. - def size - @children.inject(1) {|sum, node| sum + node.size} - end - - # Convenience synonym for Tree#size - def length - size() - end - - # Pretty prints the tree starting with the receiver node. - def printTree(level = 0) - - if isRoot? - print "*" - else - print "|" unless parent.isLastSibling? - print(' ' * (level - 1) * 4) - print(isLastSibling? ? "+" : "|") - print "---" - print(hasChildren? ? "+" : ">") - end - - puts " #{name}" - - children { |child| child.printTree(level + 1)} - end - - # Returns the root for this tree. Root's root is itself. - def root - root = self - root = root.parent while !root.isRoot? - root - end - - # Returns the first sibling for this node. If this is the root node, returns - # itself. - def firstSibling - if isRoot? - self - else - parent.children.first - end - end - - # Returns true if this node is the first sibling. - def isFirstSibling? - firstSibling == self - end - - # Returns the last sibling for this node. If this node is the root, returns - # itself. - def lastSibling - if isRoot? - self - else - parent.children.last - end - end - - # Returns true if his node is the last sibling - def isLastSibling? - lastSibling == self - end - - # Returns an array of siblings for this node. - # If a block is provided, yields each of the sibling - # nodes to the block. The root always has nil siblings. - def siblings - return nil if isRoot? - if block_given? - for sibling in parent.children - yield sibling if sibling != self - end - else - siblings = [] - parent.children {|sibling| siblings << sibling if sibling != self} - siblings - end - end - - # Returns true if this node is the only child of its parent - def isOnlyChild? - parent.children.size == 1 - end - - # Returns the next sibling for this node. Will return nil if no subsequent - # node is present. - def nextSibling - if myidx = parent.children.index(self) - parent.children.at(myidx + 1) - end - end - - # Returns the previous sibling for this node. Will return nil if no - # subsequent node is present. - def previousSibling - if myidx = parent.children.index(self) - parent.children.at(myidx - 1) if myidx > 0 - end - end - - # Provides a comparision operation for the nodes. Comparision - # is based on the natural character-set ordering for the - # node names. - def <=>(other) - return +1 if other == nil - self.name <=> other.name - end - - # Freezes all nodes in the tree - def freezeTree! - each {|node| node.freeze} - end - - # Creates the marshal-dump represention of the tree rooted at this node. - def marshal_dump - self.collect { |node| node.createDumpRep } - end - - # Creates a dump representation and returns the same as a hash. - def createDumpRep - { :name => @name, :parent => (isRoot? ? nil : @parent.name), :content => Marshal.dump(@content)} - end - - # Loads a marshalled dump of the tree and returns the root node of the - # reconstructed tree. See the Marshal class for additional details. - def marshal_load(dumped_tree_array) - nodes = { } - for node_hash in dumped_tree_array do - name = node_hash[:name] - parent_name = node_hash[:parent] - content = Marshal.load(node_hash[:content]) - - if parent_name then - nodes[name] = current_node = Tree::TreeNode.new(name, content) - nodes[parent_name].add current_node - else - # This is the root node, hence initialize self. - initialize(name, content) - - nodes[name] = self # Add self to the list of nodes - end - end - end - - # Returns depth of the tree from this node. A single leaf node has a - # depth of 1. - def depth - return 1 if isLeaf? - 1 + @children.collect { |child| child.depth }.max - end - - # Returns breadth of the tree at this node level. A single node has a - # breadth of 1. - def breadth - return 1 if isRoot? - parent.children.size - end - - protected :parent=, :setAsRoot!, :createDumpRep - - end -end - -# $Log: tree.rb,v $ -# Revision 1.29 2007/12/22 00:28:59 anupamsg -# Added more test cases, and enabled ZenTest compatibility. -# -# Revision 1.28 2007/12/20 03:19:33 anupamsg -# * README (Module): Modified the install instructions from source. -# (Module): Updated the minor version number. -# -# Revision 1.27 2007/12/20 03:00:03 anupamsg -# Minor code changes. Removed self_initialize from the protected methods' list. -# -# Revision 1.26 2007/12/20 02:50:04 anupamsg -# (Tree::TreeNode): Removed the spurious self_initialize from the protected list. -# -# Revision 1.25 2007/12/19 20:28:05 anupamsg -# Removed the unnecesary self_initialize method. -# -# Revision 1.24 2007/12/19 06:39:17 anupamsg -# Removed the unnecessary field and record separator constants. Also updated the -# history.txt file. -# -# Revision 1.23 2007/12/19 06:25:00 anupamsg -# (Tree::TreeNode): Minor fix to the comments. Also fixed the private/protected -# scope issue with the createDumpRep method. -# -# Revision 1.22 2007/12/19 06:22:03 anupamsg -# Updated the marshalling logic to correctly handle non-string content. This -# should fix the bug # 15614 ("When dumping with an Object as the content, you get -# a delimiter collision") -# -# Revision 1.21 2007/12/19 02:24:17 anupamsg -# Updated the marshalling logic to handle non-string contents on the nodes. -# -# Revision 1.20 2007/10/10 08:42:57 anupamsg -# Release 0.4.3 -# -# Revision 1.19 2007/08/31 01:16:27 anupamsg -# Added breadth and pre-order traversals for the tree. Also added a method -# to return the detached copy of a node from the tree. -# -# Revision 1.18 2007/07/21 05:14:44 anupamsg -# Added a VERSION constant to the Tree module, -# and using the same in the Rakefile. -# -# Revision 1.17 2007/07/21 03:24:25 anupamsg -# Minor edits to parameter names. User visible functionality does not change. -# -# Revision 1.16 2007/07/18 23:38:55 anupamsg -# Minor updates to tree.rb -# -# Revision 1.15 2007/07/18 22:11:50 anupamsg -# Added depth and breadth methods for the TreeNode. -# -# Revision 1.14 2007/07/18 19:33:27 anupamsg -# Added a new binary tree implementation. -# -# Revision 1.13 2007/07/18 07:17:34 anupamsg -# Fixed a issue where TreeNode.ancestors was shadowing Module.ancestors. This method -# has been renamed to TreeNode.parentage. -# -# Revision 1.12 2007/07/17 03:39:28 anupamsg -# Moved the CVS Log keyword to end of the files. -# diff --git a/vendor/gems/rubytree-0.5.2/lib/tree/binarytree.rb b/vendor/gems/rubytree-0.5.2/lib/tree/binarytree.rb deleted file mode 100644 index 76c36366..00000000 --- a/vendor/gems/rubytree-0.5.2/lib/tree/binarytree.rb +++ /dev/null @@ -1,131 +0,0 @@ -# binarytree.rb -# -# $Revision: 1.5 $ by $Author: anupamsg $ -# $Name: $ -# -# = binarytree.rb - Binary Tree implementation -# -# Provides a generic tree data structure with ability to -# store keyed node elements in the tree. The implementation -# mixes in the Enumerable module. -# -# Author:: Anupam Sengupta (anupamsg@gmail.com) -# - -# Copyright (c) 2007 Anupam Sengupta -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# - Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright notice, this -# list of conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. -# -# - Neither the name of the organization nor the names of its contributors may -# be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -require 'tree' - -module Tree - - # Provides a Binary tree implementation. This tree node allows only two child - # nodes (left and right childs). It also provides direct access to the left - # and right children, including assignment to the same. - class BinaryTreeNode < TreeNode - - # Adds the specified child node to the receiver node. The child node's - # parent is set to be the receiver. The child nodes are added in the order - # of addition, i.e., the first child added becomes the left node, and the - # second child will be the second node. - # If only one child is present, then this will be the left child. - def add(child) - raise "Already has two child nodes" if @children.size == 2 - - super(child) - end - - # Returns the left child node. Note that - # left Child == first Child - def leftChild - children.first - end - - # Returns the right child node. Note that - # right child == last child unless there is only one child. - # Returns nil if the right child does not exist. - def rightChild - children[1] - end - - # Sets the left child. If a previous child existed, it is replaced. - def leftChild=(child) - @children[0] = child - @childrenHash[child.name] = child if child # Assign the name mapping - end - - # Sets the right child. If a previous child existed, it is replaced. - def rightChild=(child) - @children[1] = child - @childrenHash[child.name] = child if child # Assign the name mapping - end - - # Returns true if this is the left child of its parent. Always returns false - # if this is the root node. - def isLeftChild? - return nil if isRoot? - self == parent.leftChild - end - - # Returns true if this is the right child of its parent. Always returns false - # if this is the root node. - def isRightChild? - return nil if isRoot? - self == parent.rightChild - end - - # Swaps the left and right children with each other - def swap_children - tempChild = leftChild - self.leftChild= rightChild - self.rightChild= tempChild - end - end - -end - -# $Log: binarytree.rb,v $ -# Revision 1.5 2007/12/18 23:11:29 anupamsg -# Minor documentation changes in the binarytree class. -# -# Revision 1.4 2007/08/30 22:08:58 anupamsg -# Added a new swap_children method for Binary Tree. Also added minor -# documentation and test updates. -# -# Revision 1.3 2007/07/21 03:24:25 anupamsg -# Minor edits to parameter names. User visible functionality does not change. -# -# Revision 1.2 2007/07/18 20:15:06 anupamsg -# Added two predicate methods in BinaryTreeNode to determine whether a node -# is a left or a right node. -# -# Revision 1.1 2007/07/18 19:33:27 anupamsg -# Added a new binary tree implementation. -# diff --git a/vendor/gems/rubytree-0.5.2/setup.rb b/vendor/gems/rubytree-0.5.2/setup.rb deleted file mode 100644 index 424a5f37..00000000 --- a/vendor/gems/rubytree-0.5.2/setup.rb +++ /dev/null @@ -1,1585 +0,0 @@ -# -# setup.rb -# -# Copyright (c) 2000-2005 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU LGPL, Lesser General Public License version 2.1. -# - -unless Enumerable.method_defined?(:map) # Ruby 1.4.6 - module Enumerable - alias map collect - end -end - -unless File.respond_to?(:read) # Ruby 1.6 - def File.read(fname) - open(fname) {|f| - return f.read - } - end -end - -unless Errno.const_defined?(:ENOTEMPTY) # Windows? - module Errno - class ENOTEMPTY - # We do not raise this exception, implementation is not needed. - end - end -end - -def File.binread(fname) - open(fname, 'rb') {|f| - return f.read - } -end - -# for corrupted Windows' stat(2) -def File.dir?(path) - File.directory?((path[-1,1] == '/') ? path : path + '/') -end - - -class ConfigTable - - include Enumerable - - def initialize(rbconfig) - @rbconfig = rbconfig - @items = [] - @table = {} - # options - @install_prefix = nil - @config_opt = nil - @verbose = true - @no_harm = false - end - - attr_accessor :install_prefix - attr_accessor :config_opt - - attr_writer :verbose - - def verbose? - @verbose - end - - attr_writer :no_harm - - def no_harm? - @no_harm - end - - def [](key) - lookup(key).resolve(self) - end - - def []=(key, val) - lookup(key).set val - end - - def names - @items.map {|i| i.name } - end - - def each(&block) - @items.each(&block) - end - - def key?(name) - @table.key?(name) - end - - def lookup(name) - @table[name] or setup_rb_error "no such config item: #{name}" - end - - def add(item) - @items.push item - @table[item.name] = item - end - - def remove(name) - item = lookup(name) - @items.delete_if {|i| i.name == name } - @table.delete_if {|name, i| i.name == name } - item - end - - def load_script(path, inst = nil) - if File.file?(path) - MetaConfigEnvironment.new(self, inst).instance_eval File.read(path), path - end - end - - def savefile - '.config' - end - - def load_savefile - begin - File.foreach(savefile()) do |line| - k, v = *line.split(/=/, 2) - self[k] = v.strip - end - rescue Errno::ENOENT - setup_rb_error $!.message + "\n#{File.basename($0)} config first" - end - end - - def save - @items.each {|i| i.value } - File.open(savefile(), 'w') {|f| - @items.each do |i| - f.printf "%s=%s\n", i.name, i.value if i.value? and i.value - end - } - end - - def load_standard_entries - standard_entries(@rbconfig).each do |ent| - add ent - end - end - - def standard_entries(rbconfig) - c = rbconfig - - rubypath = File.join(c['bindir'], c['ruby_install_name'] + c['EXEEXT']) - - major = c['MAJOR'].to_i - minor = c['MINOR'].to_i - teeny = c['TEENY'].to_i - version = "#{major}.#{minor}" - - # ruby ver. >= 1.4.4? - newpath_p = ((major >= 2) or - ((major == 1) and - ((minor >= 5) or - ((minor == 4) and (teeny >= 4))))) - - if c['rubylibdir'] - # V > 1.6.3 - libruby = "#{c['prefix']}/lib/ruby" - librubyver = c['rubylibdir'] - librubyverarch = c['archdir'] - siteruby = c['sitedir'] - siterubyver = c['sitelibdir'] - siterubyverarch = c['sitearchdir'] - elsif newpath_p - # 1.4.4 <= V <= 1.6.3 - libruby = "#{c['prefix']}/lib/ruby" - librubyver = "#{c['prefix']}/lib/ruby/#{version}" - librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" - siteruby = c['sitedir'] - siterubyver = "$siteruby/#{version}" - siterubyverarch = "$siterubyver/#{c['arch']}" - else - # V < 1.4.4 - libruby = "#{c['prefix']}/lib/ruby" - librubyver = "#{c['prefix']}/lib/ruby/#{version}" - librubyverarch = "#{c['prefix']}/lib/ruby/#{version}/#{c['arch']}" - siteruby = "#{c['prefix']}/lib/ruby/#{version}/site_ruby" - siterubyver = siteruby - siterubyverarch = "$siterubyver/#{c['arch']}" - end - parameterize = lambda {|path| - path.sub(/\A#{Regexp.quote(c['prefix'])}/, '$prefix') - } - - if arg = c['configure_args'].split.detect {|arg| /--with-make-prog=/ =~ arg } - makeprog = arg.sub(/'/, '').split(/=/, 2)[1] - else - makeprog = 'make' - end - - [ - ExecItem.new('installdirs', 'std/site/home', - 'std: install under libruby; site: install under site_ruby; home: install under $HOME')\ - {|val, table| - case val - when 'std' - table['rbdir'] = '$librubyver' - table['sodir'] = '$librubyverarch' - when 'site' - table['rbdir'] = '$siterubyver' - table['sodir'] = '$siterubyverarch' - when 'home' - setup_rb_error '$HOME was not set' unless ENV['HOME'] - table['prefix'] = ENV['HOME'] - table['rbdir'] = '$libdir/ruby' - table['sodir'] = '$libdir/ruby' - end - }, - PathItem.new('prefix', 'path', c['prefix'], - 'path prefix of target environment'), - PathItem.new('bindir', 'path', parameterize.call(c['bindir']), - 'the directory for commands'), - PathItem.new('libdir', 'path', parameterize.call(c['libdir']), - 'the directory for libraries'), - PathItem.new('datadir', 'path', parameterize.call(c['datadir']), - 'the directory for shared data'), - PathItem.new('mandir', 'path', parameterize.call(c['mandir']), - 'the directory for man pages'), - PathItem.new('sysconfdir', 'path', parameterize.call(c['sysconfdir']), - 'the directory for system configuration files'), - PathItem.new('localstatedir', 'path', parameterize.call(c['localstatedir']), - 'the directory for local state data'), - PathItem.new('libruby', 'path', libruby, - 'the directory for ruby libraries'), - PathItem.new('librubyver', 'path', librubyver, - 'the directory for standard ruby libraries'), - PathItem.new('librubyverarch', 'path', librubyverarch, - 'the directory for standard ruby extensions'), - PathItem.new('siteruby', 'path', siteruby, - 'the directory for version-independent aux ruby libraries'), - PathItem.new('siterubyver', 'path', siterubyver, - 'the directory for aux ruby libraries'), - PathItem.new('siterubyverarch', 'path', siterubyverarch, - 'the directory for aux ruby binaries'), - PathItem.new('rbdir', 'path', '$siterubyver', - 'the directory for ruby scripts'), - PathItem.new('sodir', 'path', '$siterubyverarch', - 'the directory for ruby extentions'), - PathItem.new('rubypath', 'path', rubypath, - 'the path to set to #! line'), - ProgramItem.new('rubyprog', 'name', rubypath, - 'the ruby program using for installation'), - ProgramItem.new('makeprog', 'name', makeprog, - 'the make program to compile ruby extentions'), - SelectItem.new('shebang', 'all/ruby/never', 'ruby', - 'shebang line (#!) editing mode'), - BoolItem.new('without-ext', 'yes/no', 'no', - 'does not compile/install ruby extentions') - ] - end - private :standard_entries - - def load_multipackage_entries - multipackage_entries().each do |ent| - add ent - end - end - - def multipackage_entries - [ - PackageSelectionItem.new('with', 'name,name...', '', 'ALL', - 'package names that you want to install'), - PackageSelectionItem.new('without', 'name,name...', '', 'NONE', - 'package names that you do not want to install') - ] - end - private :multipackage_entries - - ALIASES = { - 'std-ruby' => 'librubyver', - 'stdruby' => 'librubyver', - 'rubylibdir' => 'librubyver', - 'archdir' => 'librubyverarch', - 'site-ruby-common' => 'siteruby', # For backward compatibility - 'site-ruby' => 'siterubyver', # For backward compatibility - 'bin-dir' => 'bindir', - 'bin-dir' => 'bindir', - 'rb-dir' => 'rbdir', - 'so-dir' => 'sodir', - 'data-dir' => 'datadir', - 'ruby-path' => 'rubypath', - 'ruby-prog' => 'rubyprog', - 'ruby' => 'rubyprog', - 'make-prog' => 'makeprog', - 'make' => 'makeprog' - } - - def fixup - ALIASES.each do |ali, name| - @table[ali] = @table[name] - end - @items.freeze - @table.freeze - @options_re = /\A--(#{@table.keys.join('|')})(?:=(.*))?\z/ - end - - def parse_opt(opt) - m = @options_re.match(opt) or setup_rb_error "config: unknown option #{opt}" - m.to_a[1,2] - end - - def dllext - @rbconfig['DLEXT'] - end - - def value_config?(name) - lookup(name).value? - end - - class Item - def initialize(name, template, default, desc) - @name = name.freeze - @template = template - @value = default - @default = default - @description = desc - end - - attr_reader :name - attr_reader :description - - attr_accessor :default - alias help_default default - - def help_opt - "--#{@name}=#{@template}" - end - - def value? - true - end - - def value - @value - end - - def resolve(table) - @value.gsub(%r<\$([^/]+)>) { table[$1] } - end - - def set(val) - @value = check(val) - end - - private - - def check(val) - setup_rb_error "config: --#{name} requires argument" unless val - val - end - end - - class BoolItem < Item - def config_type - 'bool' - end - - def help_opt - "--#{@name}" - end - - private - - def check(val) - return 'yes' unless val - case val - when /\Ay(es)?\z/i, /\At(rue)?\z/i then 'yes' - when /\An(o)?\z/i, /\Af(alse)\z/i then 'no' - else - setup_rb_error "config: --#{@name} accepts only yes/no for argument" - end - end - end - - class PathItem < Item - def config_type - 'path' - end - - private - - def check(path) - setup_rb_error "config: --#{@name} requires argument" unless path - path[0,1] == '$' ? path : File.expand_path(path) - end - end - - class ProgramItem < Item - def config_type - 'program' - end - end - - class SelectItem < Item - def initialize(name, selection, default, desc) - super - @ok = selection.split('/') - end - - def config_type - 'select' - end - - private - - def check(val) - unless @ok.include?(val.strip) - setup_rb_error "config: use --#{@name}=#{@template} (#{val})" - end - val.strip - end - end - - class ExecItem < Item - def initialize(name, selection, desc, &block) - super name, selection, nil, desc - @ok = selection.split('/') - @action = block - end - - def config_type - 'exec' - end - - def value? - false - end - - def resolve(table) - setup_rb_error "$#{name()} wrongly used as option value" - end - - undef set - - def evaluate(val, table) - v = val.strip.downcase - unless @ok.include?(v) - setup_rb_error "invalid option --#{@name}=#{val} (use #{@template})" - end - @action.call v, table - end - end - - class PackageSelectionItem < Item - def initialize(name, template, default, help_default, desc) - super name, template, default, desc - @help_default = help_default - end - - attr_reader :help_default - - def config_type - 'package' - end - - private - - def check(val) - unless File.dir?("packages/#{val}") - setup_rb_error "config: no such package: #{val}" - end - val - end - end - - class MetaConfigEnvironment - def initialize(config, installer) - @config = config - @installer = installer - end - - def config_names - @config.names - end - - def config?(name) - @config.key?(name) - end - - def bool_config?(name) - @config.lookup(name).config_type == 'bool' - end - - def path_config?(name) - @config.lookup(name).config_type == 'path' - end - - def value_config?(name) - @config.lookup(name).config_type != 'exec' - end - - def add_config(item) - @config.add item - end - - def add_bool_config(name, default, desc) - @config.add BoolItem.new(name, 'yes/no', default ? 'yes' : 'no', desc) - end - - def add_path_config(name, default, desc) - @config.add PathItem.new(name, 'path', default, desc) - end - - def set_config_default(name, default) - @config.lookup(name).default = default - end - - def remove_config(name) - @config.remove(name) - end - - # For only multipackage - def packages - raise '[setup.rb fatal] multi-package metaconfig API packages() called for single-package; contact application package vendor' unless @installer - @installer.packages - end - - # For only multipackage - def declare_packages(list) - raise '[setup.rb fatal] multi-package metaconfig API declare_packages() called for single-package; contact application package vendor' unless @installer - @installer.packages = list - end - end - -end # class ConfigTable - - -# This module requires: #verbose?, #no_harm? -module FileOperations - - def mkdir_p(dirname, prefix = nil) - dirname = prefix + File.expand_path(dirname) if prefix - $stderr.puts "mkdir -p #{dirname}" if verbose? - return if no_harm? - - # Does not check '/', it's too abnormal. - dirs = File.expand_path(dirname).split(%r<(?=/)>) - if /\A[a-z]:\z/i =~ dirs[0] - disk = dirs.shift - dirs[0] = disk + dirs[0] - end - dirs.each_index do |idx| - path = dirs[0..idx].join('') - Dir.mkdir path unless File.dir?(path) - end - end - - def rm_f(path) - $stderr.puts "rm -f #{path}" if verbose? - return if no_harm? - force_remove_file path - end - - def rm_rf(path) - $stderr.puts "rm -rf #{path}" if verbose? - return if no_harm? - remove_tree path - end - - def remove_tree(path) - if File.symlink?(path) - remove_file path - elsif File.dir?(path) - remove_tree0 path - else - force_remove_file path - end - end - - def remove_tree0(path) - Dir.foreach(path) do |ent| - next if ent == '.' - next if ent == '..' - entpath = "#{path}/#{ent}" - if File.symlink?(entpath) - remove_file entpath - elsif File.dir?(entpath) - remove_tree0 entpath - else - force_remove_file entpath - end - end - begin - Dir.rmdir path - rescue Errno::ENOTEMPTY - # directory may not be empty - end - end - - def move_file(src, dest) - force_remove_file dest - begin - File.rename src, dest - rescue - File.open(dest, 'wb') {|f| - f.write File.binread(src) - } - File.chmod File.stat(src).mode, dest - File.unlink src - end - end - - def force_remove_file(path) - begin - remove_file path - rescue - end - end - - def remove_file(path) - File.chmod 0777, path - File.unlink path - end - - def install(from, dest, mode, prefix = nil) - $stderr.puts "install #{from} #{dest}" if verbose? - return if no_harm? - - realdest = prefix ? prefix + File.expand_path(dest) : dest - realdest = File.join(realdest, File.basename(from)) if File.dir?(realdest) - str = File.binread(from) - if diff?(str, realdest) - verbose_off { - rm_f realdest if File.exist?(realdest) - } - File.open(realdest, 'wb') {|f| - f.write str - } - File.chmod mode, realdest - - File.open("#{objdir_root()}/InstalledFiles", 'a') {|f| - if prefix - f.puts realdest.sub(prefix, '') - else - f.puts realdest - end - } - end - end - - def diff?(new_content, path) - return true unless File.exist?(path) - new_content != File.binread(path) - end - - def command(*args) - $stderr.puts args.join(' ') if verbose? - system(*args) or raise RuntimeError, - "system(#{args.map{|a| a.inspect }.join(' ')}) failed" - end - - def ruby(*args) - command config('rubyprog'), *args - end - - def make(task = nil) - command(*[config('makeprog'), task].compact) - end - - def extdir?(dir) - File.exist?("#{dir}/MANIFEST") or File.exist?("#{dir}/extconf.rb") - end - - def files_of(dir) - Dir.open(dir) {|d| - return d.select {|ent| File.file?("#{dir}/#{ent}") } - } - end - - DIR_REJECT = %w( . .. CVS SCCS RCS CVS.adm .svn ) - - def directories_of(dir) - Dir.open(dir) {|d| - return d.select {|ent| File.dir?("#{dir}/#{ent}") } - DIR_REJECT - } - end - -end - - -# This module requires: #srcdir_root, #objdir_root, #relpath -module HookScriptAPI - - def get_config(key) - @config[key] - end - - alias config get_config - - # obsolete: use metaconfig to change configuration - def set_config(key, val) - @config[key] = val - end - - # - # srcdir/objdir (works only in the package directory) - # - - def curr_srcdir - "#{srcdir_root()}/#{relpath()}" - end - - def curr_objdir - "#{objdir_root()}/#{relpath()}" - end - - def srcfile(path) - "#{curr_srcdir()}/#{path}" - end - - def srcexist?(path) - File.exist?(srcfile(path)) - end - - def srcdirectory?(path) - File.dir?(srcfile(path)) - end - - def srcfile?(path) - File.file?(srcfile(path)) - end - - def srcentries(path = '.') - Dir.open("#{curr_srcdir()}/#{path}") {|d| - return d.to_a - %w(. ..) - } - end - - def srcfiles(path = '.') - srcentries(path).select {|fname| - File.file?(File.join(curr_srcdir(), path, fname)) - } - end - - def srcdirectories(path = '.') - srcentries(path).select {|fname| - File.dir?(File.join(curr_srcdir(), path, fname)) - } - end - -end - - -class ToplevelInstaller - - Version = '3.4.1' - Copyright = 'Copyright (c) 2000-2005 Minero Aoki' - - TASKS = [ - [ 'all', 'do config, setup, then install' ], - [ 'config', 'saves your configurations' ], - [ 'show', 'shows current configuration' ], - [ 'setup', 'compiles ruby extentions and others' ], - [ 'install', 'installs files' ], - [ 'test', 'run all tests in test/' ], - [ 'clean', "does `make clean' for each extention" ], - [ 'distclean',"does `make distclean' for each extention" ] - ] - - def ToplevelInstaller.invoke - config = ConfigTable.new(load_rbconfig()) - config.load_standard_entries - config.load_multipackage_entries if multipackage? - config.fixup - klass = (multipackage?() ? ToplevelInstallerMulti : ToplevelInstaller) - klass.new(File.dirname($0), config).invoke - end - - def ToplevelInstaller.multipackage? - File.dir?(File.dirname($0) + '/packages') - end - - def ToplevelInstaller.load_rbconfig - if arg = ARGV.detect {|arg| /\A--rbconfig=/ =~ arg } - ARGV.delete(arg) - load File.expand_path(arg.split(/=/, 2)[1]) - $".push 'rbconfig.rb' - else - require 'rbconfig' - end - ::Config::CONFIG - end - - def initialize(ardir_root, config) - @ardir = File.expand_path(ardir_root) - @config = config - # cache - @valid_task_re = nil - end - - def config(key) - @config[key] - end - - def inspect - "#<#{self.class} #{__id__()}>" - end - - def invoke - run_metaconfigs - case task = parsearg_global() - when nil, 'all' - parsearg_config - init_installers - exec_config - exec_setup - exec_install - else - case task - when 'config', 'test' - ; - when 'clean', 'distclean' - @config.load_savefile if File.exist?(@config.savefile) - else - @config.load_savefile - end - __send__ "parsearg_#{task}" - init_installers - __send__ "exec_#{task}" - end - end - - def run_metaconfigs - @config.load_script "#{@ardir}/metaconfig" - end - - def init_installers - @installer = Installer.new(@config, @ardir, File.expand_path('.')) - end - - # - # Hook Script API bases - # - - def srcdir_root - @ardir - end - - def objdir_root - '.' - end - - def relpath - '.' - end - - # - # Option Parsing - # - - def parsearg_global - while arg = ARGV.shift - case arg - when /\A\w+\z/ - setup_rb_error "invalid task: #{arg}" unless valid_task?(arg) - return arg - when '-q', '--quiet' - @config.verbose = false - when '--verbose' - @config.verbose = true - when '--help' - print_usage $stdout - exit 0 - when '--version' - puts "#{File.basename($0)} version #{Version}" - exit 0 - when '--copyright' - puts Copyright - exit 0 - else - setup_rb_error "unknown global option '#{arg}'" - end - end - nil - end - - def valid_task?(t) - valid_task_re() =~ t - end - - def valid_task_re - @valid_task_re ||= /\A(?:#{TASKS.map {|task,desc| task }.join('|')})\z/ - end - - def parsearg_no_options - unless ARGV.empty? - task = caller(0).first.slice(%r<`parsearg_(\w+)'>, 1) - setup_rb_error "#{task}: unknown options: #{ARGV.join(' ')}" - end - end - - alias parsearg_show parsearg_no_options - alias parsearg_setup parsearg_no_options - alias parsearg_test parsearg_no_options - alias parsearg_clean parsearg_no_options - alias parsearg_distclean parsearg_no_options - - def parsearg_config - evalopt = [] - set = [] - @config.config_opt = [] - while i = ARGV.shift - if /\A--?\z/ =~ i - @config.config_opt = ARGV.dup - break - end - name, value = *@config.parse_opt(i) - if @config.value_config?(name) - @config[name] = value - else - evalopt.push [name, value] - end - set.push name - end - evalopt.each do |name, value| - @config.lookup(name).evaluate value, @config - end - # Check if configuration is valid - set.each do |n| - @config[n] if @config.value_config?(n) - end - end - - def parsearg_install - @config.no_harm = false - @config.install_prefix = '' - while a = ARGV.shift - case a - when '--no-harm' - @config.no_harm = true - when /\A--prefix=/ - path = a.split(/=/, 2)[1] - path = File.expand_path(path) unless path[0,1] == '/' - @config.install_prefix = path - else - setup_rb_error "install: unknown option #{a}" - end - end - end - - def print_usage(out) - out.puts 'Typical Installation Procedure:' - out.puts " $ ruby #{File.basename $0} config" - out.puts " $ ruby #{File.basename $0} setup" - out.puts " # ruby #{File.basename $0} install (may require root privilege)" - out.puts - out.puts 'Detailed Usage:' - out.puts " ruby #{File.basename $0} " - out.puts " ruby #{File.basename $0} [] []" - - fmt = " %-24s %s\n" - out.puts - out.puts 'Global options:' - out.printf fmt, '-q,--quiet', 'suppress message outputs' - out.printf fmt, ' --verbose', 'output messages verbosely' - out.printf fmt, ' --help', 'print this message' - out.printf fmt, ' --version', 'print version and quit' - out.printf fmt, ' --copyright', 'print copyright and quit' - out.puts - out.puts 'Tasks:' - TASKS.each do |name, desc| - out.printf fmt, name, desc - end - - fmt = " %-24s %s [%s]\n" - out.puts - out.puts 'Options for CONFIG or ALL:' - @config.each do |item| - out.printf fmt, item.help_opt, item.description, item.help_default - end - out.printf fmt, '--rbconfig=path', 'rbconfig.rb to load',"running ruby's" - out.puts - out.puts 'Options for INSTALL:' - out.printf fmt, '--no-harm', 'only display what to do if given', 'off' - out.printf fmt, '--prefix=path', 'install path prefix', '' - out.puts - end - - # - # Task Handlers - # - - def exec_config - @installer.exec_config - @config.save # must be final - end - - def exec_setup - @installer.exec_setup - end - - def exec_install - @installer.exec_install - end - - def exec_test - @installer.exec_test - end - - def exec_show - @config.each do |i| - printf "%-20s %s\n", i.name, i.value if i.value? - end - end - - def exec_clean - @installer.exec_clean - end - - def exec_distclean - @installer.exec_distclean - end - -end # class ToplevelInstaller - - -class ToplevelInstallerMulti < ToplevelInstaller - - include FileOperations - - def initialize(ardir_root, config) - super - @packages = directories_of("#{@ardir}/packages") - raise 'no package exists' if @packages.empty? - @root_installer = Installer.new(@config, @ardir, File.expand_path('.')) - end - - def run_metaconfigs - @config.load_script "#{@ardir}/metaconfig", self - @packages.each do |name| - @config.load_script "#{@ardir}/packages/#{name}/metaconfig" - end - end - - attr_reader :packages - - def packages=(list) - raise 'package list is empty' if list.empty? - list.each do |name| - raise "directory packages/#{name} does not exist"\ - unless File.dir?("#{@ardir}/packages/#{name}") - end - @packages = list - end - - def init_installers - @installers = {} - @packages.each do |pack| - @installers[pack] = Installer.new(@config, - "#{@ardir}/packages/#{pack}", - "packages/#{pack}") - end - with = extract_selection(config('with')) - without = extract_selection(config('without')) - @selected = @installers.keys.select {|name| - (with.empty? or with.include?(name)) \ - and not without.include?(name) - } - end - - def extract_selection(list) - a = list.split(/,/) - a.each do |name| - setup_rb_error "no such package: #{name}" unless @installers.key?(name) - end - a - end - - def print_usage(f) - super - f.puts 'Inluded packages:' - f.puts ' ' + @packages.sort.join(' ') - f.puts - end - - # - # Task Handlers - # - - def exec_config - run_hook 'pre-config' - each_selected_installers {|inst| inst.exec_config } - run_hook 'post-config' - @config.save # must be final - end - - def exec_setup - run_hook 'pre-setup' - each_selected_installers {|inst| inst.exec_setup } - run_hook 'post-setup' - end - - def exec_install - run_hook 'pre-install' - each_selected_installers {|inst| inst.exec_install } - run_hook 'post-install' - end - - def exec_test - run_hook 'pre-test' - each_selected_installers {|inst| inst.exec_test } - run_hook 'post-test' - end - - def exec_clean - rm_f @config.savefile - run_hook 'pre-clean' - each_selected_installers {|inst| inst.exec_clean } - run_hook 'post-clean' - end - - def exec_distclean - rm_f @config.savefile - run_hook 'pre-distclean' - each_selected_installers {|inst| inst.exec_distclean } - run_hook 'post-distclean' - end - - # - # lib - # - - def each_selected_installers - Dir.mkdir 'packages' unless File.dir?('packages') - @selected.each do |pack| - $stderr.puts "Processing the package `#{pack}' ..." if verbose? - Dir.mkdir "packages/#{pack}" unless File.dir?("packages/#{pack}") - Dir.chdir "packages/#{pack}" - yield @installers[pack] - Dir.chdir '../..' - end - end - - def run_hook(id) - @root_installer.run_hook id - end - - # module FileOperations requires this - def verbose? - @config.verbose? - end - - # module FileOperations requires this - def no_harm? - @config.no_harm? - end - -end # class ToplevelInstallerMulti - - -class Installer - - FILETYPES = %w( bin lib ext data conf man ) - - include FileOperations - include HookScriptAPI - - def initialize(config, srcroot, objroot) - @config = config - @srcdir = File.expand_path(srcroot) - @objdir = File.expand_path(objroot) - @currdir = '.' - end - - def inspect - "#<#{self.class} #{File.basename(@srcdir)}>" - end - - def noop(rel) - end - - # - # Hook Script API base methods - # - - def srcdir_root - @srcdir - end - - def objdir_root - @objdir - end - - def relpath - @currdir - end - - # - # Config Access - # - - # module FileOperations requires this - def verbose? - @config.verbose? - end - - # module FileOperations requires this - def no_harm? - @config.no_harm? - end - - def verbose_off - begin - save, @config.verbose = @config.verbose?, false - yield - ensure - @config.verbose = save - end - end - - # - # TASK config - # - - def exec_config - exec_task_traverse 'config' - end - - alias config_dir_bin noop - alias config_dir_lib noop - - def config_dir_ext(rel) - extconf if extdir?(curr_srcdir()) - end - - alias config_dir_data noop - alias config_dir_conf noop - alias config_dir_man noop - - def extconf - ruby "#{curr_srcdir()}/extconf.rb", *@config.config_opt - end - - # - # TASK setup - # - - def exec_setup - exec_task_traverse 'setup' - end - - def setup_dir_bin(rel) - files_of(curr_srcdir()).each do |fname| - update_shebang_line "#{curr_srcdir()}/#{fname}" - end - end - - alias setup_dir_lib noop - - def setup_dir_ext(rel) - make if extdir?(curr_srcdir()) - end - - alias setup_dir_data noop - alias setup_dir_conf noop - alias setup_dir_man noop - - def update_shebang_line(path) - return if no_harm? - return if config('shebang') == 'never' - old = Shebang.load(path) - if old - $stderr.puts "warning: #{path}: Shebang line includes too many args. It is not portable and your program may not work." if old.args.size > 1 - new = new_shebang(old) - return if new.to_s == old.to_s - else - return unless config('shebang') == 'all' - new = Shebang.new(config('rubypath')) - end - $stderr.puts "updating shebang: #{File.basename(path)}" if verbose? - open_atomic_writer(path) {|output| - File.open(path, 'rb') {|f| - f.gets if old # discard - output.puts new.to_s - output.print f.read - } - } - end - - def new_shebang(old) - if /\Aruby/ =~ File.basename(old.cmd) - Shebang.new(config('rubypath'), old.args) - elsif File.basename(old.cmd) == 'env' and old.args.first == 'ruby' - Shebang.new(config('rubypath'), old.args[1..-1]) - else - return old unless config('shebang') == 'all' - Shebang.new(config('rubypath')) - end - end - - def open_atomic_writer(path, &block) - tmpfile = File.basename(path) + '.tmp' - begin - File.open(tmpfile, 'wb', &block) - File.rename tmpfile, File.basename(path) - ensure - File.unlink tmpfile if File.exist?(tmpfile) - end - end - - class Shebang - def Shebang.load(path) - line = nil - File.open(path) {|f| - line = f.gets - } - return nil unless /\A#!/ =~ line - parse(line) - end - - def Shebang.parse(line) - cmd, *args = *line.strip.sub(/\A\#!/, '').split(' ') - new(cmd, args) - end - - def initialize(cmd, args = []) - @cmd = cmd - @args = args - end - - attr_reader :cmd - attr_reader :args - - def to_s - "#! #{@cmd}" + (@args.empty? ? '' : " #{@args.join(' ')}") - end - end - - # - # TASK install - # - - def exec_install - rm_f 'InstalledFiles' - exec_task_traverse 'install' - end - - def install_dir_bin(rel) - install_files targetfiles(), "#{config('bindir')}/#{rel}", 0755 - end - - def install_dir_lib(rel) - install_files libfiles(), "#{config('rbdir')}/#{rel}", 0644 - end - - def install_dir_ext(rel) - return unless extdir?(curr_srcdir()) - install_files rubyextentions('.'), - "#{config('sodir')}/#{File.dirname(rel)}", - 0555 - end - - def install_dir_data(rel) - install_files targetfiles(), "#{config('datadir')}/#{rel}", 0644 - end - - def install_dir_conf(rel) - # FIXME: should not remove current config files - # (rename previous file to .old/.org) - install_files targetfiles(), "#{config('sysconfdir')}/#{rel}", 0644 - end - - def install_dir_man(rel) - install_files targetfiles(), "#{config('mandir')}/#{rel}", 0644 - end - - def install_files(list, dest, mode) - mkdir_p dest, @config.install_prefix - list.each do |fname| - install fname, dest, mode, @config.install_prefix - end - end - - def libfiles - glob_reject(%w(*.y *.output), targetfiles()) - end - - def rubyextentions(dir) - ents = glob_select("*.#{@config.dllext}", targetfiles()) - if ents.empty? - setup_rb_error "no ruby extention exists: 'ruby #{$0} setup' first" - end - ents - end - - def targetfiles - mapdir(existfiles() - hookfiles()) - end - - def mapdir(ents) - ents.map {|ent| - if File.exist?(ent) - then ent # objdir - else "#{curr_srcdir()}/#{ent}" # srcdir - end - } - end - - # picked up many entries from cvs-1.11.1/src/ignore.c - JUNK_FILES = %w( - core RCSLOG tags TAGS .make.state - .nse_depinfo #* .#* cvslog.* ,* .del-* *.olb - *~ *.old *.bak *.BAK *.orig *.rej _$* *$ - - *.org *.in .* - ) - - def existfiles - glob_reject(JUNK_FILES, (files_of(curr_srcdir()) | files_of('.'))) - end - - def hookfiles - %w( pre-%s post-%s pre-%s.rb post-%s.rb ).map {|fmt| - %w( config setup install clean ).map {|t| sprintf(fmt, t) } - }.flatten - end - - def glob_select(pat, ents) - re = globs2re([pat]) - ents.select {|ent| re =~ ent } - end - - def glob_reject(pats, ents) - re = globs2re(pats) - ents.reject {|ent| re =~ ent } - end - - GLOB2REGEX = { - '.' => '\.', - '$' => '\$', - '#' => '\#', - '*' => '.*' - } - - def globs2re(pats) - /\A(?:#{ - pats.map {|pat| pat.gsub(/[\.\$\#\*]/) {|ch| GLOB2REGEX[ch] } }.join('|') - })\z/ - end - - # - # TASK test - # - - TESTDIR = 'test' - - def exec_test - unless File.directory?('test') - $stderr.puts 'no test in this package' if verbose? - return - end - $stderr.puts 'Running tests...' if verbose? - begin - require 'test/unit' - rescue LoadError - setup_rb_error 'test/unit cannot loaded. You need Ruby 1.8 or later to invoke this task.' - end - runner = Test::Unit::AutoRunner.new(true) - runner.to_run << TESTDIR - runner.run - end - - # - # TASK clean - # - - def exec_clean - exec_task_traverse 'clean' - rm_f @config.savefile - rm_f 'InstalledFiles' - end - - alias clean_dir_bin noop - alias clean_dir_lib noop - alias clean_dir_data noop - alias clean_dir_conf noop - alias clean_dir_man noop - - def clean_dir_ext(rel) - return unless extdir?(curr_srcdir()) - make 'clean' if File.file?('Makefile') - end - - # - # TASK distclean - # - - def exec_distclean - exec_task_traverse 'distclean' - rm_f @config.savefile - rm_f 'InstalledFiles' - end - - alias distclean_dir_bin noop - alias distclean_dir_lib noop - - def distclean_dir_ext(rel) - return unless extdir?(curr_srcdir()) - make 'distclean' if File.file?('Makefile') - end - - alias distclean_dir_data noop - alias distclean_dir_conf noop - alias distclean_dir_man noop - - # - # Traversing - # - - def exec_task_traverse(task) - run_hook "pre-#{task}" - FILETYPES.each do |type| - if type == 'ext' and config('without-ext') == 'yes' - $stderr.puts 'skipping ext/* by user option' if verbose? - next - end - traverse task, type, "#{task}_dir_#{type}" - end - run_hook "post-#{task}" - end - - def traverse(task, rel, mid) - dive_into(rel) { - run_hook "pre-#{task}" - __send__ mid, rel.sub(%r[\A.*?(?:/|\z)], '') - directories_of(curr_srcdir()).each do |d| - traverse task, "#{rel}/#{d}", mid - end - run_hook "post-#{task}" - } - end - - def dive_into(rel) - return unless File.dir?("#{@srcdir}/#{rel}") - - dir = File.basename(rel) - Dir.mkdir dir unless File.dir?(dir) - prevdir = Dir.pwd - Dir.chdir dir - $stderr.puts '---> ' + rel if verbose? - @currdir = rel - yield - Dir.chdir prevdir - $stderr.puts '<--- ' + rel if verbose? - @currdir = File.dirname(rel) - end - - def run_hook(id) - path = [ "#{curr_srcdir()}/#{id}", - "#{curr_srcdir()}/#{id}.rb" ].detect {|cand| File.file?(cand) } - return unless path - begin - instance_eval File.read(path), path, 1 - rescue - raise if $DEBUG - setup_rb_error "hook #{path} failed:\n" + $!.message - end - end - -end # class Installer - - -class SetupError < StandardError; end - -def setup_rb_error(msg) - raise SetupError, msg -end - -if $0 == __FILE__ - begin - ToplevelInstaller.invoke - rescue SetupError - raise if $DEBUG - $stderr.puts $!.message - $stderr.puts "Try 'ruby #{$0} --help' for detailed usage." - exit 1 - end -end diff --git a/vendor/gems/rubytree-0.5.2/test/test_binarytree.rb b/vendor/gems/rubytree-0.5.2/test/test_binarytree.rb deleted file mode 100644 index 8d866456..00000000 --- a/vendor/gems/rubytree-0.5.2/test/test_binarytree.rb +++ /dev/null @@ -1,204 +0,0 @@ -#!/usr/bin/env ruby - -# test_binarytree.rb -# -# $Revision: 1.5 $ by $Author: anupamsg $ -# $Name: $ -# -# Copyright (c) 2006, 2007 Anupam Sengupta -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# - Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright notice, this -# list of conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. -# -# - Neither the name of the organization nor the names of its contributors may -# be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -require 'test/unit' -require 'tree/binarytree' - -module TestTree - # Test class for the Tree node. - class TestBinaryTreeNode < Test::Unit::TestCase - - def setup - @root = Tree::BinaryTreeNode.new("ROOT", "Root Node") - - @left_child1 = Tree::BinaryTreeNode.new("A Child at Left", "Child Node @ left") - @right_child1 = Tree::BinaryTreeNode.new("B Child at Right", "Child Node @ right") - - end - - def teardown - @root.remove!(@left_child1) - @root.remove!(@right_child1) - @root = nil - end - - def test_initialize - assert_not_nil(@root, "Binary tree's Root should have been created") - end - - def test_add - @root.add @left_child1 - assert_same(@left_child1, @root.leftChild, "The left node should be left_child1") - assert_same(@left_child1, @root.firstChild, "The first node should be left_child1") - - @root.add @right_child1 - assert_same(@right_child1, @root.rightChild, "The right node should be right_child1") - assert_same(@right_child1, @root.lastChild, "The first node should be right_child1") - - assert_raise RuntimeError do - @root.add Tree::BinaryTreeNode.new("The third child!") - end - - assert_raise RuntimeError do - @root << Tree::BinaryTreeNode.new("The third child!") - end - end - - def test_leftChild - @root << @left_child1 - @root << @right_child1 - assert_same(@left_child1, @root.leftChild, "The left child should be 'left_child1") - assert_not_same(@right_child1, @root.leftChild, "The right_child1 is not the left child") - end - - def test_rightChild - @root << @left_child1 - @root << @right_child1 - assert_same(@right_child1, @root.rightChild, "The right child should be 'right_child1") - assert_not_same(@left_child1, @root.rightChild, "The left_child1 is not the left child") - end - - def test_leftChild_equals - @root << @left_child1 - @root << @right_child1 - assert_same(@left_child1, @root.leftChild, "The left child should be 'left_child1") - - @root.leftChild = Tree::BinaryTreeNode.new("New Left Child") - assert_equal("New Left Child", @root.leftChild.name, "The left child should now be the new child") - assert_equal("B Child at Right", @root.lastChild.name, "The last child should now be the right child") - - # Now set the left child as nil, and retest - @root.leftChild = nil - assert_nil(@root.leftChild, "The left child should now be nil") - assert_nil(@root.firstChild, "The first child is now nil") - assert_equal("B Child at Right", @root.lastChild.name, "The last child should now be the right child") - end - - def test_rightChild_equals - @root << @left_child1 - @root << @right_child1 - assert_same(@right_child1, @root.rightChild, "The right child should be 'right_child1") - - @root.rightChild = Tree::BinaryTreeNode.new("New Right Child") - assert_equal("New Right Child", @root.rightChild.name, "The right child should now be the new child") - assert_equal("A Child at Left", @root.firstChild.name, "The first child should now be the left child") - assert_equal("New Right Child", @root.lastChild.name, "The last child should now be the right child") - - # Now set the right child as nil, and retest - @root.rightChild = nil - assert_nil(@root.rightChild, "The right child should now be nil") - assert_equal("A Child at Left", @root.firstChild.name, "The first child should now be the left child") - assert_nil(@root.lastChild, "The first child is now nil") - end - - def test_isLeftChild_eh - @root << @left_child1 - @root << @right_child1 - - assert(@left_child1.isLeftChild?, "left_child1 should be the left child") - assert(!@right_child1.isLeftChild?, "left_child1 should be the left child") - - # Now set the right child as nil, and retest - @root.rightChild = nil - assert(@left_child1.isLeftChild?, "left_child1 should be the left child") - - assert(!@root.isLeftChild?, "Root is neither left child nor right") - end - - def test_isRightChild_eh - @root << @left_child1 - @root << @right_child1 - - assert(@right_child1.isRightChild?, "right_child1 should be the right child") - assert(!@left_child1.isRightChild?, "right_child1 should be the right child") - - # Now set the left child as nil, and retest - @root.leftChild = nil - assert(@right_child1.isRightChild?, "right_child1 should be the right child") - assert(!@root.isRightChild?, "Root is neither left child nor right") - end - - def test_swap_children - @root << @left_child1 - @root << @right_child1 - - assert(@right_child1.isRightChild?, "right_child1 should be the right child") - assert(!@left_child1.isRightChild?, "right_child1 should be the right child") - - @root.swap_children - - assert(@right_child1.isLeftChild?, "right_child1 should now be the left child") - assert(@left_child1.isRightChild?, "left_child1 should now be the right child") - assert_equal(@right_child1, @root.firstChild, "right_child1 should now be the first child") - assert_equal(@left_child1, @root.lastChild, "left_child1 should now be the last child") - assert_equal(@right_child1, @root[0], "right_child1 should now be the first child") - assert_equal(@left_child1, @root[1], "left_child1 should now be the last child") - end - end -end - -# $Log: test_binarytree.rb,v $ -# Revision 1.5 2007/12/22 00:28:59 anupamsg -# Added more test cases, and enabled ZenTest compatibility. -# -# Revision 1.4 2007/12/18 23:11:29 anupamsg -# Minor documentation changes in the binarytree class. -# -# Revision 1.3 2007/10/02 03:07:30 anupamsg -# * Rakefile: Added an optional task for rcov code coverage. -# -# * test/test_binarytree.rb: Removed the unnecessary dependency on "Person" class. -# -# * test/test_tree.rb: Removed dependency on the redundant "Person" class. -# -# Revision 1.2 2007/08/30 22:06:13 anupamsg -# Added a new swap_children method for the Binary Tree class. -# Also made minor documentation updates and test additions. -# -# Revision 1.1 2007/07/21 04:52:37 anupamsg -# Renamed the test files. -# -# Revision 1.4 2007/07/19 02:03:57 anupamsg -# Minor syntax correction. -# -# Revision 1.3 2007/07/19 02:02:12 anupamsg -# Removed useless files (including rdoc, which should be generated for each release. -# -# Revision 1.2 2007/07/18 20:15:06 anupamsg -# Added two predicate methods in BinaryTreeNode to determine whether a node -# is a left or a right node. -# diff --git a/vendor/gems/rubytree-0.5.2/test/test_tree.rb b/vendor/gems/rubytree-0.5.2/test/test_tree.rb deleted file mode 100644 index d1aa1211..00000000 --- a/vendor/gems/rubytree-0.5.2/test/test_tree.rb +++ /dev/null @@ -1,718 +0,0 @@ -#!/usr/bin/env ruby - -# testtree.rb -# -# $Revision: 1.6 $ by $Author: anupamsg $ -# $Name: $ -# -# Copyright (c) 2006, 2007 Anupam Sengupta -# -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without modification, -# are permitted provided that the following conditions are met: -# -# - Redistributions of source code must retain the above copyright notice, this -# list of conditions and the following disclaimer. -# -# - Redistributions in binary form must reproduce the above copyright notice, this -# list of conditions and the following disclaimer in the documentation and/or -# other materials provided with the distribution. -# -# - Neither the name of the organization nor the names of its contributors may -# be used to endorse or promote products derived from this software without -# specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# - -require 'test/unit' -require 'tree' - -module TestTree - # Test class for the Tree node. - class TestTreeNode < Test::Unit::TestCase - - Person = Struct::new(:First, :last) - - def setup - @root = Tree::TreeNode.new("ROOT", "Root Node") - - @child1 = Tree::TreeNode.new("Child1", "Child Node 1") - @child2 = Tree::TreeNode.new("Child2", "Child Node 2") - @child3 = Tree::TreeNode.new("Child3", "Child Node 3") - @child4 = Tree::TreeNode.new("Child31", "Grand Child 1") - - end - - # Create this structure for the tests - # - # +----------+ - # | ROOT | - # +-+--------+ - # | - # | +---------------+ - # +----+ CHILD1 | - # | +---------------+ - # | - # | +---------------+ - # +----+ CHILD2 | - # | +---------------+ - # | - # | +---------------+ +------------------+ - # +----+ CHILD3 +---+ CHILD4 | - # +---------------+ +------------------+ - # - def loadChildren - @root << @child1 - @root << @child2 - @root << @child3 << @child4 - end - - def teardown - @root = nil - end - - def test_root_setup - assert_not_nil(@root, "Root cannot be nil") - assert_nil(@root.parent, "Parent of root node should be nil") - assert_not_nil(@root.name, "Name should not be nil") - assert_equal("ROOT", @root.name, "Name should be 'ROOT'") - assert_equal("Root Node", @root.content, "Content should be 'Root Node'") - assert(@root.isRoot?, "Should identify as root") - assert(!@root.hasChildren?, "Cannot have any children") - assert(@root.hasContent?, "This root should have content") - assert_equal(1, @root.size, "Number of nodes should be one") - assert_nil(@root.siblings, "Root cannot have any children") - - assert_raise(RuntimeError) { Tree::TreeNode.new(nil) } - end - - def test_root - loadChildren - - assert_same(@root, @root.root, "Root's root is self") - assert_same(@root, @child1.root, "Root should be ROOT") - assert_same(@root, @child4.root, "Root should be ROOT") - end - - def test_hasContent_eh - aNode = Tree::TreeNode.new("A Node") - assert_nil(aNode.content, "The node should not have content") - assert(!aNode.hasContent?, "The node should not have content") - - aNode.content = "Something" - assert_not_nil(aNode.content, "The node should now have content") - assert(aNode.hasContent?, "The node should now have content") - end - - def test_length - loadChildren - assert_equal(@root.size, @root.length, "Length and size methods should return the same result") - end - - def test_spaceship # Test the <=> operator. - firstNode = Tree::TreeNode.new(1) - secondNode = Tree::TreeNode.new(2) - - assert_equal(firstNode <=> nil, +1) - assert_equal(firstNode <=> secondNode, -1) - - secondNode = Tree::TreeNode.new(1) - assert_equal(firstNode <=> secondNode, 0) - - firstNode = Tree::TreeNode.new("ABC") - secondNode = Tree::TreeNode.new("XYZ") - - assert_equal(firstNode <=> nil, +1) - assert_equal(firstNode <=> secondNode, -1) - - secondNode = Tree::TreeNode.new("ABC") - assert_equal(firstNode <=> secondNode, 0) - end - - def test_to_s - aNode = Tree::TreeNode.new("A Node", "Some Content") - - expectedString = "Node Name: A Node Content: Some Content Parent: Children: 0 Total Nodes: 1" - - assert_equal(expectedString, aNode.to_s, "The string representation should be same") - end - - def test_firstSibling - loadChildren - - assert_same(@root, @root.firstSibling, "Root's first sibling is itself") - assert_same(@child1, @child1.firstSibling, "Child1's first sibling is itself") - assert_same(@child1, @child2.firstSibling, "Child2's first sibling should be child1") - assert_same(@child1, @child3.firstSibling, "Child3's first sibling should be child1") - assert_not_same(@child1, @child4.firstSibling, "Child4's first sibling is itself") - end - - def test_isFirstSibling_eh - loadChildren - - assert(@root.isFirstSibling?, "Root's first sibling is itself") - assert( @child1.isFirstSibling?, "Child1's first sibling is itself") - assert(!@child2.isFirstSibling?, "Child2 is not the first sibling") - assert(!@child3.isFirstSibling?, "Child3 is not the first sibling") - assert( @child4.isFirstSibling?, "Child4's first sibling is itself") - end - - def test_isLastSibling_eh - loadChildren - - assert(@root.isLastSibling?, "Root's last sibling is itself") - assert(!@child1.isLastSibling?, "Child1 is not the last sibling") - assert(!@child2.isLastSibling?, "Child2 is not the last sibling") - assert( @child3.isLastSibling?, "Child3's last sibling is itself") - assert( @child4.isLastSibling?, "Child4's last sibling is itself") - end - - def test_lastSibling - loadChildren - - assert_same(@root, @root.lastSibling, "Root's last sibling is itself") - assert_same(@child3, @child1.lastSibling, "Child1's last sibling should be child3") - assert_same(@child3, @child2.lastSibling, "Child2's last sibling should be child3") - assert_same(@child3, @child3.lastSibling, "Child3's last sibling should be itself") - assert_not_same(@child3, @child4.lastSibling, "Child4's last sibling is itself") - end - - def test_siblings - loadChildren - - siblings = [] - @child1.siblings { |sibling| siblings << sibling} - assert_equal(2, siblings.length, "Should have two siblings") - assert(siblings.include?(@child2), "Should have 2nd child as sibling") - assert(siblings.include?(@child3), "Should have 3rd child as sibling") - - siblings.clear - siblings = @child1.siblings - assert_equal(2, siblings.length, "Should have two siblings") - - siblings.clear - @child4.siblings {|sibling| siblings << sibling} - assert(siblings.empty?, "Should not have any children") - - end - - def test_isOnlyChild_eh - loadChildren - - assert(!@child1.isOnlyChild?, "Child1 is not the only child") - assert(!@child2.isOnlyChild?, "Child2 is not the only child") - assert(!@child3.isOnlyChild?, "Child3 is not the only child") - assert( @child4.isOnlyChild?, "Child4 is not the only child") - end - - def test_nextSibling - loadChildren - - assert_equal(@child2, @child1.nextSibling, "Child1's next sibling is Child2") - assert_equal(@child3, @child2.nextSibling, "Child2's next sibling is Child3") - assert_nil(@child3.nextSibling, "Child3 does not have a next sibling") - assert_nil(@child4.nextSibling, "Child4 does not have a next sibling") - end - - def test_previousSibling - loadChildren - - assert_nil(@child1.previousSibling, "Child1 does not have previous sibling") - assert_equal(@child1, @child2.previousSibling, "Child2's previous sibling is Child1") - assert_equal(@child2, @child3.previousSibling, "Child3's previous sibling is Child2") - assert_nil(@child4.previousSibling, "Child4 does not have a previous sibling") - end - - def test_add - assert(!@root.hasChildren?, "Should not have any children") - - @root.add(@child1) - - @root << @child2 - - assert(@root.hasChildren?, "Should have children") - assert_equal(3, @root.size, "Should have three nodes") - - @root << @child3 << @child4 - - assert_equal(5, @root.size, "Should have five nodes") - assert_equal(2, @child3.size, "Should have two nodes") - - assert_raise(RuntimeError) { @root.add(Tree::TreeNode.new(@child1.name)) } - - end - - def test_remove_bang - @root << @child1 - @root << @child2 - - assert(@root.hasChildren?, "Should have children") - assert_equal(3, @root.size, "Should have three nodes") - - @root.remove!(@child1) - assert_equal(2, @root.size, "Should have two nodes") - @root.remove!(@child2) - - assert(!@root.hasChildren?, "Should have no children") - assert_equal(1, @root.size, "Should have one node") - - @root << @child1 - @root << @child2 - - assert(@root.hasChildren?, "Should have children") - assert_equal(3, @root.size, "Should have three nodes") - - @root.removeAll! - - assert(!@root.hasChildren?, "Should have no children") - assert_equal(1, @root.size, "Should have one node") - - end - - def test_removeAll_bang - loadChildren - assert(@root.hasChildren?, "Should have children") - @root.removeAll! - - assert(!@root.hasChildren?, "Should have no children") - assert_equal(1, @root.size, "Should have one node") - end - - def test_removeFromParent_bang - loadChildren - assert(@root.hasChildren?, "Should have children") - assert(!@root.isLeaf?, "Root is not a leaf here") - - child1 = @root[0] - assert_not_nil(child1, "Child 1 should exist") - assert_same(@root, child1.root, "Child 1's root should be ROOT") - assert(@root.include?(child1), "root should have child1") - child1.removeFromParent! - assert_same(child1, child1.root, "Child 1's root should be self") - assert(!@root.include?(child1), "root should not have child1") - - child1.removeFromParent! - assert_same(child1, child1.root, "Child 1's root should still be self") - end - - def test_children - loadChildren - - assert(@root.hasChildren?, "Should have children") - assert_equal(5, @root.size, "Should have four nodes") - assert(@child3.hasChildren?, "Should have children") - assert(!@child3.isLeaf?, "Should not be a leaf") - - children = [] - for child in @root.children - children << child - end - - assert_equal(3, children.length, "Should have three direct children") - assert(!children.include?(@root), "Should not have root") - assert(children.include?(@child1), "Should have child 1") - assert(children.include?(@child2), "Should have child 2") - assert(children.include?(@child3), "Should have child 3") - assert(!children.include?(@child4), "Should not have child 4") - - children.clear - children = @root.children - assert_equal(3, children.length, "Should have three children") - - end - - def test_firstChild - loadChildren - - assert_equal(@child1, @root.firstChild, "Root's first child is Child1") - assert_nil(@child1.firstChild, "Child1 does not have any children") - assert_equal(@child4, @child3.firstChild, "Child3's first child is Child4") - - end - - def test_lastChild - loadChildren - - assert_equal(@child3, @root.lastChild, "Root's last child is Child3") - assert_nil(@child1.lastChild, "Child1 does not have any children") - assert_equal(@child4, @child3.lastChild, "Child3's last child is Child4") - - end - - def test_find - loadChildren - foundNode = @root.find { |node| node == @child2} - assert_same(@child2, foundNode, "The node should be Child 2") - - foundNode = @root.find { |node| node == @child4} - assert_same(@child4, foundNode, "The node should be Child 4") - - foundNode = @root.find { |node| node.name == "Child31" } - assert_same(@child4, foundNode, "The node should be Child 4") - foundNode = @root.find { |node| node.name == "NOT PRESENT" } - assert_nil(foundNode, "The node should not be found") - end - - def test_parentage - loadChildren - - assert_nil(@root.parentage, "Root does not have any parentage") - assert_equal([@root], @child1.parentage, "Child1 has Root as its parent") - assert_equal([@child3, @root], @child4.parentage, "Child4 has Child3 and Root as ancestors") - end - - def test_each - loadChildren - assert(@root.hasChildren?, "Should have children") - assert_equal(5, @root.size, "Should have five nodes") - assert(@child3.hasChildren?, "Should have children") - - nodes = [] - @root.each { |node| nodes << node } - - assert_equal(5, nodes.length, "Should have FIVE NODES") - assert(nodes.include?(@root), "Should have root") - assert(nodes.include?(@child1), "Should have child 1") - assert(nodes.include?(@child2), "Should have child 2") - assert(nodes.include?(@child3), "Should have child 3") - assert(nodes.include?(@child4), "Should have child 4") - end - - def test_each_leaf - loadChildren - - nodes = [] - @root.each_leaf { |node| nodes << node } - - assert_equal(3, nodes.length, "Should have THREE LEAF NODES") - assert(!nodes.include?(@root), "Should not have root") - assert(nodes.include?(@child1), "Should have child 1") - assert(nodes.include?(@child2), "Should have child 2") - assert(!nodes.include?(@child3), "Should not have child 3") - assert(nodes.include?(@child4), "Should have child 4") - end - - def test_parent - loadChildren - assert_nil(@root.parent, "Root's parent should be nil") - assert_equal(@root, @child1.parent, "Parent should be root") - assert_equal(@root, @child3.parent, "Parent should be root") - assert_equal(@child3, @child4.parent, "Parent should be child3") - assert_equal(@root, @child4.parent.parent, "Parent should be root") - end - - def test_indexed_access - loadChildren - assert_equal(@child1, @root[0], "Should be the first child") - assert_equal(@child4, @root[2][0], "Should be the grandchild") - assert_nil(@root["TEST"], "Should be nil") - assert_raise(RuntimeError) { @root[nil] } - end - - def test_printTree - loadChildren - #puts - #@root.printTree - end - - # Tests the binary dumping mechanism with an Object content node - def test_marshal_dump - # Setup Test Data - test_root = Tree::TreeNode.new("ROOT", "Root Node") - test_content = {"KEY1" => "Value1", "KEY2" => "Value2" } - test_child = Tree::TreeNode.new("Child", test_content) - test_content2 = ["AValue1", "AValue2", "AValue3"] - test_grand_child = Tree::TreeNode.new("Grand Child 1", test_content2) - test_root << test_child << test_grand_child - - # Perform the test operation - data = Marshal.dump(test_root) # Marshal - new_root = Marshal.load(data) # And unmarshal - - # Test the root node - assert_equal(test_root.name, new_root.name, "Must identify as ROOT") - assert_equal(test_root.content, new_root.content, "Must have root's content") - assert(new_root.isRoot?, "Must be the ROOT node") - assert(new_root.hasChildren?, "Must have a child node") - - # Test the child node - new_child = new_root[test_child.name] - assert_equal(test_child.name, new_child.name, "Must have child 1") - assert(new_child.hasContent?, "Child must have content") - assert(new_child.isOnlyChild?, "Child must be the only child") - - new_child_content = new_child.content - assert_equal(Hash, new_child_content.class, "Class of child's content should be a hash") - assert_equal(test_child.content.size, new_child_content.size, "The content should have same size") - - # Test the grand-child node - new_grand_child = new_child[test_grand_child.name] - assert_equal(test_grand_child.name, new_grand_child.name, "Must have grand child") - assert(new_grand_child.hasContent?, "Grand-child must have content") - assert(new_grand_child.isOnlyChild?, "Grand-child must be the only child") - - new_grand_child_content = new_grand_child.content - assert_equal(Array, new_grand_child_content.class, "Class of grand-child's content should be an Array") - assert_equal(test_grand_child.content.size, new_grand_child_content.size, "The content should have same size") - end - - # marshal_load and marshal_dump are symmetric methods - # This alias is for satisfying ZenTest - alias test_marshal_load test_marshal_dump - - # Test the collect method from the mixed-in Enumerable functionality. - def test_collect - loadChildren - collectArray = @root.collect do |node| - node.content = "abc" - node - end - collectArray.each {|node| assert_equal("abc", node.content, "Should be 'abc'")} - end - - # Test freezing the tree - def test_freezeTree_bang - loadChildren - @root.content = "ABC" - assert_equal("ABC", @root.content, "Content should be 'ABC'") - @root.freezeTree! - assert_raise(TypeError) {@root.content = "123"} - assert_raise(TypeError) {@root[0].content = "123"} - end - - # Test whether the content is accesible - def test_content - pers = Person::new("John", "Doe") - @root.content = pers - assert_same(pers, @root.content, "Content should be the same") - end - - # Test the depth computation algorithm - def test_depth - assert_equal(1, @root.depth, "A single node's depth is 1") - - @root << @child1 - assert_equal(2, @root.depth, "This should be of depth 2") - - @root << @child2 - assert_equal(2, @root.depth, "This should be of depth 2") - - @child2 << @child3 - assert_equal(3, @root.depth, "This should be of depth 3") - assert_equal(2, @child2.depth, "This should be of depth 2") - - @child3 << @child4 - assert_equal(4, @root.depth, "This should be of depth 4") - end - - # Test the breadth computation algorithm - def test_breadth - assert_equal(1, @root.breadth, "A single node's breadth is 1") - - @root << @child1 - assert_equal(1, @root.breadth, "This should be of breadth 1") - - @root << @child2 - assert_equal(2, @child1.breadth, "This should be of breadth 2") - assert_equal(2, @child2.breadth, "This should be of breadth 2") - - @root << @child3 - assert_equal(3, @child1.breadth, "This should be of breadth 3") - assert_equal(3, @child2.breadth, "This should be of breadth 3") - - @child3 << @child4 - assert_equal(1, @child4.breadth, "This should be of breadth 1") - end - - # Test the breadth for each - def test_breadth_each - j = Tree::TreeNode.new("j") - f = Tree::TreeNode.new("f") - k = Tree::TreeNode.new("k") - a = Tree::TreeNode.new("a") - d = Tree::TreeNode.new("d") - h = Tree::TreeNode.new("h") - z = Tree::TreeNode.new("z") - - # The expected order of response - expected_array = [j, - f, k, - a, h, z, - d] - - # Create the following Tree - # j <-- level 0 (Root) - # / \ - # f k <-- level 1 - # / \ \ - # a h z <-- level 2 - # \ - # d <-- level 3 - j << f << a << d - f << h - j << k << z - - # Create the response - result_array = Array.new - j.breadth_each { |node| result_array << node.detached_copy } - - expected_array.each_index do |i| - assert_equal(expected_array[i].name, result_array[i].name) # Match only the names. - end - end - - - def test_preordered_each - j = Tree::TreeNode.new("j") - f = Tree::TreeNode.new("f") - k = Tree::TreeNode.new("k") - a = Tree::TreeNode.new("a") - d = Tree::TreeNode.new("d") - h = Tree::TreeNode.new("h") - z = Tree::TreeNode.new("z") - - # The expected order of response - expected_array = [j, f, a, d, h, k, z] - - # Create the following Tree - # j <-- level 0 (Root) - # / \ - # f k <-- level 1 - # / \ \ - # a h z <-- level 2 - # \ - # d <-- level 3 - j << f << a << d - f << h - j << k << z - - result_array = [] - j.preordered_each { |node| result_array << node.detached_copy} - - expected_array.each_index do |i| - # Match only the names. - assert_equal(expected_array[i].name, result_array[i].name) - end - end - - def test_detached_copy - loadChildren - - assert(@root.hasChildren?, "The root should have children") - copy_of_root = @root.detached_copy - assert(!copy_of_root.hasChildren?, "The copy should not have children") - assert_equal(@root.name, copy_of_root.name, "The names should be equal") - - # Try the same test with a child node - assert(!@child3.isRoot?, "Child 3 is not a root") - assert(@child3.hasChildren?, "Child 3 has children") - copy_of_child3 = @child3.detached_copy - assert(copy_of_child3.isRoot?, "Child 3's copy is a root") - assert(!copy_of_child3.hasChildren?, "Child 3's copy does not have children") - end - - def test_hasChildren_eh - loadChildren - assert(@root.hasChildren?, "The Root node MUST have children") - end - - def test_isLeaf_eh - loadChildren - assert(!@child3.isLeaf?, "Child 3 is not a leaf node") - assert(@child4.isLeaf?, "Child 4 is a leaf node") - end - - def test_isRoot_eh - loadChildren - assert(@root.isRoot?, "The ROOT node must respond as the root node") - end - - def test_content_equals - @root.content = nil - assert_nil(@root.content, "Root's content should be nil") - @root.content = "ABCD" - assert_equal("ABCD", @root.content, "Root's content should now be 'ABCD'") - end - - def test_size - assert_equal(1, @root.size, "Root's size should be 1") - loadChildren - assert_equal(5, @root.size, "Root's size should be 5") - assert_equal(2, @child3.size, "Child 3's size should be 2") - end - - def test_lt2 # Test the << method - @root << @child1 - @root << @child2 - @root << @child3 << @child4 - assert_not_nil(@root['Child1'], "Child 1 should have been added to Root") - assert_not_nil(@root['Child2'], "Child 2 should have been added to Root") - assert_not_nil(@root['Child3'], "Child 3 should have been added to Root") - assert_not_nil(@child3['Child31'], "Child 31 should have been added to Child3") - end - - def test_index # Test the [] method - assert_raise(RuntimeError) {@root[nil]} - - @root << @child1 - @root << @child2 - assert_equal(@child1.name, @root['Child1'].name, "Child 1 should be returned") - assert_equal(@child1.name, @root[0].name, "Child 1 should be returned") - assert_equal(@child2.name, @root['Child2'].name, "Child 2 should be returned") - assert_equal(@child2.name, @root[1].name, "Child 2 should be returned") - - assert_nil(@root['Some Random Name'], "Should return nil") - assert_nil(@root[99], "Should return nil") - end - end -end - -__END__ - -# $Log: test_tree.rb,v $ -# Revision 1.6 2007/12/22 00:28:59 anupamsg -# Added more test cases, and enabled ZenTest compatibility. -# -# Revision 1.5 2007/12/19 02:24:18 anupamsg -# Updated the marshalling logic to handle non-string contents on the nodes. -# -# Revision 1.4 2007/10/02 03:38:11 anupamsg -# Removed dependency on the redundant "Person" class. -# (TC_TreeTest::test_comparator): Added a new test for the spaceship operator. -# (TC_TreeTest::test_hasContent): Added tests for hasContent? and length methods. -# -# Revision 1.3 2007/10/02 03:07:30 anupamsg -# * Rakefile: Added an optional task for rcov code coverage. -# -# * test/test_binarytree.rb: Removed the unnecessary dependency on "Person" class. -# -# * test/test_tree.rb: Removed dependency on the redundant "Person" class. -# -# Revision 1.2 2007/08/31 01:16:28 anupamsg -# Added breadth and pre-order traversals for the tree. Also added a method -# to return the detached copy of a node from the tree. -# -# Revision 1.1 2007/07/21 04:52:38 anupamsg -# Renamed the test files. -# -# Revision 1.13 2007/07/18 22:11:50 anupamsg -# Added depth and breadth methods for the TreeNode. -# -# Revision 1.12 2007/07/18 07:17:34 anupamsg -# Fixed a issue where TreeNode.ancestors was shadowing Module.ancestors. This method -# has been renamed to TreeNode.parentage. -# -# Revision 1.11 2007/07/17 03:39:29 anupamsg -# Moved the CVS Log keyword to end of the files. -# From 8304c6847a4985e883f14306af5bc43bdf896f01 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Sat, 19 Mar 2011 16:04:43 +0100 Subject: [PATCH 644/777] [#290] loading mocha after shoulda to make sure, that mocha's patches can be properly applied --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index eb961436..9d5560d3 100644 --- a/Gemfile +++ b/Gemfile @@ -8,9 +8,9 @@ gem "ruby-openid" gem "rubytree", "~> 0.5.2", :require => 'tree' group :development, :test do + gem 'shoulda', '~> 2.10.3' gem 'edavis10-object_daddy', :require => 'object_daddy' gem 'mocha' - gem 'shoulda', '~> 2.10.3' end From ddcec2f4a0d822df9ca0bdb99cdc5e02319f40fd Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Sat, 19 Mar 2011 17:03:58 +0100 Subject: [PATCH 645/777] [#290] making openid opt-out by adding it to a group --- Gemfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 9d5560d3..196da5f7 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,6 @@ gem "rails", "2.3.11" gem "coderay", "~> 0.9.7" gem "i18n", "< 0.5" # explicit version 0.4.2 is used in config! -gem "ruby-openid" gem "rubytree", "~> 0.5.2", :require => 'tree' group :development, :test do @@ -13,6 +12,9 @@ group :development, :test do gem 'mocha' end +group :openid do + gem "ruby-openid", '~> 2.1.4', :require => 'openid' +end # Use the commented pure ruby gems, if you have not the needed prerequisites on # board to compile the native ones. Note, that their use is discouraged, since From 326dffbc2900e37a3db207c902d07ea70730976d Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Sat, 19 Mar 2011 17:12:29 +0100 Subject: [PATCH 646/777] [#290] Adding rmagick, making it opt-out using version < 2.0 since later versions do not work w/o backports on Debian Lenny --- Gemfile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Gemfile b/Gemfile index 196da5f7..7289f612 100644 --- a/Gemfile +++ b/Gemfile @@ -16,6 +16,10 @@ group :openid do gem "ruby-openid", '~> 2.1.4', :require => 'openid' end +group :rmagick do + gem "rmagick", "~> 1.15.17" +end + # Use the commented pure ruby gems, if you have not the needed prerequisites on # board to compile the native ones. Note, that their use is discouraged, since # their integration is propbably not that well tested and their are slower in From cbc26ea982c6ddd65ca0169ef7dc7900b9befde4 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Sat, 19 Mar 2011 22:36:39 +0100 Subject: [PATCH 647/777] [#290] Remove test gems from dev enviroment. running single test without RAILS_ENV=test prefix seams to work without it. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 7289f612..96c4900c 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ gem "coderay", "~> 0.9.7" gem "i18n", "< 0.5" # explicit version 0.4.2 is used in config! gem "rubytree", "~> 0.5.2", :require => 'tree' -group :development, :test do +group :test do gem 'shoulda', '~> 2.10.3' gem 'edavis10-object_daddy', :require => 'object_daddy' gem 'mocha' From a0eb66fc981ef62cd26d8e22302ad75f038b8a84 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Sat, 19 Mar 2011 22:38:03 +0100 Subject: [PATCH 648/777] [#290] using ~> instead of < for i18n dependency it is more accurate in this case --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 96c4900c..a116810d 100644 --- a/Gemfile +++ b/Gemfile @@ -3,7 +3,7 @@ source :rubygems gem "rails", "2.3.11" gem "coderay", "~> 0.9.7" -gem "i18n", "< 0.5" # explicit version 0.4.2 is used in config! +gem "i18n", "~> 0.4.2" gem "rubytree", "~> 0.5.2", :require => 'tree' group :test do From ddcd4f2888e626d2866cbbe1d2299035428f27a6 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Tue, 10 May 2011 08:42:37 +0200 Subject: [PATCH 649/777] Pinning mysql2 gem to 0.2 branch, since 0.3 and the following are Rails 3 only --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index a116810d..02063034 100644 --- a/Gemfile +++ b/Gemfile @@ -33,7 +33,7 @@ platforms :mri do end group :mysql2 do - gem "mysql2" + gem "mysql2", "~> 0.2.7" end group :postgres do From c2d058a53bd0f5e4c7d5fed0a88adad5bd0e5e72 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Wed, 11 May 2011 00:19:11 +0200 Subject: [PATCH 650/777] [#390] check to handle mysql2's early type casting --- app/models/wiki_page.rb | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/models/wiki_page.rb b/app/models/wiki_page.rb index 923f381b..3a6cebec 100644 --- a/app/models/wiki_page.rb +++ b/app/models/wiki_page.rb @@ -131,7 +131,10 @@ class WikiPage < ActiveRecord::Base unless @updated_on if time = read_attribute(:updated_on) # content updated_on was eager loaded with the page - @updated_on = Time.parse(time) rescue nil + unless time.is_a? Time + time = Time.parse(time) rescue nil + end + @updated_on = time else @updated_on = content && content.updated_on end From f27614b576266848c8dc0c96fdac65e4218c3980 Mon Sep 17 00:00:00 2001 From: Adam Soltys Date: Wed, 11 May 2011 15:34:26 -0600 Subject: [PATCH 651/777] make username a link to their profile page --- app/views/my/_sidebar.rhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/my/_sidebar.rhtml b/app/views/my/_sidebar.rhtml index 2089feea..e7689c13 100644 --- a/app/views/my/_sidebar.rhtml +++ b/app/views/my/_sidebar.rhtml @@ -1,6 +1,6 @@

    <%=l(:label_my_account)%>

    -

    <%=l(:field_login)%>: <%= @user.login %>
    +

    <%=l(:field_login)%>: <%= link_to @user.login, user_path(@user) %>
    <%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>

    From 315ec5f65cd6f18d313d06de96f610ffea92866a Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 11 May 2011 15:39:07 -0700 Subject: [PATCH 652/777] HTML escape some user values --- app/views/my/_sidebar.rhtml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/my/_sidebar.rhtml b/app/views/my/_sidebar.rhtml index e7689c13..cc4a7850 100644 --- a/app/views/my/_sidebar.rhtml +++ b/app/views/my/_sidebar.rhtml @@ -1,6 +1,6 @@

    <%=l(:label_my_account)%>

    -

    <%=l(:field_login)%>: <%= link_to @user.login, user_path(@user) %>
    +

    <%=l(:field_login)%>: <%= link_to(h(@user.login), user_path(@user) %>
    <%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>

    @@ -19,7 +19,7 @@

    <%= l(:label_api_access_key) %>

    <%= link_to_function(l(:button_show), "$('api-access-key').toggle();")%> -
    <%= @user.api_key %>
    +
    <%= h(@user.api_key) %>
    <%= javascript_tag("$('api-access-key').hide();") %>

    From 90df645cae9734d70c0996d2a0f4b657d33b8de4 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 11 May 2011 15:40:55 -0700 Subject: [PATCH 653/777] Use link_to_user instead of a manual link --- app/views/my/_sidebar.rhtml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/my/_sidebar.rhtml b/app/views/my/_sidebar.rhtml index cc4a7850..407fe990 100644 --- a/app/views/my/_sidebar.rhtml +++ b/app/views/my/_sidebar.rhtml @@ -1,6 +1,6 @@

    <%=l(:label_my_account)%>

    -

    <%=l(:field_login)%>: <%= link_to(h(@user.login), user_path(@user) %>
    +

    <%=l(:field_login)%>: <%= link_to_user(@user, :format => :username) %>
    <%=l(:field_created_on)%>: <%= format_time(@user.created_on) %>

    From f273b7b18c2b5b1415656abec43515c69e0a9d58 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Wed, 11 May 2011 15:48:36 -0700 Subject: [PATCH 654/777] Create the ChiliProject namespace --- config/initializers/30-redmine.rb | 1 + lib/chili_project.rb | 2 ++ lib/chili_project/.empty | 0 3 files changed, 3 insertions(+) create mode 100644 lib/chili_project.rb create mode 100644 lib/chili_project/.empty diff --git a/config/initializers/30-redmine.rb b/config/initializers/30-redmine.rb index 708dcd65..23989ed2 100644 --- a/config/initializers/30-redmine.rb +++ b/config/initializers/30-redmine.rb @@ -3,3 +3,4 @@ I18n.default_locale = 'en' I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) require 'redmine' +require 'chili_project' diff --git a/lib/chili_project.rb b/lib/chili_project.rb new file mode 100644 index 00000000..e27cbf86 --- /dev/null +++ b/lib/chili_project.rb @@ -0,0 +1,2 @@ +module ChiliProject +end diff --git a/lib/chili_project/.empty b/lib/chili_project/.empty new file mode 100644 index 00000000..e69de29b From 68925684fef747552bd3109edbcd0fbb6490cb86 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 09:16:46 -0700 Subject: [PATCH 655/777] Remove generic Rails performance test --- test/performance/browsing_test.rb | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 test/performance/browsing_test.rb diff --git a/test/performance/browsing_test.rb b/test/performance/browsing_test.rb deleted file mode 100644 index 4b60558b..00000000 --- a/test/performance/browsing_test.rb +++ /dev/null @@ -1,9 +0,0 @@ -require 'test_helper' -require 'performance_test_help' - -# Profiling results for each test method are written to tmp/performance. -class BrowsingTest < ActionController::PerformanceTest - def test_homepage - get '/' - end -end From cff4e83044f02dd9147fef360b816c29f5b1da10 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 09:17:29 -0700 Subject: [PATCH 656/777] [#290] Only print the plugin Gemfile messages when $DEBUG is set --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 02063034..28fd75b5 100644 --- a/Gemfile +++ b/Gemfile @@ -65,6 +65,6 @@ end # Load plugins' Gemfiles Dir.glob File.expand_path("../vendor/plugins/*/Gemfile", __FILE__) do |file| - puts "Loading #{file} ..." + puts "Loading #{file} ..." if $DEBUG # `ruby -d` or `bundle -v` instance_eval File.read(file) end From 62c9fd218590a009850fa6e7ab1fc6a0be559b3b Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 09:49:56 -0700 Subject: [PATCH 657/777] [#123] Removed the acts_as_journalized submodule --- .gitmodules | 3 --- vendor/plugins/acts_as_journalized | 1 - 2 files changed, 4 deletions(-) delete mode 160000 vendor/plugins/acts_as_journalized diff --git a/.gitmodules b/.gitmodules index dec27a61..e69de29b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "vendor/plugins/acts_as_journalized"] - path = vendor/plugins/acts_as_journalized - url = git://github.com/finnlabs/acts_as_journalized diff --git a/vendor/plugins/acts_as_journalized b/vendor/plugins/acts_as_journalized deleted file mode 160000 index 0b242548..00000000 --- a/vendor/plugins/acts_as_journalized +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0b242548a3b45b6ef5b26ab225bf23b7b7f8e490 From b1845fcfebb6f6827933bca61c41191f64e41be9 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 09:55:55 -0700 Subject: [PATCH 658/777] [#123] Added latest edavis10:acts_as_journalized --- vendor/plugins/acts_as_journalized/.gitignore | 22 ++ vendor/plugins/acts_as_journalized/GPL.txt | 339 ++++++++++++++++++ vendor/plugins/acts_as_journalized/LICENSE | 87 +++++ .../plugins/acts_as_journalized/README.rdoc | 3 + vendor/plugins/acts_as_journalized/REVISION | 1 + .../app/controllers/journals_controller.rb | 45 +++ .../app/helpers/journals_helper.rb | 128 +++++++ .../acts_as_journalized/app/models/journal.rb | 111 ++++++ .../app/models/journal_observer.rb | 33 ++ .../app/views/journals/_notes_form.rhtml | 8 + .../app/views/journals/edit.rjs | 3 + .../app/views/journals/update.rjs | 11 + .../20100714111651_generalize_journals.rb | 119 ++++++ ...12053_merge_wiki_versions_with_journals.rb | 49 +++ vendor/plugins/acts_as_journalized/init.rb | 17 + .../lib/acts_as_journalized.rb | 181 ++++++++++ .../lib/journal_deprecated.rb | 49 +++ .../lib/journal_formatter.rb | 190 ++++++++++ .../lib/redmine/acts/journalized/changes.rb | 162 +++++++++ .../redmine/acts/journalized/configuration.rb | 77 ++++ .../lib/redmine/acts/journalized/creation.rb | 127 +++++++ .../redmine/acts/journalized/deprecated.rb | 68 ++++ .../redmine/acts/journalized/format_hooks.rb | 42 +++ .../lib/redmine/acts/journalized/options.rb | 81 +++++ .../redmine/acts/journalized/permissions.rb | 36 ++ .../lib/redmine/acts/journalized/reload.rb | 60 ++++ .../lib/redmine/acts/journalized/reset.rb | 65 ++++ .../lib/redmine/acts/journalized/reversion.rb | 110 ++++++ .../redmine/acts/journalized/save_hooks.rb | 115 ++++++ .../lib/redmine/acts/journalized/users.rb | 86 +++++ .../lib/redmine/acts/journalized/versioned.rb | 67 ++++ .../lib/redmine/acts/journalized/versions.rb | 111 ++++++ .../acts_as_journalized/test/changes_test.rb | 169 +++++++++ .../test/conditions_test.rb | 137 +++++++ .../test/configuration_test.rb | 39 ++ .../acts_as_journalized/test/control_test.rb | 152 ++++++++ .../acts_as_journalized/test/creation_test.rb | 110 ++++++ .../acts_as_journalized/test/options_test.rb | 52 +++ .../acts_as_journalized/test/reload_test.rb | 19 + .../acts_as_journalized/test/reset_test.rb | 112 ++++++ .../test/reversion_test.rb | 68 ++++ .../acts_as_journalized/test/schema.rb | 43 +++ .../acts_as_journalized/test/tagging_test.rb | 39 ++ .../acts_as_journalized/test/test_helper.rb | 11 + .../acts_as_journalized/test/users_test.rb | 25 ++ .../acts_as_journalized/test/version_test.rb | 43 +++ .../test/versioned_test.rb | 18 + .../acts_as_journalized/test/versions_test.rb | 172 +++++++++ 48 files changed, 3812 insertions(+) create mode 100644 vendor/plugins/acts_as_journalized/.gitignore create mode 100644 vendor/plugins/acts_as_journalized/GPL.txt create mode 100644 vendor/plugins/acts_as_journalized/LICENSE create mode 100644 vendor/plugins/acts_as_journalized/README.rdoc create mode 100644 vendor/plugins/acts_as_journalized/REVISION create mode 100644 vendor/plugins/acts_as_journalized/app/controllers/journals_controller.rb create mode 100644 vendor/plugins/acts_as_journalized/app/helpers/journals_helper.rb create mode 100644 vendor/plugins/acts_as_journalized/app/models/journal.rb create mode 100644 vendor/plugins/acts_as_journalized/app/models/journal_observer.rb create mode 100644 vendor/plugins/acts_as_journalized/app/views/journals/_notes_form.rhtml create mode 100644 vendor/plugins/acts_as_journalized/app/views/journals/edit.rjs create mode 100644 vendor/plugins/acts_as_journalized/app/views/journals/update.rjs create mode 100644 vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb create mode 100644 vendor/plugins/acts_as_journalized/db/migrate/20100804112053_merge_wiki_versions_with_journals.rb create mode 100644 vendor/plugins/acts_as_journalized/init.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/journal_deprecated.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/journal_formatter.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/changes.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/configuration.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/creation.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/format_hooks.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/options.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reload.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reset.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reversion.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/save_hooks.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/users.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versioned.rb create mode 100644 vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versions.rb create mode 100644 vendor/plugins/acts_as_journalized/test/changes_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/conditions_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/configuration_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/control_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/creation_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/options_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/reload_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/reset_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/reversion_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/schema.rb create mode 100644 vendor/plugins/acts_as_journalized/test/tagging_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/test_helper.rb create mode 100644 vendor/plugins/acts_as_journalized/test/users_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/version_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/versioned_test.rb create mode 100644 vendor/plugins/acts_as_journalized/test/versions_test.rb diff --git a/vendor/plugins/acts_as_journalized/.gitignore b/vendor/plugins/acts_as_journalized/.gitignore new file mode 100644 index 00000000..460367e9 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/.gitignore @@ -0,0 +1,22 @@ +## MAC OS +.DS_Store + +## TEXTMATE +*.tmproj +tmtags + +## EMACS +*~ +\#* +.\#* + +## VIM +*.swp + +## PROJECT::GENERAL +coverage +rdoc +pkg + +## PROJECT::SPECIFIC +*.db diff --git a/vendor/plugins/acts_as_journalized/GPL.txt b/vendor/plugins/acts_as_journalized/GPL.txt new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/vendor/plugins/acts_as_journalized/GPL.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/vendor/plugins/acts_as_journalized/LICENSE b/vendor/plugins/acts_as_journalized/LICENSE new file mode 100644 index 00000000..9a6cbf09 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/LICENSE @@ -0,0 +1,87 @@ +"Acts_as_journalized" is a Redmine core plugin derived from the vestal_versions +Ruby on Rails plugin. The parts are under different copyright and license conditions +noted below. + +The overall license terms applying to "Acts_as_journalized" as in +this distribution are the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 of +the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + + +For the individual files, the following copyrights and licenses apply: + +app/controllers/** +app/views/** +app/helpers/** +app/models/journal_observer.rb + Copyright (C) 2006-2008 Jean-Philippe Lang + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +lib/acts_as_journalized.rb +lib/journal_formatter.rb +lib/redmine/acts/journalized/permissions.rb +lib/redmine/acts/journalized/save_hooks.rb +lib/redmine/acts/journalized/format_hooks.rb +lib/redmine/acts/journalized/deprecated.rb + Copyright (c) 2010 Finn GmbH + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +All remaining files are: + Copyright (c) 2009 Steve Richert + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/vendor/plugins/acts_as_journalized/README.rdoc b/vendor/plugins/acts_as_journalized/README.rdoc new file mode 100644 index 00000000..b7d0440a --- /dev/null +++ b/vendor/plugins/acts_as_journalized/README.rdoc @@ -0,0 +1,3 @@ +acts as journalized + +A redmine core plugin for unification of journals, events and activities in redmine diff --git a/vendor/plugins/acts_as_journalized/REVISION b/vendor/plugins/acts_as_journalized/REVISION new file mode 100644 index 00000000..a7286ae3 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/REVISION @@ -0,0 +1 @@ +67a8c4bee0a06420f1ba64eb9906a15d63bf5ac5 https://github.com/edavis10/acts_as_journalized diff --git a/vendor/plugins/acts_as_journalized/app/controllers/journals_controller.rb b/vendor/plugins/acts_as_journalized/app/controllers/journals_controller.rb new file mode 100644 index 00000000..6ea072a5 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/app/controllers/journals_controller.rb @@ -0,0 +1,45 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2006-2008 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either journal 2 +# of the License, or (at your option) any later journal. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class JournalsController < ApplicationController + unloadable + before_filter :find_journal + + def edit + if request.post? + @journal.update_attribute(:notes, params[:notes]) if params[:notes] + @journal.destroy if @journal.details.empty? && @journal.notes.blank? + call_hook(:controller_journals_edit_post, { :journal => @journal, :params => params}) + respond_to do |format| + format.html { redirect_to :controller => @journal.journaled.class.name.pluralize.downcase, + :action => 'show', :id => @journal.journaled_id } + format.js { render :action => 'update' } + end + end + end + +private + def find_journal + @journal = Journal.find(params[:id]) + (render_403; return false) unless @journal.editable_by?(User.current) + @project = @journal.project + rescue ActiveRecord::RecordNotFound + render_404 + end +end diff --git a/vendor/plugins/acts_as_journalized/app/helpers/journals_helper.rb b/vendor/plugins/acts_as_journalized/app/helpers/journals_helper.rb new file mode 100644 index 00000000..10785fe6 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/app/helpers/journals_helper.rb @@ -0,0 +1,128 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2006-2008 Jean-Philippe Lang +# Copyright (C) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either journal 2 +# of the License, or (at your option) any later journal. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module JournalsHelper + unloadable + include ApplicationHelper + include ActionView::Helpers::TagHelper + + def self.included(base) + base.class_eval do + if respond_to? :before_filter + before_filter :find_optional_journal, :only => [:edit] + end + end + end + + def render_journal(model, journal, options = {}) + return "" if journal.initial? + journal_content = render_journal_details(journal, :label_updated_time_by) + journal_content += render_notes(model, journal, options) unless journal.notes.blank? + content_tag "div", journal_content, { :id => "change-#{journal.id}", :class => journal.css_classes } + end + + # This renders a journal entry wiht a header and details + def render_journal_details(journal, header_label = :label_updated_time_by) + header = <<-HTML +

    +
    #{link_to "##{journal.anchor}", :anchor => "note-#{journal.anchor}"}
    + #{avatar(journal.user, :size => "24")} + #{content_tag('a', '', :name => "note-#{journal.anchor}")} + #{authoring journal.created_at, journal.user, :label => header_label} +

    + HTML + + if journal.details.any? + details = content_tag "ul", :class => "details" do + journal.details.collect do |detail| + if d = journal.render_detail(detail) + content_tag("li", d) + end + end.compact + end + end + + content_tag("div", "#{header}#{details}", :id => "change-#{journal.id}", :class => "journal") + end + + def render_notes(model, journal, options={}) + controller = model.class.name.downcase.pluralize + action = 'edit' + reply_links = authorize_for(controller, action) + + if User.current.logged? + editable = User.current.allowed_to?(options[:edit_permission], journal.project) if options[:edit_permission] + if journal.user == User.current && options[:edit_own_permission] + editable ||= User.current.allowed_to?(options[:edit_own_permission], journal.project) + end + end + + unless journal.notes.blank? + links = returning [] do |l| + if reply_links + l << link_to_remote(image_tag('comment.png'), :title => l(:button_quote), + :url => {:controller => controller, :action => action, :id => model, :journal_id => journal}) + end + if editable + l << link_to_in_place_notes_editor(image_tag('edit.png'), "journal-#{journal.id}-notes", + { :controller => 'journals', :action => 'edit', :id => journal }, + :title => l(:button_edit)) + end + end + end + + content = '' + content << content_tag('div', links.join(' '), :class => 'contextual') unless links.empty? + content << textilizable(journal, :notes) + + css_classes = "wiki" + css_classes << " editable" if editable + + content_tag('div', content, :id => "journal-#{journal.id}-notes", :class => css_classes) + end + + def link_to_in_place_notes_editor(text, field_id, url, options={}) + onclick = "new Ajax.Request('#{url_for(url)}', {asynchronous:true, evalScripts:true, method:'get'}); return false;" + link_to text, '#', options.merge(:onclick => onclick) + end + + # This may conveniently be used by controllers to find journals referred to in the current request + def find_optional_journal + @journal = Journal.find_by_id(params[:journal_id]) + end + + def render_reply(journal) + user = journal.user + text = journal.notes + + # Replaces pre blocks with [...] + text = text.to_s.strip.gsub(%r{
    ((.|\s)*?)
    }m, '[...]') + content = "#{ll(Setting.default_language, :text_user_wrote, user)}\n> " + content << text.gsub(/(\r?\n|\r\n?)/, "\n> ") + "\n\n" + + render(:update) do |page| + page << "$('notes').value = \"#{escape_javascript content}\";" + page.show 'update' + page << "Form.Element.focus('notes');" + page << "Element.scrollTo('update');" + page << "$('notes').scrollTop = $('notes').scrollHeight - $('notes').clientHeight;" + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_journalized/app/models/journal.rb b/vendor/plugins/acts_as_journalized/app/models/journal.rb new file mode 100644 index 00000000..fff8b968 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/app/models/journal.rb @@ -0,0 +1,111 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (c) 2009 Steve Richert +# Copyright (c) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either journal 2 +# of the License, or (at your option) any later journal. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require_dependency 'journal_formatter' + +# The ActiveRecord model representing journals. +class Journal < ActiveRecord::Base + unloadable + + include Comparable + include JournalFormatter + include JournalDeprecated + + # Make sure each journaled model instance only has unique version ids + validates_uniqueness_of :version, :scope => [:journaled_id, :type] + belongs_to :journaled + belongs_to :user + + # ActiveRecord::Base#changes is an existing method, so before serializing the +changes+ column, + # the existing +changes+ method is undefined. The overridden +changes+ method pertained to + # dirty attributes, but will not affect the partial updates functionality as that's based on + # an underlying +changed_attributes+ method, not +changes+ itself. + # undef_method :changes + serialize :changes, Hash + + # In conjunction with the included Comparable module, allows comparison of journal records + # based on their corresponding version numbers, creation timestamps and IDs. + def <=>(other) + [version, created_at, id].map(&:to_i) <=> [other.version, other.created_at, other.id].map(&:to_i) + end + + # Returns whether the version has a version number of 1. Useful when deciding whether to ignore + # the version during reversion, as initial versions have no serialized changes attached. Helps + # maintain backwards compatibility. + def initial? + version < 2 + end + + # The anchor number for html output + def anchor + version - 1 + end + + # Possible shortcut to the associated project + def project + if journaled.respond_to?(:project) + journaled.project + elsif journaled.is_a? Project + journaled + else + nil + end + end + + def editable_by?(user) + journaled.journal_editable_by?(user) + end + + def details + attributes["changes"] || {} + end + + alias_method :changes, :details + + def new_value_for(prop) + details[prop.to_s].last if details.keys.include? prop.to_s + end + + def old_value_for(prop) + details[prop.to_s].first if details.keys.include? prop.to_s + end + + # Returns a string of css classes + def css_classes + s = 'journal' + s << ' has-notes' unless notes.blank? + s << ' has-details' unless details.empty? + s + end + + # This is here to allow people to disregard the difference between working with a + # Journal and the object it is attached to. + # The lookup is as follows: + ## => Call super if the method corresponds to one of our attributes (will end up in AR::Base) + ## => Try the journaled object with the same method and arguments + ## => On error, call super + def method_missing(method, *args, &block) + return super if attributes[method.to_s] + journaled.send(method, *args, &block) + rescue NoMethodError => e + e.name == method ? super : raise(e) + end + +end diff --git a/vendor/plugins/acts_as_journalized/app/models/journal_observer.rb b/vendor/plugins/acts_as_journalized/app/models/journal_observer.rb new file mode 100644 index 00000000..f854241b --- /dev/null +++ b/vendor/plugins/acts_as_journalized/app/models/journal_observer.rb @@ -0,0 +1,33 @@ +# redMine - project management software +# Copyright (C) 2006-2007 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class JournalObserver < ActiveRecord::Observer + def after_create(journal) + if journal.type == "IssueJournal" and journal.version > 1 + after_create_issue_journal(journal) + end + end + + def after_create_issue_journal(journal) + if Setting.notified_events.include?('issue_updated') || + (Setting.notified_events.include?('issue_note_added') && journal.notes.present?) || + (Setting.notified_events.include?('issue_status_updated') && journal.new_status.present?) || + (Setting.notified_events.include?('issue_priority_updated') && journal.new_value_for('priority_id').present?) + Mailer.deliver_issue_edit(journal) + end + end +end diff --git a/vendor/plugins/acts_as_journalized/app/views/journals/_notes_form.rhtml b/vendor/plugins/acts_as_journalized/app/views/journals/_notes_form.rhtml new file mode 100644 index 00000000..8344d938 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/app/views/journals/_notes_form.rhtml @@ -0,0 +1,8 @@ +<% form_remote_tag(:url => {}, :html => { :id => "journal-#{@journal.id}-form" }) do %> + <%= text_area_tag :notes, @journal.notes, :class => 'wiki-edit', + :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %> + <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %> +

    <%= submit_tag l(:button_save) %> + <%= link_to l(:button_cancel), '#', :onclick => "Element.remove('journal-#{@journal.id}-form'); " + + "Element.show('journal-#{@journal.id}-notes'); return false;" %>

    +<% end %> diff --git a/vendor/plugins/acts_as_journalized/app/views/journals/edit.rjs b/vendor/plugins/acts_as_journalized/app/views/journals/edit.rjs new file mode 100644 index 00000000..798cb0f0 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/app/views/journals/edit.rjs @@ -0,0 +1,3 @@ +page.hide "journal-#{@journal.id}-notes" +page.insert_html :after, "journal-#{@journal.id}-notes", + :partial => 'notes_form' diff --git a/vendor/plugins/acts_as_journalized/app/views/journals/update.rjs b/vendor/plugins/acts_as_journalized/app/views/journals/update.rjs new file mode 100644 index 00000000..50cd395a --- /dev/null +++ b/vendor/plugins/acts_as_journalized/app/views/journals/update.rjs @@ -0,0 +1,11 @@ +if @journal.frozen? + # journal was destroyed + page.remove "change-#{@journal.id}" +else + page.replace "journal-#{@journal.id}-notes", render_notes(@journal.journaled, @journal, + :edit_permission => :edit_issue_notes, :edit_own_permission => :edit_own_issue_notes) + page.show "journal-#{@journal.id}-notes" + page.remove "journal-#{@journal.id}-form" +end + +call_hook(:view_journals_update_rjs_bottom, { :page => page, :journal => @journal }) diff --git a/vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb b/vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb new file mode 100644 index 00000000..385bacc4 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb @@ -0,0 +1,119 @@ +class GeneralizeJournals < ActiveRecord::Migration + def self.up + # This is provided here for migrating up after the JournalDetails has been removed + unless Object.const_defined?("JournalDetails") + Object.const_set("JournalDetails", Class.new(ActiveRecord::Base)) + end + + change_table :journals do |t| + t.rename :journalized_id, :journaled_id + t.rename :created_on, :created_at + + t.integer :version, :default => 0, :null => false + t.string :activity_type + t.text :changes + t.string :type + + t.index :journaled_id + t.index :activity_type + t.index :created_at + t.index :type + end + + Journal.all.group_by(&:journaled_id).each_pair do |id, journals| + journals.sort_by(&:created_at).each_with_index do |j, idx| + j.update_attribute(:type, "#{j.journalized_type}Journal") + j.update_attribute(:version, idx + 1) + # FIXME: Find some way to choose the right activity here + j.update_attribute(:activity_type, j.journalized_type.constantize.activity_provider_options.keys.first) + end + end + + change_table :journals do |t| + t.remove :journalized_type + end + + JournalDetails.all.each do |detail| + journal = Journal.find(detail.journal_id) + changes = journal.changes || {} + if detail.property == 'attr' # Standard attributes + changes[detail.prop_key.to_s] = [detail.old_value, detail.value] + elsif detail.property == 'cf' # Custom fields + changes["custom_values_" + detail.prop_key.to_s] = [detail.old_value, detail.value] + elsif detail.property == 'attachment' # Attachment + changes["attachments_" + detail.prop_key.to_s] = [detail.old_value, detail.value] + end + journal.update_attribute(:changes, changes.to_yaml) + end + + # Create creation journals for all activity providers + providers = Redmine::Activity.providers.collect {|k, v| v.collect(&:constantize) }.flatten.compact.uniq + providers.each do |p| + next unless p.table_exists? # Objects not in the DB yet need creation journal entries + p.find(:all).each do |o| + unless o.last_journal + o.send(:update_journal) + created_at = nil + [:created_at, :created_on, :updated_at, :updated_on].each do |m| + if o.respond_to? m + created_at = o.send(m) + break + end + end + p "Updating #{o}" + o.last_journal.update_attribute(:created_at, created_at) if created_at and o.last_journal + end + end + end + + # drop_table :journal_details + end + + def self.down + # create_table "journal_details", :force => true do |t| + # t.integer "journal_id", :default => 0, :null => false + # t.string "property", :limit => 30, :default => "", :null => false + # t.string "prop_key", :limit => 30, :default => "", :null => false + # t.string "old_value" + # t.string "value" + # end + + change_table "journals" do |t| + t.rename :journaled_id, :journalized_id + t.rename :created_at, :created_on + + t.string :journalized_type, :limit => 30, :default => "", :null => false + end + + custom_field_names = CustomField.all.group_by(&:type)[IssueCustomField].collect(&:name) + Journal.all.each do |j| + j.update_attribute(:journalized_type, j.journalized.class.name) + # j.changes.each_pair do |prop_key, values| + # if Issue.columns.collect(&:name).include? prop_key.to_s + # property = :attr + # elsif CustomField.find_by_id(prop_key.to_s) + # property = :cf + # else + # property = :attachment + # end + # JournalDetail.create(:journal_id => j.id, :property => property, + # :prop_key => prop_key, :old_value => values.first, :value => values.last) + # end + end + + change_table "journals" do |t| + t.remove_index :journaled_id + t.remove_index :activity_type + t.remove_index :created_at + t.remove_index :type + + t.remove :type + t.remove :version + t.remove :activity_type + t.remove :changes + end + + # add_index "journal_details", ["journal_id"], :name => "journal_details_journal_id" + # add_index "journals", ["journalized_id", "journalized_type"], :name => "journals_journalized_id" + end +end diff --git a/vendor/plugins/acts_as_journalized/db/migrate/20100804112053_merge_wiki_versions_with_journals.rb b/vendor/plugins/acts_as_journalized/db/migrate/20100804112053_merge_wiki_versions_with_journals.rb new file mode 100644 index 00000000..b2b707f1 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/db/migrate/20100804112053_merge_wiki_versions_with_journals.rb @@ -0,0 +1,49 @@ +class MergeWikiVersionsWithJournals < ActiveRecord::Migration + def self.up + # This is provided here for migrating up after the WikiContent::Version class has been removed + unless WikiContent.const_defined?("Version") + WikiContent.const_set("Version", Class.new(ActiveRecord::Base)) + end + + WikiContent::Version.find_by_sql("SELECT * FROM wiki_content_versions").each do |wv| + journal = WikiContentJournal.create!(:journaled_id => wv.wiki_content_id, :user_id => wv.author_id, + :notes => wv.comments, :activity_type => "wiki_edits") + changes = {} + changes["compression"] = wv.compression + changes["data"] = wv.data + journal.update_attribute(:changes, changes.to_yaml) + journal.update_attribute(:version, wv.version) + end + # drop_table :wiki_content_versions + + change_table :wiki_contents do |t| + t.rename :version, :lock_version + end + end + + def self.down + change_table :wiki_contents do |t| + t.rename :lock_version, :version + end + + # create_table :wiki_content_versions do |t| + # t.column :wiki_content_id, :integer, :null => false + # t.column :page_id, :integer, :null => false + # t.column :author_id, :integer + # t.column :data, :binary + # t.column :compression, :string, :limit => 6, :default => "" + # t.column :comments, :string, :limit => 255, :default => "" + # t.column :updated_on, :datetime, :null => false + # t.column :version, :integer, :null => false + # end + # add_index :wiki_content_versions, :wiki_content_id, :name => :wiki_content_versions_wcid + # + # WikiContentJournal.all.each do |j| + # WikiContent::Version.create(:wiki_content_id => j.journaled_id, :page_id => j.journaled.page_id, + # :author_id => j.user_id, :data => j.changes["data"], :compression => j.changes["compression"], + # :comments => j.notes, :updated_on => j.created_at, :version => j.version) + # end + + WikiContentJournal.destroy_all + end +end diff --git a/vendor/plugins/acts_as_journalized/init.rb b/vendor/plugins/acts_as_journalized/init.rb new file mode 100644 index 00000000..560552c0 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/init.rb @@ -0,0 +1,17 @@ +$LOAD_PATH.unshift File.expand_path("../lib/", __FILE__) + +require "acts_as_journalized" +ActiveRecord::Base.send(:include, Redmine::Acts::Journalized) + +require 'dispatcher' +Dispatcher.to_prepare do + # Model + require_dependency "journal" + + # this is for compatibility with current trunk + # once the plugin is part of the core, this will not be needed + # patches should then be ported onto the core + # require_dependency File.dirname(__FILE__) + '/lib/acts_as_journalized/journal_patch' + # require_dependency File.dirname(__FILE__) + '/lib/acts_as_journalized/journal_observer_patch' + # require_dependency File.dirname(__FILE__) + '/lib/acts_as_journalized/activity_fetcher_patch' +end diff --git a/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb new file mode 100644 index 00000000..ba08ff55 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb @@ -0,0 +1,181 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either journal 2 +# of the License, or (at your option) any later journal. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +Dir[File.expand_path("../redmine/acts/journalized/*.rb", __FILE__)].each{|f| require f } +require_dependency 'lib/ar_condition' + +module Redmine + module Acts + module Journalized + + def self.included(base) + base.extend ClassMethods + base.extend Versioned + end + + module ClassMethods + + def plural_name + self.name.underscore.pluralize + end + + # A model might provide as many activity_types as it wishes. + # Activities are just different search options for the event a model provides + def acts_as_activity(options = {}) + activity_hash = journalized_activity_hash(options) + type = activity_hash[:type] + acts_as_activity_provider activity_hash + unless Redmine::Activity.providers[type].include? self.name + Redmine::Activity.register type.to_sym, :class_name => self.name + end + end + + # This call will add an activity and, if neccessary, start the journaling and + # add an event callback on the model. + # Versioning and acting as an Event may only be applied once. + # To apply more than on activity, use acts_as_activity + def acts_as_journalized(options = {}, &block) + activity_hash, event_hash, journal_hash = split_option_hashes(options) + + acts_as_activity(activity_hash) + + return if journaled? + + include Options + include Changes + include Creation + include Users + include Reversion + include Reset + include Reload + include Permissions + include SaveHooks + include FormatHooks + + # FIXME: When the transition to the new API is complete, remove me + include Deprecated + + journal_class.acts_as_event journalized_event_hash(event_hash) + + (journal_hash[:except] ||= []) << self.primary_key << inheritance_column << + :updated_on << :updated_at << :lock_version << :lft << :rgt + prepare_journaled_options(journal_hash) + has_many :journals, journal_hash.merge({:class_name => journal_class.name, + :foreign_key => "journaled_id"}), &block + end + + def journal_class + journal_class_name = "#{name.gsub("::", "_")}Journal" + if Object.const_defined?(journal_class_name) + Object.const_get(journal_class_name) + else + Object.const_set(journal_class_name, Class.new(Journal)).tap do |c| + # Run after the inherited hook to associate with the parent record. + # This eager loads the associated project (for permissions) if possible + if project_assoc = reflect_on_association(:project).try(:name) + include_option = ", :include => :#{project_assoc.to_s}" + end + c.class_eval("belongs_to :journaled, :class_name => '#{name}' #{include_option}") + c.class_eval("belongs_to :#{name.gsub("::", "_").underscore}, + :foreign_key => 'journaled_id' #{include_option}") + end + end + end + + private + # Splits an option has into three hashes: + ## => [{ options prefixed with "activity_" }, { options prefixed with "event_" }, { other options }] + def split_option_hashes(options) + activity_hash = {} + event_hash = {} + journal_hash = {} + + options.each_pair do |k, v| + case + when k.to_s =~ /^activity_(.+)$/ + activity_hash[$1.to_sym] = v + when k.to_s =~ /^event_(.+)$/ + event_hash[$1.to_sym] = v + else + journal_hash[k.to_sym] = v + end + end + [activity_hash, event_hash, journal_hash] + end + + # Merges the passed activity_hash with the options we require for + # acts_as_journalized to work, as follows: + # # type is the supplied or the pluralized class name + # # timestamp is supplied or the journal's created_at + # # author_key will always be the journal's author + # # + # # find_options are merged as follows: + # # # select statement is enriched with the journal fields + # # # journal association is added to the includes + # # # if a project is associated with the model, this is added to the includes + # # # the find conditions are extended to only choose journals which have the proper activity_type + # => a valid activity hash + def journalized_activity_hash(options) + options.tap do |h| + h[:type] ||= plural_name + h[:timestamp] = "#{journal_class.table_name}.created_at" + h[:author_key] = "#{journal_class.table_name}.user_id" + + h[:find_options] ||= {} # in case it is nil + h[:find_options] = {}.tap do |opts| + cond = ARCondition.new + cond.add(["#{journal_class.table_name}.activity_type = ?", h[:type]]) + cond.add(h[:find_options][:conditions]) if h[:find_options][:conditions] + opts[:conditions] = cond.conditions + + include_opts = [] + include_opts << :project if reflect_on_association(:project) + if h[:find_options][:include] + include_opts += case h[:find_options][:include] + when Array then h[:find_options][:include] + else [h[:find_options][:include]] + end + end + include_opts.uniq! + opts[:include] = [:journaled => include_opts] + + #opts[:joins] = h[:find_options][:joins] if h[:find_options][:joins] + end + end + end + + # Merges the event hashes defaults with the options provided by the user + # The defaults take their details from the journal + def journalized_event_hash(options) + unless options.has_key? :url + options[:url] = Proc.new do |journal| + { :controller => plural_name, + :action => 'show', + :id => journal.journaled_id, + :anchor => ("note-#{journal.anchor}" unless journal.initial?) } + end + end + { :description => :notes, :author => :user }.reverse_merge options + end + end + + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_journalized/lib/journal_deprecated.rb b/vendor/plugins/acts_as_journalized/lib/journal_deprecated.rb new file mode 100644 index 00000000..b66b4159 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/journal_deprecated.rb @@ -0,0 +1,49 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either journal 2 +# of the License, or (at your option) any later journal. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# This module holds the formatting methods that each journal has. +# It provides the hooks to apply different formatting to the details +# of a specific journal. +module JournalDeprecated + unloadable + # Old timestamps. created_at is what t.timestamps creates in recent Rails journals + def created_on + created_at + end + + # Old naming + def journalized + journaled + end + + # Old naming + def journalized= obj + journaled = obj + end + + + # Shortcut from more issue-specific journals + def attachments + journalized.respond_to?(:attachments) ? journalized.attachments : nil + end + + # deprecate :created_on => "use #created_at" + # deprecate :journalized => "use journaled" + # deprecate :attachments => "implement it yourself" +end diff --git a/vendor/plugins/acts_as_journalized/lib/journal_formatter.rb b/vendor/plugins/acts_as_journalized/lib/journal_formatter.rb new file mode 100644 index 00000000..10246185 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/journal_formatter.rb @@ -0,0 +1,190 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either journal 2 +# of the License, or (at your option) any later journal. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# This module holds the formatting methods that each journal has. +# It provides the hooks to apply different formatting to the details +# of a specific journal. +module JournalFormatter + unloadable + mattr_accessor :formatters, :registered_fields + include ApplicationHelper + include CustomFieldsHelper + include ActionView::Helpers::TagHelper + include ActionView::Helpers::UrlHelper + extend Redmine::I18n + + def self.register(hash) + if hash[:class] + klazz = hash.delete(:class) + registered_fields[klazz] ||= {} + registered_fields[klazz].merge!(hash) + else + formatters.merge(hash) + end + end + + # TODO: Document Formatters (can take up to three params, value, journaled, field ...) + def self.default_formatters + { :plaintext => (Proc.new {|v,*| v.try(:to_s) }), + :datetime => (Proc.new {|v,*| format_date(v.to_date) }), + :named_association => (Proc.new do |value, journaled, field| + association = journaled.class.reflect_on_association(field.to_sym) + if association + record = association.class_name.constantize.find_by_id(value.to_i) + record.name if record + end + end), + :fraction => (Proc.new {|v,*| "%0.02f" % v.to_f }), + :decimal => (Proc.new {|v,*| v.to_i.to_s }), + :id => (Proc.new {|v,*| "##{v}" }) } + end + + self.formatters = default_formatters + self.registered_fields = {} + + def format_attribute_detail(key, values, no_html=false) + field = key.to_s.gsub(/\_id$/, "") + label = l(("field_" + field).to_sym) + + if format = JournalFormatter.registered_fields[self.class.name.to_sym][key] + formatter = JournalFormatter.formatters[format] + old_value = formatter.call(values.first, journaled, field) if values.first + value = formatter.call(values.last, journaled, field) if values.last + [label, old_value, value] + else + return nil + end + end + + def format_custom_value_detail(custom_field, values, no_html) + label = custom_field.name + old_value = format_value(values.first, custom_field.field_format) if values.first + value = format_value(values.last, custom_field.field_format) if values.last + + [label, old_value, value] + end + + def format_attachment_detail(key, values, no_html) + label = l(:label_attachment) + old_value = values.first + value = values.last + + [label, old_value, value] + end + + def format_html_attachment_detail(key, value) + if !value.blank? && a = Attachment.find_by_id(key.to_i) + # Link to the attachment if it has not been removed + # FIXME: this is broken => link_to_attachment(a) + a.filename + else + content_tag("i", h(value)) if value.present? + end + end + + def format_html_detail(label, old_value, value) + label = content_tag('strong', label) + old_value = content_tag("i", h(old_value)) if old_value && !old_value.blank? + old_value = content_tag("strike", old_value) if old_value and value.blank? + value = content_tag("i", h(value)) if value.present? + value ||= "" + [label, old_value, value] + end + + def property(detail) + key = prop_key(detail) + if key.start_with? "custom_values" + :custom_field + elsif key.start_with? "attachments" + :attachment + elsif journaled.class.columns.collect(&:name).include? key + :attribute + end + end + + def prop_key(detail) + if detail.respond_to? :to_ary + detail.first + else + detail + end + end + + def values(detail) + key = prop_key(detail) + if detail != key + detail.last + else + details[key.to_s] + end + end + + def old_value(detail) + values(detail).first + end + + def value(detail) + values(detail).last + end + + def render_detail(detail, no_html=false) + if detail.respond_to? :to_ary + key = detail.first + values = detail.last + else + key = detail + values = details[key.to_s] + end + + case property(detail) + when :attribute + attr_detail = format_attribute_detail(key, values, no_html) + when :custom_field + custom_field = CustomField.find_by_id(key.sub("custom_values", "").to_i) + cv_detail = format_custom_value_detail(custom_field, values, no_html) + when :attachment + attachment_detail = format_attachment_detail(key.sub("attachments", ""), values, no_html) + end + + label, old_value, value = attr_detail || cv_detail || attachment_detail + Redmine::Hook.call_hook :helper_issues_show_detail_after_setting, {:detail => detail, + :label => label, :value => value, :old_value => old_value } + return nil unless label || old_value || value # print nothing if there are no values + label, old_value, value = [label, old_value, value].collect(&:to_s) + + unless no_html + label, old_value, value = *format_html_detail(label, old_value, value) + value = format_html_attachment_detail(key.sub("attachments", ""), value) if attachment_detail + end + + unless value.blank? + if attr_detail || cv_detail + unless old_value.blank? + l(:text_journal_changed, :label => label, :old => old_value, :new => value) + else + l(:text_journal_set_to, :label => label, :value => value) + end + elsif attachment_detail + l(:text_journal_added, :label => label, :value => value) + end + else + l(:text_journal_deleted, :label => label, :old => old_value) + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/changes.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/changes.rb new file mode 100644 index 00000000..5c60cb3f --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/changes.rb @@ -0,0 +1,162 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either journal 2 +# of the License, or (at your option) any later journal. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Provides the ability to manipulate hashes in the specific format that ActiveRecord gives to + # dirty attribute changes: string keys and unique, two-element array values. + module Changes + def self.included(base) # :nodoc: + Hash.send(:include, HashMethods) + + base.class_eval do + include InstanceMethods + + after_update :merge_journal_changes + end + end + + # Methods available to journaled ActiveRecord::Base instances in order to manage changes used + # for journal creation. + module InstanceMethods + # Collects an array of changes from a record's journals between the given range and compiles + # them into one summary hash of changes. The +from+ and +to+ arguments can each be either a + # version number, a symbol representing an association proxy method, a string representing a + # journal tag or a journal object itself. + def changes_between(from, to) + from_number, to_number = journals.journal_at(from), journals.journal_at(to) + return {} if from_number == to_number + chain = journals.between(from_number, to_number).reject(&:initial?) + return {} if chain.empty? + + backward = from_number > to_number + backward ? chain.pop : chain.shift unless from_number == 1 || to_number == 1 + + chain.inject({}) do |changes, journal| + changes.append_changes!(backward ? journal.changes.reverse_changes : journal.changes) + end + end + + private + # Before a new journal is created, the newly-changed attributes are appended onto a hash + # of previously-changed attributes. Typically the previous changes will be empty, except in + # the case that a control block is used where journals are to be merged. See + # VestalVersions::Control for more information. + def merge_journal_changes + journal_changes.append_changes!(incremental_journal_changes) + end + + # Stores the cumulative changes that are eventually used for journal creation. + def journal_changes + @journal_changes ||= {} + end + + # Stores the incremental changes that are appended to the cumulative changes before journal + # creation. Incremental changes are reset when the record is saved because they represent + # a subset of the dirty attribute changes, which are reset upon save. + def incremental_journal_changes + changes.slice(*journaled_columns) + end + + # Simply resets the cumulative changes after journal creation. + def reset_journal_changes + @journal_changes = nil + end + end + + # Instance methods included into Hash for dealing with manipulation of hashes in the specific + # format of ActiveRecord::Base#changes. + module HashMethods + # When called on a hash of changes and given a second hash of changes as an argument, + # +append_changes+ will run the second hash on top of the first, updating the last element + # of each array value with its own, or creating its own key/value pair for missing keys. + # Resulting non-unique array values are removed. + # + # == Example + # + # first = { + # "first_name" => ["Steve", "Stephen"], + # "age" => [25, 26] + # } + # second = { + # "first_name" => ["Stephen", "Steve"], + # "last_name" => ["Richert", "Jobs"], + # "age" => [26, 54] + # } + # first.append_changes(second) + # # => { + # "last_name" => ["Richert", "Jobs"], + # "age" => [25, 54] + # } + def append_changes(changes) + changes.inject(self) do |new_changes, (attribute, change)| + new_change = [new_changes.fetch(attribute, change).first, change.last] + new_changes.merge(attribute => new_change) + end.reject do |attribute, change| + change.first == change.last + end + end + + # Destructively appends a given hash of changes onto an existing hash of changes. + def append_changes!(changes) + replace(append_changes(changes)) + end + + # Appends the existing hash of changes onto a given hash of changes. Relates to the + # +append_changes+ method in the same way that Hash#reverse_merge relates to + # Hash#merge. + def prepend_changes(changes) + changes.append_changes(self) + end + + # Destructively prepends a given hash of changes onto an existing hash of changes. + def prepend_changes!(changes) + replace(prepend_changes(changes)) + end + + # Reverses the array values of a hash of changes. Useful for rejournal both backward and + # forward through a record's history of changes. + def reverse_changes + inject({}){|nc,(a,c)| nc.merge!(a => c.reverse) } + end + + # Destructively reverses the array values of a hash of changes. + def reverse_changes! + replace(reverse_changes) + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/configuration.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/configuration.rb new file mode 100644 index 00000000..0c4db2be --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/configuration.rb @@ -0,0 +1,77 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Allows for easy application-wide configuration of options passed into the +journaled+ method. + module Configuration + # The VestalVersions module is extended by VestalVersions::Configuration, allowing the + # +configure method+ to be used as follows in a Rails initializer: + # + # VestalVersions.configure do |config| + # config.class_name = "MyCustomVersion" + # config.dependent = :destroy + # end + # + # Each variable assignment in the +configure+ block corresponds directly with the options + # available to the +journaled+ method. Assigning common options in an initializer can keep your + # models tidy. + # + # If an option is given in both an initializer and in the options passed to +journaled+, the + # value given in the model itself will take precedence. + def configure + yield Configuration + end + + class << self + # Simply stores a hash of options given to the +configure+ block. + def options + @options ||= {} + end + + # If given a setter method name, will assign the first argument to the +options+ hash with + # the method name (sans "=") as the key. If given a getter method name, will attempt to + # a value from the +options+ hash for that key. If the key doesn't exist, defers to +super+. + def method_missing(symbol, *args) + if (method = symbol.to_s).sub!(/\=$/, '') + options[method.to_sym] = args.first + else + options.fetch(method.to_sym, super) + end + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/creation.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/creation.rb new file mode 100644 index 00000000..031fbcf7 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/creation.rb @@ -0,0 +1,127 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Adds the functionality necessary to control journal creation on a journaled instance of + # ActiveRecord::Base. + module Creation + def self.included(base) # :nodoc: + base.class_eval do + extend ClassMethods + include InstanceMethods + + after_save :create_journal, :if => :create_journal? + + class << self + alias_method_chain :prepare_journaled_options, :creation + end + end + end + + # Class methods added to ActiveRecord::Base to facilitate the creation of new journals. + module ClassMethods + # Overrides the basal +prepare_journaled_options+ method defined in VestalVersions::Options + # to extract the :only and :except options into +vestal_journals_options+. + def prepare_journaled_options_with_creation(options) + result = prepare_journaled_options_without_creation(options) + + self.vestal_journals_options[:only] = Array(options.delete(:only)).map(&:to_s).uniq if options[:only] + self.vestal_journals_options[:except] = Array(options.delete(:except)).map(&:to_s).uniq if options[:except] + + result + end + end + + # Instance methods that determine whether to save a journal and actually perform the save. + module InstanceMethods + private + # Returns whether a new journal should be created upon updating the parent record. + # A new journal will be created if + # a) attributes have changed + # b) no previous journal exists + # c) journal notes were added + # d) the parent record is already saved + def create_journal? + update_journal + (journal_changes.present? or journal_notes.present? or journals.empty?) and !new_record? + end + + # Creates a new journal upon updating the parent record. + # "update_journal" has been called in "update_journal?" at this point (to get a hold on association changes) + # It must not be called again here. + def create_journal + journals << self.class.journal_class.create(journal_attributes) + reset_journal_changes + reset_journal + true + rescue Exception => e # FIXME: What to do? This likely means that the parent record is invalid! + p e + p e.message + p e.backtrace + false + end + + # Returns an array of column names that should be included in the changes of created + # journals. If vestal_journals_options[:only] is specified, only those columns + # will be journaled. Otherwise, if vestal_journals_options[:except] is specified, + # all columns will be journaled other than those specified. Without either option, the + # default is to journal all columns. At any rate, the four "automagic" timestamp columns + # maintained by Rails are never journaled. + def journaled_columns + case + when vestal_journals_options[:only] then self.class.column_names & vestal_journals_options[:only] + when vestal_journals_options[:except] then self.class.column_names - vestal_journals_options[:except] + else self.class.column_names + end - %w(created_at updated_at) + end + + # Returns the activity type. Should be overridden in the journalized class to offer + # multiple types + def activity_type + self.class.name.underscore.pluralize + end + + # Specifies the attributes used during journal creation. This is separated into its own + # method so that it can be overridden by the VestalVersions::Users feature. + def journal_attributes + attributes = { :journaled_id => self.id, :activity_type => activity_type, + :changes => journal_changes, :version => last_version + 1, + :notes => journal_notes, :user_id => (journal_user.try(:id) || User.current) } + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb new file mode 100644 index 00000000..967b4521 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb @@ -0,0 +1,68 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# These hooks make sure journals are properly created and updated with Redmine user detail, +# notes and associated custom fields + +module Redmine::Acts::Journalized + module Deprecated + # Old mailer API + def recipients + notified = project.notified_users + notified.reject! {|user| !visible?(user)} + notified.collect(&:mail) + end + + def current_journal + last_journal + end + + # FIXME: When the new API is settled, remove me + Redmine::Acts::Event::InstanceMethods.instance_methods(false).each do |m| + if m.start_with? "event_" + class_eval(<<-RUBY, __FILE__, __LINE__) + def #{m} + if last_journal.nil? + begin + journals << self.class.journal_class.create(journal_attributes) + reset_journal_changes + reset_journal + true + rescue Exception => e # FIXME: What to do? This likely means that the parent record is invalid! + p e + p e.message + p e.backtrace + false + end + journals.reload + end + return last_journal.#{m} + end + RUBY + end + end + + def event_url(options = {}) + last_journal.event_url(options) + end + + # deprecate :recipients => "use #last_journal.recipients" + # deprecate :current_journal => "use #last_journal" + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/format_hooks.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/format_hooks.rb new file mode 100644 index 00000000..b5d1ee1f --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/format_hooks.rb @@ -0,0 +1,42 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine::Acts::Journalized + module FormatHooks + def self.included(base) + base.extend ClassMethods + end + + module ClassMethods + # Shortcut to register a formatter for a number of fields + def register_on_journal_formatter(formatter, *field_names) + formatter = formatter.to_sym + field_names.collect(&:to_s).each do |field| + JournalFormatter.register :class => self.journal_class.name.to_sym, field => formatter + end + end + + # Shortcut to register a new proc as a named formatter. Overwrites + # existing formatters with the same name + def register_journal_formatter(formatter) + JournalFormatter.register formatter.to_sym => Proc.new + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/options.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/options.rb new file mode 100644 index 00000000..324cb22c --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/options.rb @@ -0,0 +1,81 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Provides +journaled+ options conjournal and cleanup. + module Options + def self.included(base) # :nodoc: + base.class_eval do + extend ClassMethods + end + end + + # Class methods that provide preparation of options passed to the +journaled+ method. + module ClassMethods + # The +prepare_journaled_options+ method has three purposes: + # 1. Populate the provided options with default values where needed + # 2. Prepare options for use with the +has_many+ association + # 3. Save user-configurable options in a class-level variable + # + # Options are given priority in the following order: + # 1. Those passed directly to the +journaled+ method + # 2. Those specified in an initializer +configure+ block + # 3. Default values specified in +prepare_journaled_options+ + # + # The method is overridden in feature modules that require specific options outside the + # standard +has_many+ associations. + def prepare_journaled_options(options) + options.symbolize_keys! + options.reverse_merge!(Configuration.options) + options.reverse_merge!( + :class_name => 'Journal', + :dependent => :delete_all + ) + options.reverse_merge!( + :order => "#{options[:class_name].constantize.table_name}.version ASC" + ) + + class_inheritable_accessor :vestal_journals_options + self.vestal_journals_options = options.dup + + options.merge!( + :extend => Array(options[:extend]).unshift(Versions) + ) + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb new file mode 100644 index 00000000..df5b35f8 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/permissions.rb @@ -0,0 +1,36 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module Redmine::Acts::Journalized + module Permissions + # Default implementation of journal editing permission + # Is overridden if defined in the journalized model directly + def journal_editable_by?(user) + return true if user.admin? + if respond_to? :editable_by? + editable_by? user + else + permission = :"edit_#{self.class.to_s.pluralize.downcase}" + p = @project || (project if respond_to? :project) + options = { :global => p.present? } + user.allowed_to? permission, p, options + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reload.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reload.rb new file mode 100644 index 00000000..292e823f --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reload.rb @@ -0,0 +1,60 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Ties into the existing ActiveRecord::Base#reload method to ensure that journal information + # is properly reset. + module Reload + def self.included(base) # :nodoc: + base.class_eval do + include InstanceMethods + + alias_method_chain :reload, :journals + end + end + + # Adds instance methods into ActiveRecord::Base to tap into the +reload+ method. + module InstanceMethods + # Overrides ActiveRecord::Base#reload, resetting the instance-variable-cached journal number + # before performing the original +reload+ method. + def reload_with_journals(*args) + reset_journal + reload_without_journals(*args) + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reset.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reset.rb new file mode 100644 index 00000000..342a0437 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reset.rb @@ -0,0 +1,65 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Adds the ability to "reset" (or hard revert) a journaled ActiveRecord::Base instance. + module Reset + def self.included(base) # :nodoc: + base.class_eval do + include InstanceMethods + end + end + + # Adds the instance methods required to reset an object to a previous journal. + module InstanceMethods + # Similar to +revert_to!+, the +reset_to!+ method reverts an object to a previous journal, + # only instead of creating a new record in the journal history, +reset_to!+ deletes all of + # the journal history that occurs after the journal reverted to. + # + # The action taken on each journal record after the point of rejournal is determined by the + # :dependent option given to the +journaled+ method. See the +journaled+ method + # documentation for more details. + def reset_to!(value) + if saved = skip_journal{ revert_to!(value) } + journals.send(:delete_records, journals.after(value)) + reset_journal + end + saved + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reversion.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reversion.rb new file mode 100644 index 00000000..44fc9a52 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/reversion.rb @@ -0,0 +1,110 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Enables versioned ActiveRecord::Base instances to revert to a previously saved version. + module Reversion + def self.included(base) # :nodoc: + base.class_eval do + include InstanceMethods + end + end + + # Provides the base instance methods required to revert a journaled instance. + module InstanceMethods + # Returns the current version number for the versioned object. + def version + @version ||= last_version + end + + def last_journal + journals.last + end + + # Accepts a value corresponding to a specific journal record, builds a history of changes + # between that journal and the current journal, and then iterates over that history updating + # the object's attributes until the it's reverted to its prior state. + # + # The single argument should adhere to one of the formats as documented in the +at+ method of + # VestalVersions::Versions. + # + # After the object is reverted to the target journal, it is not saved. In order to save the + # object after the rejournal, use the +revert_to!+ method. + # + # The journal number of the object will reflect whatever journal has been reverted to, and + # the return value of the +revert_to+ method is also the target journal number. + def revert_to(value) + to_number = journals.journal_at(value) + + changes_between(journal, to_number).each do |attribute, change| + write_attribute(attribute, change.last) + end + + reset_journal(to_number) + end + + # Behaves similarly to the +revert_to+ method except that it automatically saves the record + # after the rejournal. The return value is the success of the save. + def revert_to!(value) + revert_to(value) + reset_journal if saved = save + saved + end + + # Returns a boolean specifying whether the object has been reverted to a previous journal or + # if the object represents the latest journal in the journal history. + def reverted? + version != last_version + end + + private + # Returns the number of the last created journal in the object's journal history. + # + # If no associated journals exist, the object is considered at version 0. + def last_version + @last_version ||= journals.maximum(:version) || 0 + end + + # Clears the cached version number instance variables so that they can be recalculated. + # Useful after a new version is created. + def reset_journal(version = nil) + @last_version = nil if version.nil? + @version = version + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/save_hooks.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/save_hooks.rb new file mode 100644 index 00000000..61e13986 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/save_hooks.rb @@ -0,0 +1,115 @@ +# This file is part of the acts_as_journalized plugin for the redMine +# project management software +# +# Copyright (C) 2010 Finn GmbH, http://finn.de +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +# These hooks make sure journals are properly created and updated with Redmine user detail, +# notes and associated custom fields +module Redmine::Acts::Journalized + module SaveHooks + def self.included(base) + base.extend ClassMethods + + base.class_eval do + before_save :init_journal + after_save :reset_instance_variables + + attr_reader :journal_notes, :journal_user + end + end + + # Saves the current custom values, notes and journal to include them in the next journal + # Called before save + def init_journal(user = User.current, notes = "") + @journal_notes ||= notes + @journal_user ||= user + @associations_before_save ||= {} + + @associations = {} + save_possible_association :custom_values, :key => :custom_field_id, :value => :value + save_possible_association :attachments, :key => :id, :value => :filename + + @current_journal ||= last_journal + end + + # Saves the notes and custom value changes in the last Journal + # Called before create_journal + def update_journal + unless (@associations || {}).empty? + changed_associations = {} + changed_associations.merge!(possibly_updated_association :custom_values) + changed_associations.merge!(possibly_updated_association :attachments) + end + + unless changed_associations.blank? + update_extended_journal_contents(changed_associations) + end + end + + def reset_instance_variables + if last_journal != @current_journal + if last_journal.user != @journal_user + last_journal.update_attribute(:user_id, @journal_user.id) + end + end + @associations_before_save = @current_journal = @journal_notes = @journal_user = nil + end + + def save_possible_association(method, options) + @associations[method] = options + if self.respond_to? method + @associations_before_save[method] ||= send(method).inject({}) do |hash, cv| + hash[cv.send(options[:key])] = cv.send(options[:value]) + hash + end + end + end + + def possibly_updated_association(method) + if @associations_before_save[method] + # Has custom values from init_journal_notes + return changed_associations(method, @associations_before_save[method]) + end + {} + end + + # Saves the notes and changed custom values to the journal + # Creates a new journal, if no immediate attributes were changed + def update_extended_journal_contents(changed_associations) + journal_changes.merge!(changed_associations) + end + + def changed_associations(method, previous) + send(method).reload # Make sure the associations are reloaded + send(method).inject({}) do |hash, c| + key = c.send(@associations[method][:key]) + new_value = c.send(@associations[method][:value]) + + if previous[key].blank? && new_value.blank? + # The key was empty before, don't add a blank value + elsif previous[key] != new_value + # The key's value changed + hash["#{method}#{key}"] = [previous[key], new_value] + end + hash + end + end + + module ClassMethods + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/users.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/users.rb new file mode 100644 index 00000000..d2b719fd --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/users.rb @@ -0,0 +1,86 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Provides a way for information to be associated with specific journals as to who was + # responsible for the associated update to the parent. + module Users + def self.included(base) # :nodoc: + Journal.send(:include, JournalMethods) + + base.class_eval do + include InstanceMethods + + attr_accessor :updated_by + alias_method_chain :journal_attributes, :user + end + end + + # Methods added to journaled ActiveRecord::Base instances to enable journaling with additional + # user information. + module InstanceMethods + private + # Overrides the +journal_attributes+ method to include user information passed into the + # parent object, by way of a +updated_by+ attr_accessor. + def journal_attributes_with_user + journal_attributes_without_user.merge(:user => updated_by || User.current) + end + end + + # Instance methods added to Redmine::Acts::Journalized::Journal to accomodate incoming + # user information. + module JournalMethods + def self.included(base) # :nodoc: + base.class_eval do + belongs_to :user + + alias_method_chain :user=, :name + end + end + + # Overrides the +user=+ method created by the polymorphic +belongs_to+ user association. + # Based on the class of the object given, either the +user+ association columns or the + # +user_name+ string column is populated. + def user_with_name=(value) + case value + when ActiveRecord::Base then self.user_without_name = value + else self.user = User.find_by_login(value) + end + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versioned.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versioned.rb new file mode 100644 index 00000000..757bf322 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versioned.rb @@ -0,0 +1,67 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # Simply adds a flag to determine whether a model class if journaled. + module Versioned + def self.extended(base) # :nodoc: + base.class_eval do + class << self + alias_method_chain :acts_as_journalized, :flag + end + end + end + + # Overrides the +journaled+ method to first define the +journaled?+ class method before + # deferring to the original +journaled+. + def acts_as_journalized_with_flag(*args) + acts_as_journalized_without_flag(*args) + + class << self + def journaled? + true + end + end + end + + # For all ActiveRecord::Base models that do not call the +journaled+ method, the +journaled?+ + # method will return false. + def journaled? + false + end + end +end diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versions.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versions.rb new file mode 100644 index 00000000..abc23495 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/versions.rb @@ -0,0 +1,111 @@ +# This file included as part of the acts_as_journalized plugin for +# the redMine project management software; You can redistribute it +# and/or modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The original copyright and license conditions are: +# Copyright (c) 2009 Steve Richert +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +module Redmine::Acts::Journalized + # An extension module for the +has_many+ association with journals. + module Versions + # Returns all journals between (and including) the two given arguments. See documentation for + # the +at+ extension method for what arguments are valid. If either of the given arguments is + # invalid, an empty array is returned. + # + # The +between+ method preserves returns an array of journal records, preserving the order + # given by the arguments. If the +from+ value represents a journal before that of the +to+ + # value, the array will be ordered from earliest to latest. The reverse is also true. + def between(from, to) + from_number, to_number = journal_at(from), journal_at(to) + return [] if from_number.nil? || to_number.nil? + + condition = (from_number == to_number) ? to_number : Range.new(*[from_number, to_number].sort) + all( + :conditions => {:version => condition}, + :order => "#{aliased_table_name}.version #{(from_number > to_number) ? 'DESC' : 'ASC'}" + ) + end + + # Returns all journal records created before the journal associated with the given value. + def before(value) + return [] if (version = journal_at(value)).nil? + all(:conditions => "#{aliased_table_name}.version < #{version}") + end + + # Returns all journal records created after the journal associated with the given value. + # + # This is useful for dissociating records during use of the +reset_to!+ method. + def after(value) + return [] if (version = journal_at(value)).nil? + all(:conditions => "#{aliased_table_name}.version > #{version}") + end + + # Returns a single journal associated with the given value. The following formats are valid: + # * A Date or Time object: When given, +to_time+ is called on the value and the last journal + # record in the history created before (or at) that time is returned. + # * A Numeric object: Typically a positive integer, these values correspond to journal numbers + # and the associated journal record is found by a journal number equal to the given value + # rounded down to the nearest integer. + # * A String: A string value represents a journal tag and the associated journal is searched + # for by a matching tag value. *Note:* Be careful with string representations of numbers. + # * A Symbol: Symbols represent association class methods on the +has_many+ journals + # association. While all of the built-in association methods require arguments, additional + # extension modules can be defined using the :extend option on the +journaled+ + # method. See the +journaled+ documentation for more information. + # * A Version object: If a journal object is passed to the +at+ method, it is simply returned + # untouched. + def at(value) + case value + when Date, Time then last(:conditions => ["#{aliased_table_name}.created_at <= ?", value.to_time]) + when Numeric then find_by_version(value.floor) + when Symbol then respond_to?(value) ? send(value) : nil + when Journal then value + end + end + + # Returns the journal number associated with the given value. In many cases, this involves + # simply passing the value to the +at+ method and then returning the subsequent journal number. + # Hoever, for Numeric values, the journal number can be returned directly and for Date/Time + # values, a default value of 1 is given to ensure that times prior to the first journal + # still return a valid journal number (useful for rejournal). + def journal_at(value) + case value + when Date, Time then (v = at(value)) ? v.version : 1 + when Numeric then value.floor + when Symbol then (v = at(value)) ? v.version : nil + when String then nil + when Journal then value.version + end + end + end +end \ No newline at end of file diff --git a/vendor/plugins/acts_as_journalized/test/changes_test.rb b/vendor/plugins/acts_as_journalized/test/changes_test.rb new file mode 100644 index 00000000..e4b86775 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/changes_test.rb @@ -0,0 +1,169 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class ChangesTest < Test::Unit::TestCase + context "A journal's changes" do + setup do + @user = User.create(:name => 'Steve Richert') + @user.update_attribute(:last_name, 'Jobs') + @changes = @user.journals.last.changes + end + + should 'be a hash' do + assert_kind_of Hash, @changes + end + + should 'not be empty' do + assert !@changes.empty? + end + + should 'have string keys' do + @changes.keys.each do |key| + assert_kind_of String, key + end + end + + should 'have array values' do + @changes.values.each do |value| + assert_kind_of Array, value + end + end + + should 'have two-element values' do + @changes.values.each do |value| + assert_equal 2, value.size + end + end + + should 'have unique-element values' do + @changes.values.each do |value| + assert_equal value.uniq, value + end + end + + should "equal the model's changes" do + @user.first_name = 'Stephen' + model_changes = @user.changes + @user.save + changes = @user.journals.last.changes + assert_equal model_changes, changes + end + end + + context 'A hash of changes' do + setup do + @changes = {'first_name' => ['Steve', 'Stephen']} + @other = {'first_name' => ['Catie', 'Catherine']} + end + + should 'properly append other changes' do + expected = {'first_name' => ['Steve', 'Catherine']} + changes = @changes.append_changes(@other) + assert_equal expected, changes + @changes.append_changes!(@other) + assert_equal expected, @changes + end + + should 'properly prepend other changes' do + expected = {'first_name' => ['Catie', 'Stephen']} + changes = @changes.prepend_changes(@other) + assert_equal expected, changes + @changes.prepend_changes!(@other) + assert_equal expected, @changes + end + + should 'be reversible' do + expected = {'first_name' => ['Stephen', 'Steve']} + changes = @changes.reverse_changes + assert_equal expected, changes + @changes.reverse_changes! + assert_equal expected, @changes + end + end + + context 'The changes between two journals' do + setup do + name = 'Steve Richert' + @user = User.create(:name => name) # 1 + @user.update_attribute(:last_name, 'Jobs') # 2 + @user.update_attribute(:first_name, 'Stephen') # 3 + @user.update_attribute(:last_name, 'Richert') # 4 + @user.update_attribute(:name, name) # 5 + @version = @user.version + end + + should 'be a hash' do + 1.upto(@version) do |i| + 1.upto(@version) do |j| + changes = @user.changes_between(i, j) + assert_kind_of Hash, changes + end + end + end + + should 'have string keys' do + 1.upto(@version) do |i| + 1.upto(@version) do |j| + changes = @user.changes_between(i, j) + changes.keys.each do |key| + assert_kind_of String, key + end + end + end + end + + should 'have array values' do + 1.upto(@version) do |i| + 1.upto(@version) do |j| + changes = @user.changes_between(i, j) + changes.values.each do |value| + assert_kind_of Array, value + end + end + end + end + + should 'have two-element values' do + 1.upto(@version) do |i| + 1.upto(@version) do |j| + changes = @user.changes_between(i, j) + changes.values.each do |value| + assert_equal 2, value.size + end + end + end + end + + should 'have unique-element values' do + 1.upto(@version) do |i| + 1.upto(@version) do |j| + changes = @user.changes_between(i, j) + changes.values.each do |value| + assert_equal value.uniq, value + end + end + end + end + + should 'be empty between identical versions' do + assert @user.changes_between(1, @version).empty? + assert @user.changes_between(@version, 1).empty? + end + + should 'be should reverse with direction' do + 1.upto(@version) do |i| + i.upto(@version) do |j| + up = @user.changes_between(i, j) + down = @user.changes_between(j, i) + assert_equal up, down.reverse_changes + end + end + end + + should 'be empty with invalid arguments' do + 1.upto(@version) do |i| + assert @user.changes_between(i, nil) + assert @user.changes_between(nil, i) + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/conditions_test.rb b/vendor/plugins/acts_as_journalized/test/conditions_test.rb new file mode 100644 index 00000000..6600cb03 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/conditions_test.rb @@ -0,0 +1,137 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class ConditionsTest < Test::Unit::TestCase + context 'Converted :if conditions' do + setup do + User.class_eval do + def true; true; end + end + end + + should 'be an array' do + assert_kind_of Array, User.vestal_journals_options[:if] + User.prepare_journaled_options(:if => :true) + assert_kind_of Array, User.vestal_journals_options[:if] + end + + should 'have proc values' do + User.prepare_journaled_options(:if => :true) + assert User.vestal_journals_options[:if].all?{|i| i.is_a?(Proc) } + end + + teardown do + User.prepare_journaled_options(:if => []) + end + end + + context 'Converted :unless conditions' do + setup do + User.class_eval do + def true; true; end + end + end + + should 'be an array' do + assert_kind_of Array, User.vestal_journals_options[:unless] + User.prepare_journaled_options(:unless => :true) + assert_kind_of Array, User.vestal_journals_options[:unless] + end + + should 'have proc values' do + User.prepare_journaled_options(:unless => :true) + assert User.vestal_journals_options[:unless].all?{|i| i.is_a?(Proc) } + end + + teardown do + User.prepare_journaled_options(:unless => []) + end + end + + context 'A new journal' do + setup do + User.class_eval do + def true; true; end + def false; false; end + end + + @user = User.create(:name => 'Steve Richert') + @count = @user.journals.count + end + + context 'with :if conditions' do + context 'that pass' do + setup do + User.prepare_journaled_options(:if => [:true]) + @user.update_attribute(:last_name, 'Jobs') + end + + should 'be created' do + assert_equal @count + 1, @user.journals.count + end + end + + context 'that fail' do + setup do + User.prepare_journaled_options(:if => [:false]) + @user.update_attribute(:last_name, 'Jobs') + end + + should 'not be created' do + assert_equal @count, @user.journals.count + end + end + end + + context 'with :unless conditions' do + context 'that pass' do + setup do + User.prepare_journaled_options(:unless => [:true]) + @user.update_attribute(:last_name, 'Jobs') + end + + should 'not be created' do + assert_equal @count, @user.journals.count + end + end + + context 'that fail' do + setup do + User.prepare_journaled_options(:unless => [:false]) + @user.update_attribute(:last_name, 'Jobs') + end + + should 'not be created' do + assert_equal @count + 1, @user.journals.count + end + end + end + + context 'with :if and :unless conditions' do + context 'that pass' do + setup do + User.prepare_journaled_options(:if => [:true], :unless => [:true]) + @user.update_attribute(:last_name, 'Jobs') + end + + should 'not be created' do + assert_equal @count, @user.journals.count + end + end + + context 'that fail' do + setup do + User.prepare_journaled_options(:if => [:false], :unless => [:false]) + @user.update_attribute(:last_name, 'Jobs') + end + + should 'not be created' do + assert_equal @count, @user.journals.count + end + end + end + + teardown do + User.prepare_journaled_options(:if => [], :unless => []) + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/configuration_test.rb b/vendor/plugins/acts_as_journalized/test/configuration_test.rb new file mode 100644 index 00000000..18f77103 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/configuration_test.rb @@ -0,0 +1,39 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class ConfigurationTest < Test::Unit::TestCase + context 'Global configuration options' do + setup do + module Extension; end + + @options = { + 'class_name' => 'CustomVersion', + :extend => Extension, + :as => :parent + } + + VestalVersions.configure do |config| + @options.each do |key, value| + config.send("#{key}=", value) + end + end + + @configuration = VestalVersions::Configuration.options + end + + should 'should be a hash' do + assert_kind_of Hash, @configuration + end + + should 'have symbol keys' do + assert @configuration.keys.all?{|k| k.is_a?(Symbol) } + end + + should 'store values identical to those given' do + assert_equal @options.symbolize_keys, @configuration + end + + teardown do + VestalVersions::Configuration.options.clear + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/control_test.rb b/vendor/plugins/acts_as_journalized/test/control_test.rb new file mode 100644 index 00000000..d032fa5b --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/control_test.rb @@ -0,0 +1,152 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class ControlTest < Test::Unit::TestCase + context 'Within a skip_journal block,' do + setup do + @user = User.create(:name => 'Steve Richert') + @count = @user.journals.count + end + + context 'a model update' do + setup do + @user.skip_journal do + @user.update_attribute(:last_name, 'Jobs') + end + end + + should 'not create a journal' do + assert_equal @count, @user.journals.count + end + end + + context 'multiple model updates' do + setup do + @user.skip_journal do + @user.update_attribute(:first_name, 'Stephen') + @user.update_attribute(:last_name, 'Jobs') + @user.update_attribute(:first_name, 'Steve') + end + end + + should 'not create a journal' do + assert_equal @count, @user.journals.count + end + end + end + + context 'Within a merge_journal block,' do + setup do + @user = User.create(:name => 'Steve Richert') + @count = @user.journals.count + end + + context 'a model update' do + setup do + @user.merge_journal do + @user.update_attribute(:last_name, 'Jobs') + end + end + + should 'create a journal' do + assert_equal @count + 1, @user.journals.count + end + end + + context 'multiple model updates' do + setup do + @user.merge_journal do + @user.update_attribute(:first_name, 'Stephen') + @user.update_attribute(:last_name, 'Jobs') + @user.update_attribute(:first_name, 'Steve') + end + end + + should 'create a journal' do + assert_equal @count + 1, @user.journals.count + end + end + end + + context 'Within a append_journal block' do + context '(when no journals exist),' do + setup do + @user = User.create(:name => 'Steve Richert') + @count = @user.journals.count + end + + context 'a model update' do + setup do + @user.append_journal do + @user.update_attribute(:last_name, 'Jobs') + end + end + + should 'create a journal' do + assert_equal @count + 1, @user.journals.count + end + end + + context 'multiple model updates' do + setup do + @user.append_journal do + @user.update_attribute(:first_name, 'Stephen') + @user.update_attribute(:last_name, 'Jobs') + @user.update_attribute(:first_name, 'Steve') + end + end + + should 'create a journal' do + assert_equal @count + 1, @user.journals.count + end + end + end + + context '(when journals exist),' do + setup do + @user = User.create(:name => 'Steve Richert') + @user.update_attribute(:last_name, 'Jobs') + @user.update_attribute(:last_name, 'Richert') + @last_journal = @user.journals.last + @count = @user.journals.count + end + + context 'a model update' do + setup do + @user.append_journal do + @user.update_attribute(:last_name, 'Jobs') + end + end + + should 'not create a journal' do + assert_equal @count, @user.journals.count + end + + should 'update the last journal' do + last_journal = @user.journals(true).last + assert_equal @last_journal.id, last_journal.id + assert_not_equal @last_journal.attributes, last_journal.attributes + end + end + + context 'multiple model updates' do + setup do + @user.append_journal do + @user.update_attribute(:first_name, 'Stephen') + @user.update_attribute(:last_name, 'Jobs') + @user.update_attribute(:first_name, 'Steve') + end + end + + should 'not create a journal' do + assert_equal @count, @user.journals.count + end + + should 'update the last journal' do + last_journal = @user.journals(true).last + assert_equal @last_journal.id, last_journal.id + assert_not_equal @last_journal.attributes, last_journal.attributes + end + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/creation_test.rb b/vendor/plugins/acts_as_journalized/test/creation_test.rb new file mode 100644 index 00000000..03508099 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/creation_test.rb @@ -0,0 +1,110 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class CreationTest < Test::Unit::TestCase + context 'The number of journals' do + setup do + @name = 'Steve Richert' + @user = User.create(:name => @name) + @count = @user.journals.count + end + + should 'initially equal zero' do + assert_equal 0, @count + end + + should 'not increase when no changes are made in an update' do + @user.update_attribute(:name, @name) + assert_equal @count, @user.journals.count + end + + should 'not increase when no changes are made before a save' do + @user.save + assert_equal @count, @user.journals.count + end + + context 'after an update' do + setup do + @user.update_attribute(:last_name, 'Jobs') + end + + should 'increase by one' do + assert_equal @count + 1, @user.journals.count + end + end + + context 'after multiple updates' do + setup do + @user.update_attribute(:last_name, 'Jobs') + @user.update_attribute(:last_name, 'Richert') + end + + should 'increase multiple times' do + assert_operator @count + 1, :<, @user.journals.count + end + end + end + + context "A created journal's changes" do + setup do + @user = User.create(:name => 'Steve Richert') + @user.update_attribute(:last_name, 'Jobs') + end + + should 'not contain Rails timestamps' do + %w(created_at created_on updated_at updated_on).each do |timestamp| + assert_does_not_contain @user.journals.last.changes.keys, timestamp + end + end + + context '(with :only options)' do + setup do + @only = %w(first_name) + User.prepare_journaled_options(:only => @only) + @user.update_attribute(:name, 'Steven Tyler') + end + + should 'only contain the specified columns' do + assert_equal @only, @user.journals.last.changes.keys + end + + teardown do + User.prepare_journaled_options(:only => nil) + end + end + + context '(with :except options)' do + setup do + @except = %w(first_name) + User.prepare_journaled_options(:except => @except) + @user.update_attribute(:name, 'Steven Tyler') + end + + should 'not contain the specified columns' do + @except.each do |column| + assert_does_not_contain @user.journals.last.changes.keys, column + end + end + + teardown do + User.prepare_journaled_options(:except => nil) + end + end + + context '(with both :only and :except options)' do + setup do + @only = %w(first_name) + @except = @only + User.prepare_journaled_options(:only => @only, :except => @except) + @user.update_attribute(:name, 'Steven Tyler') + end + + should 'respect only the :only options' do + assert_equal @only, @user.journals.last.changes.keys + end + + teardown do + User.prepare_journaled_options(:only => nil, :except => nil) + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/options_test.rb b/vendor/plugins/acts_as_journalized/test/options_test.rb new file mode 100644 index 00000000..1386b8b7 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/options_test.rb @@ -0,0 +1,52 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class OptionsTest < Test::Unit::TestCase + context 'Configuration options' do + setup do + @options = {:dependent => :destroy} + @configuration = {:class_name => 'MyCustomVersion'} + + VestalVersions::Configuration.options.clear + @configuration.each{|k,v| VestalVersions::Configuration.send("#{k}=", v) } + + @prepared_options = User.prepare_journaled_options(@options.dup) + end + + should 'have symbolized keys' do + assert User.vestal_journals_options.keys.all?{|k| k.is_a?(Symbol) } + end + + should 'combine class-level and global configuration options' do + combined_keys = (@options.keys + @configuration.keys).map(&:to_sym).uniq + combined_options = @configuration.symbolize_keys.merge(@options.symbolize_keys) + assert_equal @prepared_options.slice(*combined_keys), combined_options + end + + teardown do + VestalVersions::Configuration.options.clear + User.prepare_journaled_options({}) + end + end + + context 'Given no options, configuration options' do + setup do + @prepared_options = User.prepare_journaled_options({}) + end + + should 'default to "VestalVersions::Version" for :class_name' do + assert_equal 'VestalVersions::Version', @prepared_options[:class_name] + end + + should 'default to :delete_all for :dependent' do + assert_equal :delete_all, @prepared_options[:dependent] + end + + should 'force the :as option value to :journaled' do + assert_equal :journaled, @prepared_options[:as] + end + + should 'default to [VestalVersions::Versions] for :extend' do + assert_equal [VestalVersions::Versions], @prepared_options[:extend] + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/reload_test.rb b/vendor/plugins/acts_as_journalized/test/reload_test.rb new file mode 100644 index 00000000..91b4f67b --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/reload_test.rb @@ -0,0 +1,19 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class ReloadTest < Test::Unit::TestCase + context 'Reloading a reverted model' do + setup do + @user = User.create(:name => 'Steve Richert') + first_version = @user.version + @user.update_attribute(:last_name, 'Jobs') + @last_version = @user.version + @user.revert_to(first_version) + end + + should 'reset the journal number to the most recent journal' do + assert_not_equal @last_journal, @user.journal + @user.reload + assert_equal @last_journal, @user.journal + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/reset_test.rb b/vendor/plugins/acts_as_journalized/test/reset_test.rb new file mode 100644 index 00000000..1ecdbbd0 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/reset_test.rb @@ -0,0 +1,112 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class ResetTest < Test::Unit::TestCase + context 'Resetting a model' do + setup do + @original_dependent = User.reflect_on_association(:journals).options[:dependent] + @user, @journals = User.new, [] + @names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs'] + @names.each do |name| + @user.update_attribute(:name, name) + @journals << @user.journal + end + end + + should "properly revert the model's attributes" do + @journals.reverse.each_with_index do |journal, i| + @user.reset_to!(journal) + assert_equal @names.reverse[i], @user.name + end + end + + should 'dissociate all journals after the target' do + @journals.reverse.each do |journal| + @user.reset_to!(journal) + assert_equal 0, @user.journals(true).after(journal).count + end + end + + context 'with the :dependent option as :delete_all' do + setup do + User.reflect_on_association(:journals).options[:dependent] = :delete_all + end + + should 'delete all journals after the target journal' do + @journals.reverse.each do |journal| + later_journals = @user.journals.after(journal) + @user.reset_to!(journal) + later_journals.each do |later_journal| + assert_raise ActiveRecord::RecordNotFound do + later_journal.reload + end + end + end + end + + should 'not destroy all journals after the target journal' do + VestalVersions::Version.any_instance.stubs(:destroy).raises(RuntimeError) + @journals.reverse.each do |journal| + assert_nothing_raised do + @user.reset_to!(journal) + end + end + end + end + + context 'with the :dependent option as :destroy' do + setup do + User.reflect_on_association(:journals).options[:dependent] = :destroy + end + + should 'delete all journals after the target journal' do + @journals.reverse.each do |journal| + later_journals = @user.journals.after(journal) + @user.reset_to!(journal) + later_journals.each do |later_journal| + assert_raise ActiveRecord::RecordNotFound do + later_journal.reload + end + end + end + end + + should 'destroy all journals after the target journal' do + VestalVersions::Version.any_instance.stubs(:destroy).raises(RuntimeError) + @journals.reverse.each do |journal| + later_journals = @user.journals.after(journal) + if later_journals.empty? + assert_nothing_raised do + @user.reset_to!(journal) + end + else + assert_raise RuntimeError do + @user.reset_to!(journal) + end + end + end + end + end + + context 'with the :dependent option as :nullify' do + setup do + User.reflect_on_association(:journals).options[:dependent] = :nullify + end + + should 'leave all journals after the target journal' do + @journals.reverse.each do |journal| + later_journals = @user.journals.after(journal) + @user.reset_to!(journal) + later_journals.each do |later_journal| + assert_nothing_raised do + later_journal.reload + end + end + end + end + end + + teardown do + User.reflect_on_association(:journals).options[:dependent] = @original_dependent + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/reversion_test.rb b/vendor/plugins/acts_as_journalized/test/reversion_test.rb new file mode 100644 index 00000000..02420896 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/reversion_test.rb @@ -0,0 +1,68 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class RejournalTest < Test::Unit::TestCase + context 'A model rejournal' do + setup do + @user, @attributes, @times = User.new, {}, {} + names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs'] + time = names.size.hours.ago + names.each do |name| + @user.update_attribute(:name, name) + @attributes[@user.journal] = @user.attributes + time += 1.hour + if last_journal = @user.journals.last + last_journal.update_attribute(:created_at, time) + end + @times[@user.journal] = time + end + @user.reload.journals.reload + @first_journal, @last_journal = @attributes.keys.min, @attributes.keys.max + end + + should 'return the new journal number' do + new_journal = @user.revert_to(@first_journal) + assert_equal @first_journal, new_journal + end + + should 'change the journal number when saved' do + current_journal = @user.journal + @user.revert_to!(@first_journal) + assert_not_equal current_journal, @user.journal + end + + should 'do nothing for a invalid argument' do + current_journal = @user.journal + [nil, :bogus, 'bogus', (1..2)].each do |invalid| + @user.revert_to(invalid) + assert_equal current_journal, @user.journal + end + end + + should 'be able to target a journal number' do + @user.revert_to(1) + assert 1, @user.journal + end + + should 'be able to target a date and time' do + @times.each do |journal, time| + @user.revert_to(time + 1.second) + assert_equal journal, @user.journal + end + end + + should 'be able to target a journal object' do + @user.journals.each do |journal| + @user.revert_to(journal) + assert_equal journal.number, @user.journal + end + end + + should "correctly roll back the model's attributes" do + timestamps = %w(created_at created_on updated_at updated_on) + @attributes.each do |journal, attributes| + @user.revert_to!(journal) + assert_equal attributes.except(*timestamps), @user.attributes.except(*timestamps) + end + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/schema.rb b/vendor/plugins/acts_as_journalized/test/schema.rb new file mode 100644 index 00000000..4fa9935d --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/schema.rb @@ -0,0 +1,43 @@ +ActiveRecord::Base.establish_connection( + :adapter => defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby' ? 'jdbcsqlite3' : 'sqlite3', + :database => File.join(File.dirname(__FILE__), 'test.db') +) + +class CreateSchema < ActiveRecord::Migration + def self.up + create_table :users, :force => true do |t| + t.string :first_name + t.string :last_name + t.timestamps + end + + create_table :journals, :force => true do |t| + t.belongs_to :journaled, :polymorphic => true + t.belongs_to :user, :polymorphic => true + t.string :user_name + t.text :changes + t.integer :number + t.string :tag + t.timestamps + end + end +end + +CreateSchema.suppress_messages do + CreateSchema.migrate(:up) +end + +class User < ActiveRecord::Base + journaled + + def name + [first_name, last_name].compact.join(' ') + end + + def name=(names) + self[:first_name], self[:last_name] = names.split(' ', 2) + end +end + +class MyCustomVersion < VestalVersions::Version +end diff --git a/vendor/plugins/acts_as_journalized/test/tagging_test.rb b/vendor/plugins/acts_as_journalized/test/tagging_test.rb new file mode 100644 index 00000000..fb3a526d --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/tagging_test.rb @@ -0,0 +1,39 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class TaggingTest < Test::Unit::TestCase + context 'Tagging a journal' do + setup do + @user = User.create(:name => 'Steve Richert') + @user.update_attribute(:last_name, 'Jobs') + end + + should "update the journal record's tag column" do + tag_name = 'TAG' + last_journal = @user.journals.last + assert_not_equal tag_name, last_journal.tag + @user.tag_journal(tag_name) + assert_equal tag_name, last_journal.reload.tag + end + + should 'create a journal record for an initial journal' do + @user.revert_to(1) + assert_nil @user.journals.at(1) + @user.tag_journal('TAG') + assert_not_nil @user.journals.at(1) + end + end + + context 'A tagged journal' do + setup do + user = User.create(:name => 'Steve Richert') + user.update_attribute(:last_name, 'Jobs') + user.tag_journal('TAG') + @journal = user.journals.last + end + + should 'return true for the "tagged?" method' do + assert @journal.respond_to?(:tagged?) + assert_equal true, @journal.tagged? + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/test_helper.rb b/vendor/plugins/acts_as_journalized/test/test_helper.rb new file mode 100644 index 00000000..87e5209d --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/test_helper.rb @@ -0,0 +1,11 @@ +$: << File.join(File.dirname(__FILE__), '..', 'lib') +$: << File.dirname(__FILE__) + +require 'rubygems' +require 'test/unit' +require 'active_record' +require 'shoulda' +require 'mocha' +require 'vestal_versions' +require 'schema' +begin; require 'redgreen'; rescue LoadError; end diff --git a/vendor/plugins/acts_as_journalized/test/users_test.rb b/vendor/plugins/acts_as_journalized/test/users_test.rb new file mode 100644 index 00000000..ae29bc81 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/users_test.rb @@ -0,0 +1,25 @@ +require 'test_helper' + +class UsersTest < Test::Unit::TestCase + context 'The user responsible for an update' do + setup do + @updated_by = User.create(:name => 'Steve Jobs') + @user = User.create(:name => 'Steve Richert') + end + + should 'default to nil' do + @user.update_attributes(:first_name => 'Stephen') + assert_nil @user.journals.last.user + end + + should 'accept and return an ActiveRecord user' do + @user.update_attributes(:first_name => 'Stephen', :updated_by => @updated_by) + assert_equal @updated_by, @user.journals.last.user + end + + should 'accept and return a string user name' do + @user.update_attributes(:first_name => 'Stephen', :updated_by => @updated_by.name) + assert_equal @updated_by.name, @user.journals.last.user + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/version_test.rb b/vendor/plugins/acts_as_journalized/test/version_test.rb new file mode 100644 index 00000000..7d005196 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/version_test.rb @@ -0,0 +1,43 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class VersionTest < Test::Unit::TestCase + context 'Versions' do + setup do + @user = User.create(:name => 'Stephen Richert') + @user.update_attribute(:name, 'Steve Jobs') + @user.update_attribute(:last_name, 'Richert') + @first_journal, @last_journal = @user.journals.first, @user.journals.last + end + + should 'be comparable to another journal based on journal number' do + assert @first_journal == @first_journal + assert @last_journal == @last_journal + assert @first_journal != @last_journal + assert @last_journal != @first_journal + assert @first_journal < @last_journal + assert @last_journal > @first_journal + assert @first_journal <= @last_journal + assert @last_journal >= @first_journal + end + + should "not equal a separate model's journal with the same number" do + user = User.create(:name => 'Stephen Richert') + user.update_attribute(:name, 'Steve Jobs') + user.update_attribute(:last_name, 'Richert') + first_journal, last_journal = user.journals.first, user.journals.last + assert_not_equal @first_journal, first_journal + assert_not_equal @last_journal, last_journal + end + + should 'default to ordering by number when finding through association' do + order = @user.journals.send(:scope, :find)[:order] + assert_equal 'journals.number ASC', order + end + + should 'return true for the "initial?" method when the journal number is 1' do + journal = @user.journals.build(:number => 1) + assert_equal 1, journal.number + assert_equal true, journal.initial? + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/versioned_test.rb b/vendor/plugins/acts_as_journalized/test/versioned_test.rb new file mode 100644 index 00000000..dca8a4f3 --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/versioned_test.rb @@ -0,0 +1,18 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class VersionedTest < Test::Unit::TestCase + context 'ActiveRecord models' do + should 'respond to the "journaled?" method' do + assert ActiveRecord::Base.respond_to?(:journaled?) + assert User.respond_to?(:journaled?) + end + + should 'return true for the "journaled?" method if the model is journaled' do + assert_equal true, User.journaled? + end + + should 'return false for the "journaled?" method if the model is not journaled' do + assert_equal false, ActiveRecord::Base.journaled? + end + end +end diff --git a/vendor/plugins/acts_as_journalized/test/versions_test.rb b/vendor/plugins/acts_as_journalized/test/versions_test.rb new file mode 100644 index 00000000..ff0dbeef --- /dev/null +++ b/vendor/plugins/acts_as_journalized/test/versions_test.rb @@ -0,0 +1,172 @@ +require File.join(File.dirname(__FILE__), 'test_helper') + +class VersionsTest < Test::Unit::TestCase + context 'A collection of associated journals' do + setup do + @user, @times = User.new, {} + names = ['Steve Richert', 'Stephen Richert', 'Stephen Jobs', 'Steve Jobs'] + time = names.size.hours.ago + names.each do |name| + @user.update_attribute(:name, name) + @user.tag_journal(@user.journal.to_s) + time += 1.hour + @user.journals.last.update_attribute(:created_at, time) + @times[@user.journal] = time + end + end + + should 'be searchable between two valid journal values' do + @times.keys.each do |number| + @times.values.each do |time| + assert_kind_of Array, @user.journals.between(number, number) + assert_kind_of Array, @user.journals.between(number, time) + assert_kind_of Array, @user.journals.between(time, number) + assert_kind_of Array, @user.journals.between(time, time) + assert !@user.journals.between(number, number).empty? + assert !@user.journals.between(number, time).empty? + assert !@user.journals.between(time, number).empty? + assert !@user.journals.between(time, time).empty? + end + end + end + + should 'return an empty array when searching between a valid and an invalid journal value' do + @times.each do |number, time| + assert_equal [], @user.journals.between(number, nil) + assert_equal [], @user.journals.between(time, nil) + assert_equal [], @user.journals.between(nil, number) + assert_equal [], @user.journals.between(nil, time) + end + end + + should 'return an empty array when searching between two invalid journal values' do + assert_equal [], @user.journals.between(nil, nil) + end + + should 'be searchable before a valid journal value' do + @times.sort.each_with_index do |(number, time), i| + assert_equal i, @user.journals.before(number).size + assert_equal i, @user.journals.before(time).size + end + end + + should 'return an empty array when searching before an invalid journal value' do + assert_equal [], @user.journals.before(nil) + end + + should 'be searchable after a valid journal value' do + @times.sort.reverse.each_with_index do |(number, time), i| + assert_equal i, @user.journals.after(number).size + assert_equal i, @user.journals.after(time).size + end + end + + should 'return an empty array when searching after an invalid journal value' do + assert_equal [], @user.journals.after(nil) + end + + should 'be fetchable by journal number' do + @times.keys.each do |number| + assert_kind_of VestalVersions::Version, @user.journals.at(number) + assert_equal number, @user.journals.at(number).number + end + end + + should 'be fetchable by tag' do + @times.keys.map{|n| [n, n.to_s] }.each do |number, tag| + assert_kind_of VestalVersions::Version, @user.journals.at(tag) + assert_equal number, @user.journals.at(tag).number + end + end + + should "be fetchable by the exact time of a journal's creation" do + @times.each do |number, time| + assert_kind_of VestalVersions::Version, @user.journals.at(time) + assert_equal number, @user.journals.at(time).number + end + end + + should "be fetchable by any time after the model's creation" do + @times.each do |number, time| + assert_kind_of VestalVersions::Version, @user.journals.at(time + 30.minutes) + assert_equal number, @user.journals.at(time + 30.minutes).number + end + end + + should "return nil when fetching a time before the model's creation" do + creation = @times.values.min + assert_nil @user.journals.at(creation - 1.second) + end + + should 'be fetchable by an association extension method' do + assert_kind_of VestalVersions::Version, @user.journals.at(:first) + assert_kind_of VestalVersions::Version, @user.journals.at(:last) + assert_equal @times.keys.min, @user.journals.at(:first).number + assert_equal @times.keys.max, @user.journals.at(:last).number + end + + should 'be fetchable by a journal object' do + @times.keys.each do |number| + journal = @user.journals.at(number) + assert_kind_of VestalVersions::Version, journal + assert_kind_of VestalVersions::Version, @user.journals.at(journal) + assert_equal number, @user.journals.at(journal).number + end + end + + should 'return nil when fetching an invalid journal value' do + assert_nil @user.journals.at(nil) + end + + should 'provide a journal number for any given numeric journal value' do + @times.keys.each do |number| + assert_kind_of Fixnum, @user.journals.number_at(number) + assert_kind_of Fixnum, @user.journals.number_at(number + 0.5) + assert_equal @user.journals.number_at(number), @user.journals.number_at(number + 0.5) + end + end + + should 'provide a journal number for a valid tag' do + @times.keys.map{|n| [n, n.to_s] }.each do |number, tag| + assert_kind_of Fixnum, @user.journals.number_at(tag) + assert_equal number, @user.journals.number_at(tag) + end + end + + should 'return nil when providing a journal number for an invalid tag' do + assert_nil @user.journals.number_at('INVALID') + end + + should 'provide a journal number of a journal corresponding to an association extension method' do + assert_kind_of VestalVersions::Version, @user.journals.at(:first) + assert_kind_of VestalVersions::Version, @user.journals.at(:last) + assert_equal @times.keys.min, @user.journals.number_at(:first) + assert_equal @times.keys.max, @user.journals.number_at(:last) + end + + should 'return nil when providing a journal number for an invalid association extension method' do + assert_nil @user.journals.number_at(:INVALID) + end + + should "provide a journal number for any time after the model's creation" do + @times.each do |number, time| + assert_kind_of Fixnum, @user.journals.number_at(time + 30.minutes) + assert_equal number, @user.journals.number_at(time + 30.minutes) + end + end + + should "provide a journal number of 1 for a time before the model's creation" do + creation = @times.values.min + assert_equal 1, @user.journals.number_at(creation - 1.second) + end + + should 'provide a journal number for a given journal object' do + @times.keys.each do |number| + journal = @user.journals.at(number) + assert_kind_of VestalVersions::Version, journal + assert_kind_of Fixnum, @user.journals.number_at(journal) + assert_equal number, @user.journals.number_at(journal) + end + end + end +end From 0ca73a7f69349b0bd6f591fead34815b3cfcab16 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 10:20:34 -0700 Subject: [PATCH 659/777] [#123] Fix the down migration for Journal#journalized_type --- .../migrate/20100714111651_generalize_journals.rb | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb b/vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb index 385bacc4..2595175c 100644 --- a/vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb +++ b/vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb @@ -87,18 +87,8 @@ class GeneralizeJournals < ActiveRecord::Migration custom_field_names = CustomField.all.group_by(&:type)[IssueCustomField].collect(&:name) Journal.all.each do |j| - j.update_attribute(:journalized_type, j.journalized.class.name) - # j.changes.each_pair do |prop_key, values| - # if Issue.columns.collect(&:name).include? prop_key.to_s - # property = :attr - # elsif CustomField.find_by_id(prop_key.to_s) - # property = :cf - # else - # property = :attachment - # end - # JournalDetail.create(:journal_id => j.id, :property => property, - # :prop_key => prop_key, :old_value => values.first, :value => values.last) - # end + # Can't used j.journalized.class.name because the model changes make it nil + j.update_attribute(:journalized_type, j.type.to_s.sub("Journal","")) if j.type.present? end change_table "journals" do |t| From 23ef9fedef3bf003ae34eb3bb9e3499cf75eeacc Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 10:56:22 -0700 Subject: [PATCH 660/777] [#123] Port the send_notification feature to aaj --- .../app/models/journal_observer.rb | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/vendor/plugins/acts_as_journalized/app/models/journal_observer.rb b/vendor/plugins/acts_as_journalized/app/models/journal_observer.rb index f854241b..79b1d666 100644 --- a/vendor/plugins/acts_as_journalized/app/models/journal_observer.rb +++ b/vendor/plugins/acts_as_journalized/app/models/journal_observer.rb @@ -16,10 +16,13 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. class JournalObserver < ActiveRecord::Observer + attr_accessor :send_notification + def after_create(journal) - if journal.type == "IssueJournal" and journal.version > 1 + if journal.type == "IssueJournal" and journal.version > 1 and self.send_notification after_create_issue_journal(journal) end + clear_notification end def after_create_issue_journal(journal) @@ -30,4 +33,18 @@ class JournalObserver < ActiveRecord::Observer Mailer.deliver_issue_edit(journal) end end + + # Wrap send_notification so it defaults to true, when it's nil + def send_notification + return true if @send_notification.nil? + return @send_notification + end + + private + + # Need to clear the notification setting after each usage otherwise it might be cached + def clear_notification + @send_notification = true + end + end From adf57a64f14c3dfbce2895c7b896a08233a2e0d3 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 11:11:41 -0700 Subject: [PATCH 661/777] [#123] Move aaj migrations to core --- .../db => db}/migrate/20100714111651_generalize_journals.rb | 0 .../migrate/20100804112053_merge_wiki_versions_with_journals.rb | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {vendor/plugins/acts_as_journalized/db => db}/migrate/20100714111651_generalize_journals.rb (100%) rename {vendor/plugins/acts_as_journalized/db => db}/migrate/20100804112053_merge_wiki_versions_with_journals.rb (100%) diff --git a/vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb b/db/migrate/20100714111651_generalize_journals.rb similarity index 100% rename from vendor/plugins/acts_as_journalized/db/migrate/20100714111651_generalize_journals.rb rename to db/migrate/20100714111651_generalize_journals.rb diff --git a/vendor/plugins/acts_as_journalized/db/migrate/20100804112053_merge_wiki_versions_with_journals.rb b/db/migrate/20100804112053_merge_wiki_versions_with_journals.rb similarity index 100% rename from vendor/plugins/acts_as_journalized/db/migrate/20100804112053_merge_wiki_versions_with_journals.rb rename to db/migrate/20100804112053_merge_wiki_versions_with_journals.rb From aa2b0a8709704b21c97aff1b13ee68c8b1075b8d Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 11:26:06 -0700 Subject: [PATCH 662/777] [#123 #407] Deferred Journal#visible tests --- test/unit/journal_test.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/journal_test.rb b/test/unit/journal_test.rb index ab4e3761..579191a0 100644 --- a/test/unit/journal_test.rb +++ b/test/unit/journal_test.rb @@ -51,7 +51,7 @@ class JournalTest < ActiveSupport::TestCase assert_equal 1, ActionMailer::Base.deliveries.size end - def test_visible_scope_for_anonymous + should_eventually "test_visible_scope_for_anonymous" do # Anonymous user should see issues of public projects only journals = Journal.visible(User.anonymous).all assert journals.any? @@ -61,8 +61,8 @@ class JournalTest < ActiveSupport::TestCase journals = Journal.visible(User.anonymous).all assert journals.empty? end - - def test_visible_scope_for_user + + should_eventually "test_visible_scope_for_user" do user = User.find(9) assert user.projects.empty? # Non member user should see issues of public projects only @@ -82,7 +82,7 @@ class JournalTest < ActiveSupport::TestCase assert_nil journals.detect {|journal| journal.issue.project_id != 1} end - def test_visible_scope_for_admin + should_eventually "test_visible_scope_for_admin" do user = User.find(1) user.members.each(&:destroy) assert user.projects.empty? From 0ba4134ecc4b55b9e7901ad7ce373c481c6bf3e8 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 11:33:51 -0700 Subject: [PATCH 663/777] [#123] Fix Journal notification test --- test/unit/journal_test.rb | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/test/unit/journal_test.rb b/test/unit/journal_test.rb index 579191a0..02845c18 100644 --- a/test/unit/journal_test.rb +++ b/test/unit/journal_test.rb @@ -96,10 +96,12 @@ class JournalTest < ActiveSupport::TestCase ActionMailer::Base.deliveries.clear issue = Issue.find(:first) user = User.find(:first) - journal = issue.init_journal(user, issue) + journal = issue.init_journal(user, "A note") JournalObserver.instance.send_notification = false - assert journal.save + assert_difference("Journal.count") do + assert issue.save + end assert_equal 0, ActionMailer::Base.deliveries.size end end From f79e209d4cfb0460ba212ec638c008a7dc7d786b Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 11:53:25 -0700 Subject: [PATCH 664/777] [#123] Fix hardcoded test value with a dynamic one --- test/unit/issue_nested_set_test.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/unit/issue_nested_set_test.rb b/test/unit/issue_nested_set_test.rb index 3009af45..99e3a90c 100644 --- a/test/unit/issue_nested_set_test.rb +++ b/test/unit/issue_nested_set_test.rb @@ -239,8 +239,9 @@ class IssueNestedSetTest < ActiveSupport::TestCase leaf.subject = 'leaf with journal' leaf.save! + total_journals_on_children = leaf.reload.journals.count + child.reload.journals.count assert_difference 'Issue.count', -2 do - assert_difference 'IssueJournal.count', -3 do + assert_difference 'IssueJournal.count', -total_journals_on_children do Issue.find(child.id).destroy end end From 193b2c7a38482d63d44f31cc2deb2a49d6840db0 Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 12:34:24 -0700 Subject: [PATCH 665/777] [#404] Move vendor/plugins/acts_as_journalized/app/ to the core app/ --- .../app => app}/controllers/journals_controller.rb | 0 .../acts_as_journalized/app => app}/helpers/journals_helper.rb | 0 {vendor/plugins/acts_as_journalized/app => app}/models/journal.rb | 0 .../acts_as_journalized/app => app}/models/journal_observer.rb | 0 .../app => app}/views/journals/_notes_form.rhtml | 0 .../acts_as_journalized/app => app}/views/journals/edit.rjs | 0 .../acts_as_journalized/app => app}/views/journals/update.rjs | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename {vendor/plugins/acts_as_journalized/app => app}/controllers/journals_controller.rb (100%) rename {vendor/plugins/acts_as_journalized/app => app}/helpers/journals_helper.rb (100%) rename {vendor/plugins/acts_as_journalized/app => app}/models/journal.rb (100%) rename {vendor/plugins/acts_as_journalized/app => app}/models/journal_observer.rb (100%) rename {vendor/plugins/acts_as_journalized/app => app}/views/journals/_notes_form.rhtml (100%) rename {vendor/plugins/acts_as_journalized/app => app}/views/journals/edit.rjs (100%) rename {vendor/plugins/acts_as_journalized/app => app}/views/journals/update.rjs (100%) diff --git a/vendor/plugins/acts_as_journalized/app/controllers/journals_controller.rb b/app/controllers/journals_controller.rb similarity index 100% rename from vendor/plugins/acts_as_journalized/app/controllers/journals_controller.rb rename to app/controllers/journals_controller.rb diff --git a/vendor/plugins/acts_as_journalized/app/helpers/journals_helper.rb b/app/helpers/journals_helper.rb similarity index 100% rename from vendor/plugins/acts_as_journalized/app/helpers/journals_helper.rb rename to app/helpers/journals_helper.rb diff --git a/vendor/plugins/acts_as_journalized/app/models/journal.rb b/app/models/journal.rb similarity index 100% rename from vendor/plugins/acts_as_journalized/app/models/journal.rb rename to app/models/journal.rb diff --git a/vendor/plugins/acts_as_journalized/app/models/journal_observer.rb b/app/models/journal_observer.rb similarity index 100% rename from vendor/plugins/acts_as_journalized/app/models/journal_observer.rb rename to app/models/journal_observer.rb diff --git a/vendor/plugins/acts_as_journalized/app/views/journals/_notes_form.rhtml b/app/views/journals/_notes_form.rhtml similarity index 100% rename from vendor/plugins/acts_as_journalized/app/views/journals/_notes_form.rhtml rename to app/views/journals/_notes_form.rhtml diff --git a/vendor/plugins/acts_as_journalized/app/views/journals/edit.rjs b/app/views/journals/edit.rjs similarity index 100% rename from vendor/plugins/acts_as_journalized/app/views/journals/edit.rjs rename to app/views/journals/edit.rjs diff --git a/vendor/plugins/acts_as_journalized/app/views/journals/update.rjs b/app/views/journals/update.rjs similarity index 100% rename from vendor/plugins/acts_as_journalized/app/views/journals/update.rjs rename to app/views/journals/update.rjs From 0ed2af49e9cb5e645943da564d185d4589db74dc Mon Sep 17 00:00:00 2001 From: Eric Davis Date: Fri, 13 May 2011 12:51:44 -0700 Subject: [PATCH 666/777] [#408] Removed old JournalDetail test --- test/unit/issue_test.rb | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/test/unit/issue_test.rb b/test/unit/issue_test.rb index c40d253d..5f9d580b 100644 --- a/test/unit/issue_test.rb +++ b/test/unit/issue_test.rb @@ -641,32 +641,6 @@ class IssueTest < ActiveSupport::TestCase assert_equal new_description, journal.value("description") end - # TODO: This test has become somewhat obsolete with the new journalized scheme - def test_saving_twice_should_not_duplicate_journal_details - i = Issue.find(:first) - i.init_journal(User.find(2), 'Some notes') - # initial changes - i.subject = 'New subject' - i.done_ratio = i.done_ratio + 10 - assert_difference 'IssueJournal.count' do - assert i.save - end - assert i.current_journal.changes.has_key? "subject" - assert i.current_journal.changes.has_key? "done_ratio" - - # 1 more change - i.priority = IssuePriority.find(:first, :conditions => ["id <> ?", i.priority_id]) - assert_difference 'IssueJournal.count' do - i.save - end - assert i.current_journal.changes.has_key? "priority_id" - - # no more change - assert_no_difference 'IssueJournal.count' do - i.save - end - end - def test_all_dependent_issues IssueRelation.delete_all assert IssueRelation.create!(:issue_from => Issue.find(1), :issue_to => Issue.find(2), :relation_type => IssueRelation::TYPE_PRECEDES) From 09fd71232e5a0e0ca31de11b2efd0bff5fc40aaa Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Fri, 13 May 2011 23:52:24 +0200 Subject: [PATCH 667/777] [#412] fixes to make tests run on 1.9.2 --- vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb | 2 +- .../lib/redmine/acts/journalized/deprecated.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb index ba08ff55..72f6b2bd 100644 --- a/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb +++ b/vendor/plugins/acts_as_journalized/lib/acts_as_journalized.rb @@ -19,7 +19,7 @@ Dir[File.expand_path("../redmine/acts/journalized/*.rb", __FILE__)].each{|f| require f } -require_dependency 'lib/ar_condition' +require_dependency File.expand_path('lib/ar_condition', Rails.root) module Redmine module Acts diff --git a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb index 967b4521..8dc9a7b5 100644 --- a/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb +++ b/vendor/plugins/acts_as_journalized/lib/redmine/acts/journalized/deprecated.rb @@ -35,7 +35,7 @@ module Redmine::Acts::Journalized # FIXME: When the new API is settled, remove me Redmine::Acts::Event::InstanceMethods.instance_methods(false).each do |m| - if m.start_with? "event_" + if m.to_s.start_with? "event_" class_eval(<<-RUBY, __FILE__, __LINE__) def #{m} if last_journal.nil? From 300bc07b5a384920a11554ad8d43b11057deb6d5 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Sat, 14 May 2011 00:09:56 +0200 Subject: [PATCH 668/777] [#413] using Hash#to_a.first since Hash#first is not present in 1.8.6 --- test/functional/issues_controller_test.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 1ecb9062..40d77420 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -962,7 +962,7 @@ class IssuesControllerTest < ActionController::TestCase j = Issue.find(1).last_journal assert j.notes.blank? assert_equal 1, j.details.size - assert_equal 'testfile.txt', j.value(j.details.first) + assert_equal 'testfile.txt', j.value(j.details.to_a.first) assert_equal User.anonymous, j.user mail = ActionMailer::Base.deliveries.last @@ -1282,8 +1282,8 @@ class IssuesControllerTest < ActionController::TestCase journal = issue.journals.last assert_equal '777', issue.custom_value_for(2).value assert_equal 1, journal.details.size - assert_equal '125', journal.old_value(journal.details.first) - assert_equal '777', journal.value(journal.details.first) + assert_equal '125', journal.old_value(journal.details.to_a.first) + assert_equal '777', journal.value(journal.details.to_a.first) end def test_bulk_update_unassign From 76c72d8f116dd49a6b260894a20cbfaac4ee37e4 Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Sat, 14 May 2011 00:19:53 +0200 Subject: [PATCH 669/777] [#414] remove returning which will be removed in future versions of Rails --- app/helpers/journals_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/helpers/journals_helper.rb b/app/helpers/journals_helper.rb index 10785fe6..7519ed36 100644 --- a/app/helpers/journals_helper.rb +++ b/app/helpers/journals_helper.rb @@ -75,7 +75,7 @@ module JournalsHelper end unless journal.notes.blank? - links = returning [] do |l| + links = [].tap do |l| if reply_links l << link_to_remote(image_tag('comment.png'), :title => l(:button_quote), :url => {:controller => controller, :action => action, :id => model, :journal_id => journal}) From 8279144073b4be118d826a23edd2b37b741d92e6 Mon Sep 17 00:00:00 2001 From: Holger Just Date: Sun, 15 May 2011 23:14:02 +0200 Subject: [PATCH 670/777] [#112] Add ChiliProject::Database This module can be used to gather information about the currently used database. --- lib/chili_project/database.rb | 78 ++++++++++++++++++++ test/unit/lib/chili_project/database_test.rb | 39 ++++++++++ 2 files changed, 117 insertions(+) create mode 100644 lib/chili_project/database.rb create mode 100644 test/unit/lib/chili_project/database_test.rb diff --git a/lib/chili_project/database.rb b/lib/chili_project/database.rb new file mode 100644 index 00000000..918704ad --- /dev/null +++ b/lib/chili_project/database.rb @@ -0,0 +1,78 @@ +# ChiliProject is a project management system. +# Copyright (C) 2010-2011 The ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +module ChiliProject + + # This module provides some information about the currently used database + # adapter. It can be used to write code specific to certain database + # vendors which, while not not encouraged, is sometimes necessary due to + # syntax differences. + + module Database + + # This method returns a hash which maps the identifier of the supported + # adapter to a regex matching the adapter_name. + def self.supported_adapters + @adapters ||= ({ + :mysql => /mysql/i, + :postgresql => /postgres/i, + :sqlite => /sqlite/i + }) + end + + # Get the raw namme of the currently used database adapter. + # This string is set by the used adapter gem. + def self.adapter_name + ActiveRecord::Base.connection.adapter_name + end + + # returns the identifier of the currently used database type + def self.name + supported_adapters.find(proc{ [:unknown, //] }) { |adapter, regex| + self.adapter_name =~ regex + }[0] + end + + # Provide helper methods to quickly check the database type + # ChiliProject::Database.mysql? returns true, if we have a MySQL DB + supported_adapters.keys.each do |adapter| + (class << self; self; end).class_eval do + define_method(:"#{adapter.to_s}?"){ send(:name) == adapter } + end + end + + # Return the version of the underlying database engine. + # Set the +raw+ argument to true to return the unmangled string + # from the database. + def self.version(raw = false) + case self.name + when :mysql + version = ActiveRecord::Base.connection.select_value('SELECT VERSION()') + when :postgresql + version = ActiveRecord::Base.connection.select_value('SELECT version()') + version.match(/^PostgreSQL (\S+)/i)[1] unless raw + when :sqlite + if SQLite3.const_defined? 'SQLITE_VERSION' + SQLite3::SQLITE_VERSION + else + SQLite3::Driver::Native::API.sqlite3_libversion + end + end + end + + end +end \ No newline at end of file diff --git a/test/unit/lib/chili_project/database_test.rb b/test/unit/lib/chili_project/database_test.rb new file mode 100644 index 00000000..f4cdf0e0 --- /dev/null +++ b/test/unit/lib/chili_project/database_test.rb @@ -0,0 +1,39 @@ +# ChiliProject is a project management system. +# Copyright (C) 2010-2011 The ChiliProject Team +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require File.expand_path('../../../../test_helper', __FILE__) + +class ChiliProject::DatabaseTest < ActiveSupport::TestCase + setup do + ChiliProject::Database.stubs(:adapter_name).returns "SQLite" + SQLite3::Driver::Native::API.stubs(:sqlite3_libversion).returns "3.6.12" + end + + should "return the correct identifier" do + assert_equal :sqlite, ChiliProject::Database.name + end + + should "be able to use the helper methods" do + assert_equal false, ChiliProject::Database.mysql? + assert_equal false, ChiliProject::Database.postgresql? + assert_equal true, ChiliProject::Database.sqlite? + end + + should "return a version string" do + assert_equal "3.6.12", ChiliProject::Database.version + end +end From d90102420d9704fed197474148477371c59ec2fe Mon Sep 17 00:00:00 2001 From: Holger Just Date: Sun, 15 May 2011 23:15:52 +0200 Subject: [PATCH 671/777] [#112] Adapt database switches to use ChiliProject::Database --- app/models/user.rb | 2 +- db/migrate/20091227112908_change_wiki_contents_text_limit.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 17610e02..693c721e 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -299,7 +299,7 @@ class User < Principal # version. Exact matches will be given priority. def self.find_by_login(login) # force string comparison to be case sensitive on MySQL - type_cast = (ActiveRecord::Base.connection.adapter_name =~ /mysql/i) ? 'BINARY' : '' + type_cast = (ChiliProject::Database.mysql?) ? 'BINARY' : '' # First look for an exact match user = first(:conditions => ["#{type_cast} login = ?", login]) # Fail over to case-insensitive if none was found diff --git a/db/migrate/20091227112908_change_wiki_contents_text_limit.rb b/db/migrate/20091227112908_change_wiki_contents_text_limit.rb index 225f71e6..5e92cf01 100644 --- a/db/migrate/20091227112908_change_wiki_contents_text_limit.rb +++ b/db/migrate/20091227112908_change_wiki_contents_text_limit.rb @@ -3,7 +3,7 @@ class ChangeWikiContentsTextLimit < ActiveRecord::Migration # Migrates MySQL databases only # Postgres would raise an error (see http://dev.rubyonrails.org/ticket/3818) # Not fixed in Rails 2.3.5 - if ActiveRecord::Base.connection.adapter_name =~ /mysql/i + if ChiliProject::Database.mysql? max_size = 16.megabytes change_column :wiki_contents, :text, :text, :limit => max_size change_column :wiki_content_versions, :data, :binary, :limit => max_size From 705c0db00006bb68e6314a0b884e8e62d20beb3a Mon Sep 17 00:00:00 2001 From: Holger Just Date: Mon, 16 May 2011 00:01:09 +0200 Subject: [PATCH 672/777] [#112] Fix failing raw version for postgres --- lib/chili_project/database.rb | 2 +- test/unit/lib/chili_project/database_test.rb | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/lib/chili_project/database.rb b/lib/chili_project/database.rb index 918704ad..3aea3959 100644 --- a/lib/chili_project/database.rb +++ b/lib/chili_project/database.rb @@ -64,7 +64,7 @@ module ChiliProject version = ActiveRecord::Base.connection.select_value('SELECT VERSION()') when :postgresql version = ActiveRecord::Base.connection.select_value('SELECT version()') - version.match(/^PostgreSQL (\S+)/i)[1] unless raw + raw ? version : version.match(/^PostgreSQL (\S+)/i)[1] when :sqlite if SQLite3.const_defined? 'SQLITE_VERSION' SQLite3::SQLITE_VERSION diff --git a/test/unit/lib/chili_project/database_test.rb b/test/unit/lib/chili_project/database_test.rb index f4cdf0e0..1296a0dd 100644 --- a/test/unit/lib/chili_project/database_test.rb +++ b/test/unit/lib/chili_project/database_test.rb @@ -36,4 +36,15 @@ class ChiliProject::DatabaseTest < ActiveSupport::TestCase should "return a version string" do assert_equal "3.6.12", ChiliProject::Database.version end + + should "return long version string for raw==true" do + ChiliProject::Database.stubs(:adapter_name).returns "PostgreSQL" + + raw_version = "PostgreSQL 8.3.11 on x86_64-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1) 4.3.2" + ActiveRecord::Base.connection.stubs(:select_value).returns raw_version + + assert_equal "8.3.11", ChiliProject::Database.version + assert_equal raw_version, ChiliProject::Database.version(true) + end + end From 7b3a2047fd3c75e505d297755b3d027a1315190d Mon Sep 17 00:00:00 2001 From: Holger Just Date: Mon, 16 May 2011 00:03:51 +0200 Subject: [PATCH 673/777] Whitespace fixes --- lib/chili_project/database.rb | 2 +- test/unit/lib/chili_project/database_test.rb | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/chili_project/database.rb b/lib/chili_project/database.rb index 3aea3959..c7837667 100644 --- a/lib/chili_project/database.rb +++ b/lib/chili_project/database.rb @@ -46,7 +46,7 @@ module ChiliProject self.adapter_name =~ regex }[0] end - + # Provide helper methods to quickly check the database type # ChiliProject::Database.mysql? returns true, if we have a MySQL DB supported_adapters.keys.each do |adapter| diff --git a/test/unit/lib/chili_project/database_test.rb b/test/unit/lib/chili_project/database_test.rb index 1296a0dd..e47c7a2f 100644 --- a/test/unit/lib/chili_project/database_test.rb +++ b/test/unit/lib/chili_project/database_test.rb @@ -22,7 +22,7 @@ class ChiliProject::DatabaseTest < ActiveSupport::TestCase ChiliProject::Database.stubs(:adapter_name).returns "SQLite" SQLite3::Driver::Native::API.stubs(:sqlite3_libversion).returns "3.6.12" end - + should "return the correct identifier" do assert_equal :sqlite, ChiliProject::Database.name end @@ -32,19 +32,19 @@ class ChiliProject::DatabaseTest < ActiveSupport::TestCase assert_equal false, ChiliProject::Database.postgresql? assert_equal true, ChiliProject::Database.sqlite? end - + should "return a version string" do assert_equal "3.6.12", ChiliProject::Database.version end - + should "return long version string for raw==true" do ChiliProject::Database.stubs(:adapter_name).returns "PostgreSQL" raw_version = "PostgreSQL 8.3.11 on x86_64-pc-linux-gnu, compiled by GCC gcc-4.3.real (Debian 4.3.2-1.1) 4.3.2" ActiveRecord::Base.connection.stubs(:select_value).returns raw_version - + assert_equal "8.3.11", ChiliProject::Database.version assert_equal raw_version, ChiliProject::Database.version(true) end - + end From 9cb4feefceaa39a2fb5a5ba096797c593ddc7c3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20Scha=CC=88fer?= Date: Sat, 14 May 2011 17:53:29 +0200 Subject: [PATCH 674/777] Update the watcher list on click on "watch". #311 Based on a patch contributed by Price M. --- app/controllers/watchers_controller.rb | 7 ++++++- app/views/issues/_action_menu.rhtml | 2 +- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb index ad8d8be2..11699c35 100644 --- a/app/controllers/watchers_controller.rb +++ b/app/controllers/watchers_controller.rb @@ -90,7 +90,12 @@ private format.js do render(:update) do |page| replace_ids.each do |replace_id| - page.replace_html replace_id, watcher_link(@watched, user, :replace => replace_ids) + case replace_id + when 'watchers' + page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched} + else + page.replace_html replace_id, watcher_link(@watched, user, :replace => replace_ids) + end end end end diff --git a/app/views/issues/_action_menu.rhtml b/app/views/issues/_action_menu.rhtml index 3f4d89e2..0ec82ecd 100644 --- a/app/views/issues/_action_menu.rhtml +++ b/app/views/issues/_action_menu.rhtml @@ -2,7 +2,7 @@ <%= link_to_if_authorized(l(:button_update), {:controller => 'issues', :action => 'edit', :id => @issue }, :onclick => 'showAndScrollTo("update", "notes"); return false;', :class => 'icon icon-edit', :accesskey => accesskey(:edit)) %> <%= link_to_if_authorized l(:button_log_time), {:controller => 'timelog', :action => 'new', :issue_id => @issue}, :class => 'icon icon-time-add' %> <% replace_watcher ||= 'watcher' %> -<%= watcher_tag(@issue, User.current, {:id => replace_watcher, :replace => ['watcher','watcher2']}) %> +<%= watcher_tag(@issue, User.current, {:id => replace_watcher, :replace => ['watchers','watcher','watcher2']}) %> <%= link_to_if_authorized l(:button_duplicate), {:controller => 'issues', :action => 'new', :project_id => @project, :copy_from => @issue }, :class => 'icon icon-duplicate' %> <%= link_to_if_authorized l(:button_copy), {:controller => 'issue_moves', :action => 'new', :id => @issue, :copy_options => {:copy => 't'}}, :class => 'icon icon-copy' %> <%= link_to_if_authorized l(:button_move), {:controller => 'issue_moves', :action => 'new', :id => @issue}, :class => 'icon icon-move' %> From 508b23cf41f345d82ab76eb0e66375fc10b2d1bd Mon Sep 17 00:00:00 2001 From: Gregor Schmidt Date: Tue, 17 May 2011 18:15:34 +0200 Subject: [PATCH 675/777] [#416] Watcher links work using of css selectors instead of ids --- app/controllers/watchers_controller.rb | 36 ++++++++++++++++++++------ app/helpers/watchers_helper.rb | 36 ++++++++++++-------------- app/views/boards/show.rhtml | 2 +- app/views/issues/_action_menu.rhtml | 3 +-- app/views/messages/show.rhtml | 2 +- app/views/wiki/date_index.html.erb | 2 +- app/views/wiki/index.html.erb | 2 +- app/views/wiki/show.rhtml | 2 +- 8 files changed, 50 insertions(+), 35 deletions(-) diff --git a/app/controllers/watchers_controller.rb b/app/controllers/watchers_controller.rb index 11699c35..a7a9abfd 100644 --- a/app/controllers/watchers_controller.rb +++ b/app/controllers/watchers_controller.rb @@ -78,23 +78,43 @@ private @watched.set_watcher(user, watching) if params[:replace].present? if params[:replace].is_a? Array - replace_ids = params[:replace] + replace_selectors = params[:replace] else - replace_ids = [params[:replace]] + replace_selectors = params[:replace].split(',').map(&:strip) end else - replace_ids = ['watcher'] + replace_selectors = ['#watcher'] end + + watcher_partial = lambda do + render_to_string(:partial => 'watchers/watchers', :locals => {:watched => @watched}) + end + respond_to do |format| format.html { redirect_to :back } format.js do render(:update) do |page| - replace_ids.each do |replace_id| - case replace_id - when 'watchers' - page.replace_html 'watchers', :partial => 'watchers/watchers', :locals => {:watched => @watched} + replace_selectors.each do |selector| + next if selector.blank? + + case selector + when '#watchers' + page.select('#watchers').each do |node| + node.update watcher_partial.call + end else - page.replace_html replace_id, watcher_link(@watched, user, :replace => replace_ids) + page.select(selector).each do |node| + options = {:replace => replace_selectors} + + last_selector = selector.split(' ').last + if last_selector.starts_with? '.' + options[:class] = last_selector[1..-1] + elsif last_selector.starts_with? '#' + options[:id] = last_selector[1..-1] + end + + node.replace watcher_link(@watched, user, options) + end end end end diff --git a/app/helpers/watchers_helper.rb b/app/helpers/watchers_helper.rb index 2695ce9f..b336233d 100644 --- a/app/helpers/watchers_helper.rb +++ b/app/helpers/watchers_helper.rb @@ -17,32 +17,28 @@ module WatchersHelper - # Valid options - # * :id - the element id - # * :replace - a string or array of element ids that will be - # replaced - def watcher_tag(object, user, options={:replace => 'watcher'}) - id = options[:id] - id ||= options[:replace] if options[:replace].is_a? String - content_tag("span", watcher_link(object, user, options), :id => id) - end - - # Valid options - # * :replace - a string or array of element ids that will be - # replaced - def watcher_link(object, user, options={:replace => 'watcher'}) + # Create a link to watch/unwatch object + # + # * :replace - a string or array of strings with css selectors that will be updated, whenever the watcher status is changed + def watcher_link(object, user, options = {:replace => '.watcher_link', :class => 'watcher_link'}) + options = options.with_indifferent_access + raise ArgumentError, 'Missing :replace option in options hash' if options['replace'].blank? + return '' unless user && user.logged? && object.respond_to?('watched_by?') + watched = object.watched_by?(user) url = {:controller => 'watchers', :action => (watched ? 'unwatch' : 'watch'), :object_type => object.class.to_s.underscore, :object_id => object.id, - :replace => options[:replace]} - link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)), - {:url => url}, - :href => url_for(url), - :class => (watched ? 'icon icon-fav' : 'icon icon-fav-off')) - + :replace => options.delete('replace')} + + url_options = {:url => url} + + html_options = options.merge(:href => url_for(url)) + html_options[:class] += watched ? ' icon icon-fav' : ' icon icon-fav-off' + + link_to_remote((watched ? l(:button_unwatch) : l(:button_watch)), url_options, html_options) end # Returns a comma separated list of users watching the given object diff --git a/app/views/boards/show.rhtml b/app/views/boards/show.rhtml index c4a08b29..595038e8 100644 --- a/app/views/boards/show.rhtml +++ b/app/views/boards/show.rhtml @@ -5,7 +5,7 @@ {:controller => 'messages', :action => 'new', :board_id => @board}, :class => 'icon icon-add', :onclick => 'Element.show("add-message"); Form.Element.focus("message_subject"); return false;' %> -<%= watcher_tag(@board, User.current) %> + <%= watcher_link(@board, User.current) %>
    "; + var isBuggy = typeof el.tBodies[0] == "undefined"; + el = null; + return isBuggy; + } + } catch (e) { + return true; + } + })(); + + var LINK_ELEMENT_INNERHTML_BUGGY = (function() { + try { + var el = document.createElement('div'); + el.innerHTML = ""; + var isBuggy = (el.childNodes.length === 0); + el = null; + return isBuggy; + } catch(e) { + return true; + } + })(); + + var ANY_INNERHTML_BUGGY = SELECT_ELEMENT_INNERHTML_BUGGY || + TABLE_ELEMENT_INNERHTML_BUGGY || LINK_ELEMENT_INNERHTML_BUGGY; + + var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { + var s = document.createElement("script"), + isBuggy = false; + try { + s.appendChild(document.createTextNode("")); + isBuggy = !s.firstChild || + s.firstChild && s.firstChild.nodeType !== 3; + } catch (e) { + isBuggy = true; + } + s = null; + return isBuggy; + })(); + + + function update(element, content) { + element = $(element); + var purgeElement = Element._purgeElement; + + var descendants = element.getElementsByTagName('*'), + i = descendants.length; + while (i--) purgeElement(descendants[i]); + + if (content && content.toElement) + content = content.toElement(); + + if (Object.isElement(content)) + return element.update().insert(content); + + content = Object.toHTML(content); + + var tagName = element.tagName.toUpperCase(); + + if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { + element.text = content; + return element; + } + + if (ANY_INNERHTML_BUGGY) { + if (tagName in Element._insertionTranslations.tags) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { + element.appendChild(node) + }); + } else if (LINK_ELEMENT_INNERHTML_BUGGY && Object.isString(content) && content.indexOf(' -1) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + var nodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts(), true); + nodes.each(function(node) { element.appendChild(node) }); + } + else { + element.innerHTML = content.stripScripts(); + } + } + else { + element.innerHTML = content.stripScripts(); + } + + content.evalScripts.bind(content).defer(); + return element; + } + + return update; + })(), replace: function(element, content) { element = $(element); @@ -1679,28 +2119,35 @@ Element.Methods = { element = $(element); var result = '<' + element.tagName.toLowerCase(); $H({'id': 'id', 'className': 'class'}).each(function(pair) { - var property = pair.first(), attribute = pair.last(); - var value = (element[property] || '').toString(); + var property = pair.first(), + attribute = pair.last(), + value = (element[property] || '').toString(); if (value) result += ' ' + attribute + '=' + value.inspect(true); }); return result + '>'; }, - recursivelyCollect: function(element, property) { + recursivelyCollect: function(element, property, maximumLength) { element = $(element); + maximumLength = maximumLength || -1; var elements = []; - while (element = element[property]) + + while (element = element[property]) { if (element.nodeType == 1) elements.push(Element.extend(element)); + if (elements.length == maximumLength) + break; + } + return elements; }, ancestors: function(element) { - return $(element).recursivelyCollect('parentNode'); + return Element.recursivelyCollect(element, 'parentNode'); }, descendants: function(element) { - return $(element).select("*"); + return Element.select(element, "*"); }, firstDescendant: function(element) { @@ -1710,78 +2157,96 @@ Element.Methods = { }, immediateDescendants: function(element) { - if (!(element = $(element).firstChild)) return []; - while (element && element.nodeType != 1) element = element.nextSibling; - if (element) return [element].concat($(element).nextSiblings()); - return []; + var results = [], child = $(element).firstChild; + while (child) { + if (child.nodeType === 1) { + results.push(Element.extend(child)); + } + child = child.nextSibling; + } + return results; }, - previousSiblings: function(element) { - return $(element).recursivelyCollect('previousSibling'); + previousSiblings: function(element, maximumLength) { + return Element.recursivelyCollect(element, 'previousSibling'); }, nextSiblings: function(element) { - return $(element).recursivelyCollect('nextSibling'); + return Element.recursivelyCollect(element, 'nextSibling'); }, siblings: function(element) { element = $(element); - return element.previousSiblings().reverse().concat(element.nextSiblings()); + return Element.previousSiblings(element).reverse() + .concat(Element.nextSiblings(element)); }, match: function(element, selector) { + element = $(element); if (Object.isString(selector)) - selector = new Selector(selector); - return selector.match($(element)); + return Prototype.Selector.match(element, selector); + return selector.match(element); }, up: function(element, expression, index) { element = $(element); if (arguments.length == 1) return $(element.parentNode); - var ancestors = element.ancestors(); + var ancestors = Element.ancestors(element); return Object.isNumber(expression) ? ancestors[expression] : - Selector.findElement(ancestors, expression, index); + Prototype.Selector.find(ancestors, expression, index); }, down: function(element, expression, index) { element = $(element); - if (arguments.length == 1) return element.firstDescendant(); - return Object.isNumber(expression) ? element.descendants()[expression] : + if (arguments.length == 1) return Element.firstDescendant(element); + return Object.isNumber(expression) ? Element.descendants(element)[expression] : Element.select(element, expression)[index || 0]; }, previous: function(element, expression, index) { element = $(element); - if (arguments.length == 1) return $(Selector.handlers.previousElementSibling(element)); - var previousSiblings = element.previousSiblings(); - return Object.isNumber(expression) ? previousSiblings[expression] : - Selector.findElement(previousSiblings, expression, index); + if (Object.isNumber(expression)) index = expression, expression = false; + if (!Object.isNumber(index)) index = 0; + + if (expression) { + return Prototype.Selector.find(element.previousSiblings(), expression, index); + } else { + return element.recursivelyCollect("previousSibling", index + 1)[index]; + } }, next: function(element, expression, index) { element = $(element); - if (arguments.length == 1) return $(Selector.handlers.nextElementSibling(element)); - var nextSiblings = element.nextSiblings(); - return Object.isNumber(expression) ? nextSiblings[expression] : - Selector.findElement(nextSiblings, expression, index); + if (Object.isNumber(expression)) index = expression, expression = false; + if (!Object.isNumber(index)) index = 0; + + if (expression) { + return Prototype.Selector.find(element.nextSiblings(), expression, index); + } else { + var maximumLength = Object.isNumber(index) ? index + 1 : 1; + return element.recursivelyCollect("nextSibling", index + 1)[index]; + } }, - select: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element, args); + + select: function(element) { + element = $(element); + var expressions = Array.prototype.slice.call(arguments, 1).join(', '); + return Prototype.Selector.select(expressions, element); }, - adjacent: function() { - var args = $A(arguments), element = $(args.shift()); - return Selector.findChildElements(element.parentNode, args).without(element); + adjacent: function(element) { + element = $(element); + var expressions = Array.prototype.slice.call(arguments, 1).join(', '); + return Prototype.Selector.select(expressions, element.parentNode).without(element); }, identify: function(element) { element = $(element); - var id = element.readAttribute('id'), self = arguments.callee; + var id = Element.readAttribute(element, 'id'); if (id) return id; - do { id = 'anonymous_element_' + self.counter++ } while ($(id)); - element.writeAttribute('id', id); + do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); + Element.writeAttribute(element, 'id', id); return id; }, @@ -1820,11 +2285,11 @@ Element.Methods = { }, getHeight: function(element) { - return $(element).getDimensions().height; + return Element.getDimensions(element).height; }, getWidth: function(element) { - return $(element).getDimensions().width; + return Element.getDimensions(element).width; }, classNames: function(element) { @@ -1840,7 +2305,7 @@ Element.Methods = { addClassName: function(element, className) { if (!(element = $(element))) return; - if (!element.hasClassName(className)) + if (!Element.hasClassName(element, className)) element.className += (element.className ? ' ' : '') + className; return element; }, @@ -1854,11 +2319,10 @@ Element.Methods = { toggleClassName: function(element, className) { if (!(element = $(element))) return; - return element[element.hasClassName(className) ? - 'removeClassName' : 'addClassName'](className); + return Element[Element.hasClassName(element, className) ? + 'removeClassName' : 'addClassName'](element, className); }, - // removes whitespace-only text node children cleanWhitespace: function(element) { element = $(element); var node = element.firstChild; @@ -1892,7 +2356,7 @@ Element.Methods = { scrollTo: function(element) { element = $(element); - var pos = element.cumulativeOffset(); + var pos = Element.cumulativeOffset(element); window.scrollTo(pos[0], pos[1]); return element; }, @@ -1938,37 +2402,12 @@ Element.Methods = { return element; }, - getDimensions: function(element) { - element = $(element); - var display = element.getStyle('display'); - if (display != 'none' && display != null) // Safari bug - return {width: element.offsetWidth, height: element.offsetHeight}; - - // All *Width and *Height properties give 0 on elements with display none, - // so enable the element temporarily - var els = element.style; - var originalVisibility = els.visibility; - var originalPosition = els.position; - var originalDisplay = els.display; - els.visibility = 'hidden'; - els.position = 'absolute'; - els.display = 'block'; - var originalWidth = element.clientWidth; - var originalHeight = element.clientHeight; - els.display = originalDisplay; - els.position = originalPosition; - els.visibility = originalVisibility; - return {width: originalWidth, height: originalHeight}; - }, - makePositioned: function(element) { element = $(element); var pos = Element.getStyle(element, 'position'); if (pos == 'static' || !pos) { element._madePositioned = true; element.style.position = 'relative'; - // Opera returns the offset relative to the positioning context, when an - // element is position relative but top and left have not been defined if (Prototype.Browser.Opera) { element.style.top = 0; element.style.left = 0; @@ -2007,117 +2446,6 @@ Element.Methods = { return element; }, - cumulativeOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - positionedOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - element = element.offsetParent; - if (element) { - if (element.tagName.toUpperCase() == 'BODY') break; - var p = Element.getStyle(element, 'position'); - if (p !== 'static') break; - } - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - absolutize: function(element) { - element = $(element); - if (element.getStyle('position') == 'absolute') return element; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - var offsets = element.positionedOffset(); - var top = offsets[1]; - var left = offsets[0]; - var width = element.clientWidth; - var height = element.clientHeight; - - element._originalLeft = left - parseFloat(element.style.left || 0); - element._originalTop = top - parseFloat(element.style.top || 0); - element._originalWidth = element.style.width; - element._originalHeight = element.style.height; - - element.style.position = 'absolute'; - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.width = width + 'px'; - element.style.height = height + 'px'; - return element; - }, - - relativize: function(element) { - element = $(element); - if (element.getStyle('position') == 'relative') return element; - // Position.prepare(); // To be done manually by Scripty when it needs it. - - element.style.position = 'relative'; - var top = parseFloat(element.style.top || 0) - (element._originalTop || 0); - var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); - - element.style.top = top + 'px'; - element.style.left = left + 'px'; - element.style.height = element._originalHeight; - element.style.width = element._originalWidth; - return element; - }, - - cumulativeScrollOffset: function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.scrollTop || 0; - valueL += element.scrollLeft || 0; - element = element.parentNode; - } while (element); - return Element._returnOffset(valueL, valueT); - }, - - getOffsetParent: function(element) { - if (element.offsetParent) return $(element.offsetParent); - if (element == document.body) return $(element); - - while ((element = element.parentNode) && element != document.body) - if (Element.getStyle(element, 'position') != 'static') - return $(element); - - return $(document.body); - }, - - viewportOffset: function(forElement) { - var valueT = 0, valueL = 0; - - var element = forElement; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - - // Safari fix - if (element.offsetParent == document.body && - Element.getStyle(element, 'position') == 'absolute') break; - - } while (element = element.offsetParent); - - element = forElement; - do { - if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { - valueT -= element.scrollTop || 0; - valueL -= element.scrollLeft || 0; - } - } while (element = element.parentNode); - - return Element._returnOffset(valueL, valueT); - }, - clonePosition: function(element, source) { var options = Object.extend({ setLeft: true, @@ -2128,28 +2456,21 @@ Element.Methods = { offsetLeft: 0 }, arguments[2] || { }); - // find page position of source source = $(source); - var p = source.viewportOffset(); + var p = Element.viewportOffset(source), delta = [0, 0], parent = null; - // find coordinate system to use element = $(element); - var delta = [0, 0]; - var parent = null; - // delta [0,0] will do fine with position: fixed elements, - // position:absolute needs offsetParent deltas + if (Element.getStyle(element, 'position') == 'absolute') { - parent = element.getOffsetParent(); - delta = parent.viewportOffset(); + parent = Element.getOffsetParent(element); + delta = Element.viewportOffset(parent); } - // correct by body offsets (fixes Safari) if (parent == document.body) { delta[0] -= document.body.offsetLeft; delta[1] -= document.body.offsetTop; } - // set position if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; if (options.setWidth) element.style.width = source.offsetWidth + 'px'; @@ -2158,10 +2479,9 @@ Element.Methods = { } }; -Element.Methods.identify.counter = 1; - Object.extend(Element.Methods, { getElementsBySelector: Element.Methods.select, + childElements: Element.Methods.immediateDescendants }); @@ -2179,14 +2499,9 @@ if (Prototype.Browser.Opera) { Element.Methods.getStyle = Element.Methods.getStyle.wrap( function(proceed, element, style) { switch (style) { - case 'left': case 'top': case 'right': case 'bottom': - if (proceed(element, 'position') === 'static') return null; case 'height': case 'width': - // returns '0px' for hidden elements; we want it to return null if (!Element.visible(element)) return null; - // returns the border-box dimensions rather than the content-box - // dimensions, so we subtract padding and borders from the value var dim = parseInt(proceed(element, style), 10); if (dim !== element['offset' + style.capitalize()]) @@ -2219,52 +2534,6 @@ if (Prototype.Browser.Opera) { } else if (Prototype.Browser.IE) { - // IE doesn't report offsets correctly for static elements, so we change them - // to "relative" to get the values, then change them back. - Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( - function(proceed, element) { - element = $(element); - // IE throws an error if element is not in document - try { element.offsetParent } - catch(e) { return $(document.body) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - - $w('positionedOffset viewportOffset').each(function(method) { - Element.Methods[method] = Element.Methods[method].wrap( - function(proceed, element) { - element = $(element); - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - var position = element.getStyle('position'); - if (position !== 'static') return proceed(element); - // Trigger hasLayout on the offset parent so that IE6 reports - // accurate offsetTop and offsetLeft values for position: fixed. - var offsetParent = element.getOffsetParent(); - if (offsetParent && offsetParent.getStyle('position') === 'fixed') - offsetParent.setStyle({ zoom: 1 }); - element.setStyle({ position: 'relative' }); - var value = proceed(element); - element.setStyle({ position: position }); - return value; - } - ); - }); - - Element.Methods.cumulativeOffset = Element.Methods.cumulativeOffset.wrap( - function(proceed, element) { - try { element.offsetParent } - catch(e) { return Element._returnOffset(0,0) } - return proceed(element); - } - ); - Element.Methods.getStyle = function(element, style) { element = $(element); style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); @@ -2306,36 +2575,90 @@ else if (Prototype.Browser.IE) { return element; }; - Element._attributeTranslations = { - read: { - names: { - 'class': 'className', - 'for': 'htmlFor' - }, - values: { - _getAttr: function(element, attribute) { - return element.getAttribute(attribute, 2); + Element._attributeTranslations = (function(){ + + var classProp = 'className', + forProp = 'for', + el = document.createElement('div'); + + el.setAttribute(classProp, 'x'); + + if (el.className !== 'x') { + el.setAttribute('class', 'x'); + if (el.className === 'x') { + classProp = 'class'; + } + } + el = null; + + el = document.createElement('label'); + el.setAttribute(forProp, 'x'); + if (el.htmlFor !== 'x') { + el.setAttribute('htmlFor', 'x'); + if (el.htmlFor === 'x') { + forProp = 'htmlFor'; + } + } + el = null; + + return { + read: { + names: { + 'class': classProp, + 'className': classProp, + 'for': forProp, + 'htmlFor': forProp }, - _getAttrNode: function(element, attribute) { - var node = element.getAttributeNode(attribute); - return node ? node.value : ""; - }, - _getEv: function(element, attribute) { - attribute = element.getAttribute(attribute); - return attribute ? attribute.toString().slice(23, -2) : null; - }, - _flag: function(element, attribute) { - return $(element).hasAttribute(attribute) ? attribute : null; - }, - style: function(element) { - return element.style.cssText.toLowerCase(); - }, - title: function(element) { - return element.title; + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute); + }, + _getAttr2: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: (function(){ + + var el = document.createElement('div'), f; + el.onclick = Prototype.emptyFunction; + var value = el.getAttribute('onclick'); + + if (String(value).indexOf('{') > -1) { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + attribute = attribute.toString(); + attribute = attribute.split('{')[1]; + attribute = attribute.split('}')[0]; + return attribute.strip(); + }; + } + else if (value === '') { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + return attribute.strip(); + }; + } + el = null; + return f; + })(), + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } } } } - }; + })(); Element._attributeTranslations.write = { names: Object.extend({ @@ -2363,8 +2686,8 @@ else if (Prototype.Browser.IE) { (function(v) { Object.extend(v, { - href: v._getAttr, - src: v._getAttr, + href: v._getAttr2, + src: v._getAttr2, type: v._getAttr, action: v._getAttrNode, disabled: v._flag, @@ -2391,6 +2714,26 @@ else if (Prototype.Browser.IE) { onchange: v._getEv }); })(Element._attributeTranslations.read.values); + + if (Prototype.BrowserFeatures.ElementExtensions) { + (function() { + function _descendants(element) { + var nodes = element.getElementsByTagName('*'), results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName !== "!") // Filter out comment nodes. + results.push(node); + return results; + } + + Element.Methods.down = function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? _descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + } + })(); + } + } else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { @@ -2409,7 +2752,7 @@ else if (Prototype.Browser.WebKit) { (value < 0.00001) ? 0 : value; if (value == 1) - if(element.tagName.toUpperCase() == 'IMG' && element.width) { + if (element.tagName.toUpperCase() == 'IMG' && element.width) { element.width++; element.width--; } else try { var n = document.createTextNode(' '); @@ -2419,49 +2762,9 @@ else if (Prototype.Browser.WebKit) { return element; }; - - // Safari returns margins on body which is incorrect if the child is absolutely - // positioned. For performance reasons, redefine Element#cumulativeOffset for - // KHTML/WebKit only. - Element.Methods.cumulativeOffset = function(element) { - var valueT = 0, valueL = 0; - do { - valueT += element.offsetTop || 0; - valueL += element.offsetLeft || 0; - if (element.offsetParent == document.body) - if (Element.getStyle(element, 'position') == 'absolute') break; - - element = element.offsetParent; - } while (element); - - return Element._returnOffset(valueL, valueT); - }; } -if (Prototype.Browser.IE || Prototype.Browser.Opera) { - // IE and Opera are missing .innerHTML support for TABLE-related and SELECT elements - Element.Methods.update = function(element, content) { - element = $(element); - - if (content && content.toElement) content = content.toElement(); - if (Object.isElement(content)) return element.update().insert(content); - - content = Object.toHTML(content); - var tagName = element.tagName.toUpperCase(); - - if (tagName in Element._insertionTranslations.tags) { - $A(element.childNodes).each(function(node) { element.removeChild(node) }); - Element._getContentFromAnonymousElement(tagName, content.stripScripts()) - .each(function(node) { element.appendChild(node) }); - } - else element.innerHTML = content.stripScripts(); - - content.evalScripts.bind(content).defer(); - return element; - }; -} - -if ('outerHTML' in document.createElement('div')) { +if ('outerHTML' in document.documentElement) { Element.Methods.replace = function(element, content) { element = $(element); @@ -2475,8 +2778,8 @@ if ('outerHTML' in document.createElement('div')) { var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); if (Element._insertionTranslations.tags[tagName]) { - var nextSibling = element.next(); - var fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + var nextSibling = element.next(), + fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); parent.removeChild(element); if (nextSibling) fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); @@ -2497,12 +2800,27 @@ Element._returnOffset = function(l, t) { return result; }; -Element._getContentFromAnonymousElement = function(tagName, html) { - var div = new Element('div'), t = Element._insertionTranslations.tags[tagName]; - if (t) { - div.innerHTML = t[0] + html + t[1]; - t[2].times(function() { div = div.firstChild }); - } else div.innerHTML = html; +Element._getContentFromAnonymousElement = function(tagName, html, force) { + var div = new Element('div'), + t = Element._insertionTranslations.tags[tagName]; + + var workaround = false; + if (t) workaround = true; + else if (force) { + workaround = true; + t = ['', '', 0]; + } + + if (workaround) { + div.innerHTML = ' ' + t[0] + html + t[1]; + div.removeChild(div.firstChild); + for (var i = t[2]; i--; ) { + div = div.firstChild; + } + } + else { + div.innerHTML = html; + } return $A(div.childNodes); }; @@ -2529,12 +2847,13 @@ Element._insertionTranslations = { }; (function() { - Object.extend(this.tags, { - THEAD: this.tags.TBODY, - TFOOT: this.tags.TBODY, - TH: this.tags.TD + var tags = Element._insertionTranslations.tags; + Object.extend(tags, { + THEAD: tags.TBODY, + TFOOT: tags.TBODY, + TH: tags.TD }); -}).call(Element._insertionTranslations); +})(); Element.Methods.Simulated = { hasAttribute: function(element, attribute) { @@ -2548,41 +2867,81 @@ Element.Methods.ByTag = { }; Object.extend(Element, Element.Methods); -if (!Prototype.BrowserFeatures.ElementExtensions && - document.createElement('div')['__proto__']) { - window.HTMLElement = { }; - window.HTMLElement.prototype = document.createElement('div')['__proto__']; - Prototype.BrowserFeatures.ElementExtensions = true; -} +(function(div) { + + if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { + window.HTMLElement = { }; + window.HTMLElement.prototype = div['__proto__']; + Prototype.BrowserFeatures.ElementExtensions = true; + } + + div = null; + +})(document.createElement('div')); Element.extend = (function() { - if (Prototype.BrowserFeatures.SpecificElementExtensions) + + function checkDeficiency(tagName) { + if (typeof window.Element != 'undefined') { + var proto = window.Element.prototype; + if (proto) { + var id = '_' + (Math.random()+'').slice(2), + el = document.createElement(tagName); + proto[id] = 'x'; + var isBuggy = (el[id] !== 'x'); + delete proto[id]; + el = null; + return isBuggy; + } + } + return false; + } + + function extendElementWith(element, methods) { + for (var property in methods) { + var value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + } + + var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); + + if (Prototype.BrowserFeatures.SpecificElementExtensions) { + if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { + return function(element) { + if (element && typeof element._extendedByPrototype == 'undefined') { + var t = element.tagName; + if (t && (/^(?:object|applet|embed)$/i.test(t))) { + extendElementWith(element, Element.Methods); + extendElementWith(element, Element.Methods.Simulated); + extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); + } + } + return element; + } + } return Prototype.K; + } var Methods = { }, ByTag = Element.Methods.ByTag; var extend = Object.extend(function(element) { - if (!element || element._extendedByPrototype || + if (!element || typeof element._extendedByPrototype != 'undefined' || element.nodeType != 1 || element == window) return element; var methods = Object.clone(Methods), - tagName = element.tagName.toUpperCase(), property, value; + tagName = element.tagName.toUpperCase(); - // extend methods for specific tags if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); - for (property in methods) { - value = methods[property]; - if (Object.isFunction(value) && !(property in element)) - element[property] = value.methodize(); - } + extendElementWith(element, methods); element._extendedByPrototype = Prototype.emptyFunction; return element; }, { refresh: function() { - // extend methods for all tags (Safari doesn't need this) if (!Prototype.BrowserFeatures.ElementExtensions) { Object.extend(Methods, Element.Methods); Object.extend(Methods, Element.Methods.Simulated); @@ -2594,10 +2953,14 @@ Element.extend = (function() { return extend; })(); -Element.hasAttribute = function(element, attribute) { - if (element.hasAttribute) return element.hasAttribute(attribute); - return Element.Methods.Simulated.hasAttribute(element, attribute); -}; +if (document.documentElement.hasAttribute) { + Element.hasAttribute = function(element, attribute) { + return element.hasAttribute(attribute); + }; +} +else { + Element.hasAttribute = Element.Methods.Simulated.hasAttribute; +} Element.addMethods = function(methods) { var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; @@ -2609,7 +2972,8 @@ Element.addMethods = function(methods) { "FORM": Object.clone(Form.Methods), "INPUT": Object.clone(Form.Element.Methods), "SELECT": Object.clone(Form.Element.Methods), - "TEXTAREA": Object.clone(Form.Element.Methods) + "TEXTAREA": Object.clone(Form.Element.Methods), + "BUTTON": Object.clone(Form.Element.Methods) }); } @@ -2661,14 +3025,19 @@ Element.addMethods = function(methods) { klass = 'HTML' + tagName.capitalize() + 'Element'; if (window[klass]) return window[klass]; - window[klass] = { }; - window[klass].prototype = document.createElement(tagName)['__proto__']; - return window[klass]; + var element = document.createElement(tagName), + proto = element['__proto__'] || element.constructor.prototype; + + element = null; + return proto; } + var elementPrototype = window.HTMLElement ? HTMLElement.prototype : + Element.prototype; + if (F.ElementExtensions) { - copy(Element.Methods, HTMLElement.prototype); - copy(Element.Methods.Simulated, HTMLElement.prototype, true); + copy(Element.Methods, elementPrototype); + copy(Element.Methods.Simulated, elementPrototype, true); } if (F.SpecificElementExtensions) { @@ -2686,791 +3055,1948 @@ Element.addMethods = function(methods) { Element.cache = { }; }; + document.viewport = { + getDimensions: function() { - var dimensions = { }, B = Prototype.Browser; - $w('width height').each(function(d) { - var D = d.capitalize(); - if (B.WebKit && !document.evaluate) { - // Safari <3.0 needs self.innerWidth/Height - dimensions[d] = self['inner' + D]; - } else if (B.Opera && parseFloat(window.opera.version()) < 9.5) { - // Opera <9.5 needs document.body.clientWidth/Height - dimensions[d] = document.body['client' + D] - } else { - dimensions[d] = document.documentElement['client' + D]; - } - }); - return dimensions; - }, - - getWidth: function() { - return this.getDimensions().width; - }, - - getHeight: function() { - return this.getDimensions().height; + return { width: this.getWidth(), height: this.getHeight() }; }, getScrollOffsets: function() { return Element._returnOffset( window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, - window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); } }; -/* Portions of the Selector class are derived from Jack Slocum's DomQuery, - * part of YUI-Ext version 0.40, distributed under the terms of an MIT-style - * license. Please see http://www.yui-ext.com/ for more information. */ -var Selector = Class.create({ - initialize: function(expression) { - this.expression = expression.strip(); +(function(viewport) { + var B = Prototype.Browser, doc = document, element, property = {}; - if (this.shouldUseSelectorsAPI()) { - this.mode = 'selectorsAPI'; - } else if (this.shouldUseXPath()) { - this.mode = 'xpath'; - this.compileXPathMatcher(); + function getRootElement() { + if (B.WebKit && !doc.evaluate) + return document; + + if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) + return document.body; + + return document.documentElement; + } + + function define(D) { + if (!element) element = getRootElement(); + + property[D] = 'client' + D; + + viewport['get' + D] = function() { return element[property[D]] }; + return viewport['get' + D](); + } + + viewport.getWidth = define.curry('Width'); + + viewport.getHeight = define.curry('Height'); +})(document.viewport); + + +Element.Storage = { + UID: 1 +}; + +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return; + + var uid; + if (element === window) { + uid = 0; } else { - this.mode = "normal"; - this.compileMatcher(); + if (typeof element._prototypeUID === "undefined") + element._prototypeUID = Element.Storage.UID++; + uid = element._prototypeUID; } + if (!Element.Storage[uid]) + Element.Storage[uid] = $H(); + + return Element.Storage[uid]; }, - shouldUseXPath: function() { - if (!Prototype.BrowserFeatures.XPath) return false; + store: function(element, key, value) { + if (!(element = $(element))) return; - var e = this.expression; - - // Safari 3 chokes on :*-of-type and :empty - if (Prototype.Browser.WebKit && - (e.include("-of-type") || e.include(":empty"))) - return false; - - // XPath can't do namespaced attributes, nor can it read - // the "checked" property from DOM nodes - if ((/(\[[\w-]*?:|:checked)/).test(e)) - return false; - - return true; - }, - - shouldUseSelectorsAPI: function() { - if (!Prototype.BrowserFeatures.SelectorsAPI) return false; - - if (!Selector._div) Selector._div = new Element('div'); - - // Make sure the browser treats the selector as valid. Test on an - // isolated element to minimize cost of this check. - try { - Selector._div.querySelector(this.expression); - } catch(e) { - return false; + if (arguments.length === 2) { + Element.getStorage(element).update(key); + } else { + Element.getStorage(element).set(key, value); } - return true; + return element; }, - compileMatcher: function() { - var e = this.expression, ps = Selector.patterns, h = Selector.handlers, - c = Selector.criteria, le, p, m; + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + var hash = Element.getStorage(element), value = hash.get(key); - if (Selector._cache[e]) { - this.matcher = Selector._cache[e]; - return; + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; } - this.matcher = ["this.matcher = function(root) {", - "var r = root, h = Selector.handlers, c = false, n;"]; + return value; + }, - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - this.matcher.push(Object.isFunction(c[i]) ? c[i](m) : - new Template(c[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } + clone: function(element, deep) { + if (!(element = $(element))) return; + var clone = element.cloneNode(deep); + clone._prototypeUID = void 0; + if (deep) { + var descendants = Element.select(clone, '*'), + i = descendants.length; + while (i--) { + descendants[i]._prototypeUID = void 0; } } - - this.matcher.push("return h.unique(n);\n}"); - eval(this.matcher.join('\n')); - Selector._cache[this.expression] = this.matcher; + return Element.extend(clone); }, - compileXPathMatcher: function() { - var e = this.expression, ps = Selector.patterns, - x = Selector.xpath, le, m; + purge: function(element) { + if (!(element = $(element))) return; + var purgeElement = Element._purgeElement; - if (Selector._cache[e]) { - this.xpath = Selector._cache[e]; return; - } + purgeElement(element); - this.matcher = ['.//*']; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - if (m = e.match(ps[i])) { - this.matcher.push(Object.isFunction(x[i]) ? x[i](m) : - new Template(x[i]).evaluate(m)); - e = e.replace(m[0], ''); - break; - } - } - } + var descendants = element.getElementsByTagName('*'), + i = descendants.length; - this.xpath = this.matcher.join(''); - Selector._cache[this.expression] = this.xpath; - }, + while (i--) purgeElement(descendants[i]); - findElements: function(root) { - root = root || document; - var e = this.expression, results; - - switch (this.mode) { - case 'selectorsAPI': - // querySelectorAll queries document-wide, then filters to descendants - // of the context element. That's not what we want. - // Add an explicit context to the selector if necessary. - if (root !== document) { - var oldId = root.id, id = $(root).identify(); - e = "#" + id + " " + e; - } - - results = $A(root.querySelectorAll(e)).map(Element.extend); - root.id = oldId; - - return results; - case 'xpath': - return document._getElementsByXPath(this.xpath, root); - default: - return this.matcher(root); - } - }, - - match: function(element) { - this.tokens = []; - - var e = this.expression, ps = Selector.patterns, as = Selector.assertions; - var le, p, m; - - while (e && le !== e && (/\S/).test(e)) { - le = e; - for (var i in ps) { - p = ps[i]; - if (m = e.match(p)) { - // use the Selector.assertions methods unless the selector - // is too complex. - if (as[i]) { - this.tokens.push([i, Object.clone(m)]); - e = e.replace(m[0], ''); - } else { - // reluctantly do a document-wide search - // and look for a match in the array - return this.findElements(document).include(element); - } - } - } - } - - var match = true, name, matches; - for (var i = 0, token; token = this.tokens[i]; i++) { - name = token[0], matches = token[1]; - if (!Selector.assertions[name](element, matches)) { - match = false; break; - } - } - - return match; - }, - - toString: function() { - return this.expression; - }, - - inspect: function() { - return "#"; + return null; } }); -Object.extend(Selector, { - _cache: { }, +(function() { - xpath: { - descendant: "//*", - child: "/*", - adjacent: "/following-sibling::*[1]", - laterSibling: '/following-sibling::*', - tagName: function(m) { - if (m[1] == '*') return ''; - return "[local-name()='" + m[1].toLowerCase() + - "' or local-name()='" + m[1].toUpperCase() + "']"; - }, - className: "[contains(concat(' ', @class, ' '), ' #{1} ')]", - id: "[@id='#{1}']", - attrPresence: function(m) { - m[1] = m[1].toLowerCase(); - return new Template("[@#{1}]").evaluate(m); - }, - attr: function(m) { - m[1] = m[1].toLowerCase(); - m[3] = m[5] || m[6]; - return new Template(Selector.xpath.operators[m[2]]).evaluate(m); - }, - pseudo: function(m) { - var h = Selector.xpath.pseudos[m[1]]; - if (!h) return ''; - if (Object.isFunction(h)) return h(m); - return new Template(Selector.xpath.pseudos[m[1]]).evaluate(m); - }, - operators: { - '=': "[@#{1}='#{3}']", - '!=': "[@#{1}!='#{3}']", - '^=': "[starts-with(@#{1}, '#{3}')]", - '$=': "[substring(@#{1}, (string-length(@#{1}) - string-length('#{3}') + 1))='#{3}']", - '*=': "[contains(@#{1}, '#{3}')]", - '~=': "[contains(concat(' ', @#{1}, ' '), ' #{3} ')]", - '|=': "[contains(concat('-', @#{1}, '-'), '-#{3}-')]" - }, - pseudos: { - 'first-child': '[not(preceding-sibling::*)]', - 'last-child': '[not(following-sibling::*)]', - 'only-child': '[not(preceding-sibling::* or following-sibling::*)]', - 'empty': "[count(*) = 0 and (count(text()) = 0)]", - 'checked': "[@checked]", - 'disabled': "[(@disabled) and (@type!='hidden')]", - 'enabled': "[not(@disabled) and (@type!='hidden')]", - 'not': function(m) { - var e = m[6], p = Selector.patterns, - x = Selector.xpath, le, v; + function toDecimal(pctString) { + var match = pctString.match(/^(\d+)%?$/i); + if (!match) return null; + return (Number(match[1]) / 100); + } - var exclusion = []; - while (e && le != e && (/\S/).test(e)) { - le = e; - for (var i in p) { - if (m = e.match(p[i])) { - v = Object.isFunction(x[i]) ? x[i](m) : new Template(x[i]).evaluate(m); - exclusion.push("(" + v.substring(1, v.length - 1) + ")"); - e = e.replace(m[0], ''); - break; - } - } - } - return "[not(" + exclusion.join(" and ") + ")]"; - }, - 'nth-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./preceding-sibling::*) + 1) ", m); - }, - 'nth-last-child': function(m) { - return Selector.xpath.pseudos.nth("(count(./following-sibling::*) + 1) ", m); - }, - 'nth-of-type': function(m) { - return Selector.xpath.pseudos.nth("position() ", m); - }, - 'nth-last-of-type': function(m) { - return Selector.xpath.pseudos.nth("(last() + 1 - position()) ", m); - }, - 'first-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-of-type'](m); - }, - 'last-of-type': function(m) { - m[6] = "1"; return Selector.xpath.pseudos['nth-last-of-type'](m); - }, - 'only-of-type': function(m) { - var p = Selector.xpath.pseudos; return p['first-of-type'](m) + p['last-of-type'](m); - }, - nth: function(fragment, m) { - var mm, formula = m[6], predicate; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - if (mm = formula.match(/^(\d+)$/)) // digit only - return '[' + fragment + "= " + mm[1] + ']'; - if (mm = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (mm[1] == "-") mm[1] = -1; - var a = mm[1] ? Number(mm[1]) : 1; - var b = mm[2] ? Number(mm[2]) : 0; - predicate = "[((#{fragment} - #{b}) mod #{a} = 0) and " + - "((#{fragment} - #{b}) div #{a} >= 0)]"; - return new Template(predicate).evaluate({ - fragment: fragment, a: a, b: b }); - } - } + function getPixelValue(value, property, context) { + var element = null; + if (Object.isElement(value)) { + element = value; + value = element.getStyle(property); } - }, - criteria: { - tagName: 'n = h.tagName(n, r, "#{1}", c); c = false;', - className: 'n = h.className(n, r, "#{1}", c); c = false;', - id: 'n = h.id(n, r, "#{1}", c); c = false;', - attrPresence: 'n = h.attrPresence(n, r, "#{1}", c); c = false;', - attr: function(m) { - m[3] = (m[5] || m[6]); - return new Template('n = h.attr(n, r, "#{1}", "#{3}", "#{2}", c); c = false;').evaluate(m); - }, - pseudo: function(m) { - if (m[6]) m[6] = m[6].replace(/"/g, '\\"'); - return new Template('n = h.pseudo(n, "#{1}", "#{6}", r, c); c = false;').evaluate(m); - }, - descendant: 'c = "descendant";', - child: 'c = "child";', - adjacent: 'c = "adjacent";', - laterSibling: 'c = "laterSibling";' - }, - - patterns: { - // combinators must be listed first - // (and descendant needs to be last combinator) - laterSibling: /^\s*~\s*/, - child: /^\s*>\s*/, - adjacent: /^\s*\+\s*/, - descendant: /^\s/, - - // selectors follow - tagName: /^\s*(\*|[\w\-]+)(\b|$)?/, - id: /^#([\w\-\*]+)(\b|$)/, - className: /^\.([\w\-\*]+)(\b|$)/, - pseudo: -/^:((first|last|nth|nth-last|only)(-child|-of-type)|empty|checked|(en|dis)abled|not)(\((.*?)\))?(\b|$|(?=\s|[:+~>]))/, - attrPresence: /^\[((?:[\w]+:)?[\w]+)\]/, - attr: /\[((?:[\w-]*:)?[\w-]+)\s*(?:([!^$*~|]?=)\s*((['"])([^\4]*?)\4|([^'"][^\]]*?)))?\]/ - }, - - // for Selector.match and Element#match - assertions: { - tagName: function(element, matches) { - return matches[1].toUpperCase() == element.tagName.toUpperCase(); - }, - - className: function(element, matches) { - return Element.hasClassName(element, matches[1]); - }, - - id: function(element, matches) { - return element.id === matches[1]; - }, - - attrPresence: function(element, matches) { - return Element.hasAttribute(element, matches[1]); - }, - - attr: function(element, matches) { - var nodeValue = Element.readAttribute(element, matches[1]); - return nodeValue && Selector.operators[matches[2]](nodeValue, matches[5] || matches[6]); + if (value === null) { + return null; } - }, - handlers: { - // UTILITY FUNCTIONS - // joins two collections - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - a.push(node); - return a; - }, + if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) { + return window.parseFloat(value); + } - // marks an array of nodes for counting - mark: function(nodes) { - var _true = Prototype.emptyFunction; - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = _true; - return nodes; - }, + var isPercentage = value.include('%'), isViewport = (context === document.viewport); - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node._countedByPrototype = undefined; - return nodes; - }, + if (/\d/.test(value) && element && element.runtimeStyle && !(isPercentage && isViewport)) { + var style = element.style.left, rStyle = element.runtimeStyle.left; + element.runtimeStyle.left = element.currentStyle.left; + element.style.left = value || 0; + value = element.style.pixelLeft; + element.style.left = style; + element.runtimeStyle.left = rStyle; - // mark each child node with its position (for nth calls) - // "ofType" flag indicates whether we're indexing for nth-of-type - // rather than nth-child - index: function(parentNode, reverse, ofType) { - parentNode._countedByPrototype = Prototype.emptyFunction; - if (reverse) { - for (var nodes = parentNode.childNodes, i = nodes.length - 1, j = 1; i >= 0; i--) { - var node = nodes[i]; - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; + return value; + } + + if (element && isPercentage) { + context = context || element.parentNode; + var decimal = toDecimal(value); + var whole = null; + var position = element.getStyle('position'); + + var isHorizontal = property.include('left') || property.include('right') || + property.include('width'); + + var isVertical = property.include('top') || property.include('bottom') || + property.include('height'); + + if (context === document.viewport) { + if (isHorizontal) { + whole = document.viewport.getWidth(); + } else if (isVertical) { + whole = document.viewport.getHeight(); } } else { - for (var i = 0, j = 1, nodes = parentNode.childNodes; node = nodes[i]; i++) - if (node.nodeType == 1 && (!ofType || node._countedByPrototype)) node.nodeIndex = j++; - } - }, - - // filters out duplicates and extends all nodes - unique: function(nodes) { - if (nodes.length == 0) return nodes; - var results = [], n; - for (var i = 0, l = nodes.length; i < l; i++) - if (!(n = nodes[i])._countedByPrototype) { - n._countedByPrototype = Prototype.emptyFunction; - results.push(Element.extend(n)); + if (isHorizontal) { + whole = $(context).measure('width'); + } else if (isVertical) { + whole = $(context).measure('height'); } - return Selector.handlers.unmark(results); - }, - - // COMBINATOR FUNCTIONS - descendant: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName('*')); - return results; - }, - - child: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) { - for (var j = 0, child; child = node.childNodes[j]; j++) - if (child.nodeType == 1 && child.tagName != '!') results.push(child); } - return results; - }, - adjacent: function(nodes) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - var next = this.nextElementSibling(node); - if (next) results.push(next); - } - return results; - }, - - laterSibling: function(nodes) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - h.concat(results, Element.nextSiblings(node)); - return results; - }, - - nextElementSibling: function(node) { - while (node = node.nextSibling) - if (node.nodeType == 1) return node; - return null; - }, - - previousElementSibling: function(node) { - while (node = node.previousSibling) - if (node.nodeType == 1) return node; - return null; - }, - - // TOKEN FUNCTIONS - tagName: function(nodes, root, tagName, combinator) { - var uTagName = tagName.toUpperCase(); - var results = [], h = Selector.handlers; - if (nodes) { - if (combinator) { - // fastlane for ordinary descendant combinators - if (combinator == "descendant") { - for (var i = 0, node; node = nodes[i]; i++) - h.concat(results, node.getElementsByTagName(tagName)); - return results; - } else nodes = this[combinator](nodes); - if (tagName == "*") return nodes; - } - for (var i = 0, node; node = nodes[i]; i++) - if (node.tagName.toUpperCase() === uTagName) results.push(node); - return results; - } else return root.getElementsByTagName(tagName); - }, - - id: function(nodes, root, id, combinator) { - var targetNode = $(id), h = Selector.handlers; - if (!targetNode) return []; - if (!nodes && root == document) return [targetNode]; - if (nodes) { - if (combinator) { - if (combinator == 'child') { - for (var i = 0, node; node = nodes[i]; i++) - if (targetNode.parentNode == node) return [targetNode]; - } else if (combinator == 'descendant') { - for (var i = 0, node; node = nodes[i]; i++) - if (Element.descendantOf(targetNode, node)) return [targetNode]; - } else if (combinator == 'adjacent') { - for (var i = 0, node; node = nodes[i]; i++) - if (Selector.handlers.previousElementSibling(targetNode) == node) - return [targetNode]; - } else nodes = h[combinator](nodes); - } - for (var i = 0, node; node = nodes[i]; i++) - if (node == targetNode) return [targetNode]; - return []; - } - return (targetNode && Element.descendantOf(targetNode, root)) ? [targetNode] : []; - }, - - className: function(nodes, root, className, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - return Selector.handlers.byClassName(nodes, root, className); - }, - - byClassName: function(nodes, root, className) { - if (!nodes) nodes = Selector.handlers.descendant([root]); - var needle = ' ' + className + ' '; - for (var i = 0, results = [], node, nodeClassName; node = nodes[i]; i++) { - nodeClassName = node.className; - if (nodeClassName.length == 0) continue; - if (nodeClassName == className || (' ' + nodeClassName + ' ').include(needle)) - results.push(node); - } - return results; - }, - - attrPresence: function(nodes, root, attr, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var results = []; - for (var i = 0, node; node = nodes[i]; i++) - if (Element.hasAttribute(node, attr)) results.push(node); - return results; - }, - - attr: function(nodes, root, attr, value, operator, combinator) { - if (!nodes) nodes = root.getElementsByTagName("*"); - if (nodes && combinator) nodes = this[combinator](nodes); - var handler = Selector.operators[operator], results = []; - for (var i = 0, node; node = nodes[i]; i++) { - var nodeValue = Element.readAttribute(node, attr); - if (nodeValue === null) continue; - if (handler(nodeValue, value)) results.push(node); - } - return results; - }, - - pseudo: function(nodes, name, value, root, combinator) { - if (nodes && combinator) nodes = this[combinator](nodes); - if (!nodes) nodes = root.getElementsByTagName("*"); - return Selector.pseudos[name](nodes, value, root); + return (whole === null) ? 0 : whole * decimal; } - }, - pseudos: { - 'first-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.previousElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'last-child': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - if (Selector.handlers.nextElementSibling(node)) continue; - results.push(node); - } - return results; - }, - 'only-child': function(nodes, value, root) { - var h = Selector.handlers; - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!h.previousElementSibling(node) && !h.nextElementSibling(node)) - results.push(node); - return results; - }, - 'nth-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root); - }, - 'nth-last-child': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true); - }, - 'nth-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, false, true); - }, - 'nth-last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, formula, root, true, true); - }, - 'first-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, false, true); - }, - 'last-of-type': function(nodes, formula, root) { - return Selector.pseudos.nth(nodes, "1", root, true, true); - }, - 'only-of-type': function(nodes, formula, root) { - var p = Selector.pseudos; - return p['last-of-type'](p['first-of-type'](nodes, formula, root), formula, root); - }, - - // handles the an+b logic - getIndices: function(a, b, total) { - if (a == 0) return b > 0 ? [b] : []; - return $R(1, total).inject([], function(memo, i) { - if (0 == (i - b) % a && (i - b) / a >= 0) memo.push(i); - return memo; - }); - }, - - // handles nth(-last)-child, nth(-last)-of-type, and (first|last)-of-type - nth: function(nodes, formula, root, reverse, ofType) { - if (nodes.length == 0) return []; - if (formula == 'even') formula = '2n+0'; - if (formula == 'odd') formula = '2n+1'; - var h = Selector.handlers, results = [], indexed = [], m; - h.mark(nodes); - for (var i = 0, node; node = nodes[i]; i++) { - if (!node.parentNode._countedByPrototype) { - h.index(node.parentNode, reverse, ofType); - indexed.push(node.parentNode); - } - } - if (formula.match(/^\d+$/)) { // just a number - formula = Number(formula); - for (var i = 0, node; node = nodes[i]; i++) - if (node.nodeIndex == formula) results.push(node); - } else if (m = formula.match(/^(-?\d*)?n(([+-])(\d+))?/)) { // an+b - if (m[1] == "-") m[1] = -1; - var a = m[1] ? Number(m[1]) : 1; - var b = m[2] ? Number(m[2]) : 0; - var indices = Selector.pseudos.getIndices(a, b, nodes.length); - for (var i = 0, node, l = indices.length; node = nodes[i]; i++) { - for (var j = 0; j < l; j++) - if (node.nodeIndex == indices[j]) results.push(node); - } - } - h.unmark(nodes); - h.unmark(indexed); - return results; - }, - - 'empty': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) { - // IE treats comments as element nodes - if (node.tagName == '!' || node.firstChild) continue; - results.push(node); - } - return results; - }, - - 'not': function(nodes, selector, root) { - var h = Selector.handlers, selectorType, m; - var exclusions = new Selector(selector).findElements(root); - h.mark(exclusions); - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node._countedByPrototype) results.push(node); - h.unmark(exclusions); - return results; - }, - - 'enabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (!node.disabled && (!node.type || node.type !== 'hidden')) - results.push(node); - return results; - }, - - 'disabled': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.disabled) results.push(node); - return results; - }, - - 'checked': function(nodes, value, root) { - for (var i = 0, results = [], node; node = nodes[i]; i++) - if (node.checked) results.push(node); - return results; - } - }, - - operators: { - '=': function(nv, v) { return nv == v; }, - '!=': function(nv, v) { return nv != v; }, - '^=': function(nv, v) { return nv == v || nv && nv.startsWith(v); }, - '$=': function(nv, v) { return nv == v || nv && nv.endsWith(v); }, - '*=': function(nv, v) { return nv == v || nv && nv.include(v); }, - '$=': function(nv, v) { return nv.endsWith(v); }, - '*=': function(nv, v) { return nv.include(v); }, - '~=': function(nv, v) { return (' ' + nv + ' ').include(' ' + v + ' '); }, - '|=': function(nv, v) { return ('-' + (nv || "").toUpperCase() + - '-').include('-' + (v || "").toUpperCase() + '-'); } - }, - - split: function(expression) { - var expressions = []; - expression.scan(/(([\w#:.~>+()\s-]+|\*|\[.*?\])+)\s*(,|$)/, function(m) { - expressions.push(m[1].strip()); - }); - return expressions; - }, - - matchElements: function(elements, expression) { - var matches = $$(expression), h = Selector.handlers; - h.mark(matches); - for (var i = 0, results = [], element; element = elements[i]; i++) - if (element._countedByPrototype) results.push(element); - h.unmark(matches); - return results; - }, - - findElement: function(elements, expression, index) { - if (Object.isNumber(expression)) { - index = expression; expression = false; - } - return Selector.matchElements(elements, expression || '*')[index || 0]; - }, - - findChildElements: function(element, expressions) { - expressions = Selector.split(expressions.join(',')); - var results = [], h = Selector.handlers; - for (var i = 0, l = expressions.length, selector; i < l; i++) { - selector = new Selector(expressions[i].strip()); - h.concat(results, selector.findElements(element)); - } - return (l > 1) ? h.unique(results) : results; + return 0; } -}); -if (Prototype.Browser.IE) { - Object.extend(Selector.handlers, { - // IE returns comment nodes on getElementsByTagName("*"). - // Filter them out. - concat: function(a, b) { - for (var i = 0, node; node = b[i]; i++) - if (node.tagName !== "!") a.push(node); - return a; + function toCSSPixels(number) { + if (Object.isString(number) && number.endsWith('px')) { + return number; + } + return number + 'px'; + } + + function isDisplayed(element) { + var originalElement = element; + while (element && element.parentNode) { + var display = element.getStyle('display'); + if (display === 'none') { + return false; + } + element = $(element.parentNode); + } + return true; + } + + var hasLayout = Prototype.K; + if ('currentStyle' in document.documentElement) { + hasLayout = function(element) { + if (!element.currentStyle.hasLayout) { + element.style.zoom = 1; + } + return element; + }; + } + + function cssNameFor(key) { + if (key.include('border')) key = key + '-width'; + return key.camelize(); + } + + Element.Layout = Class.create(Hash, { + initialize: function($super, element, preCompute) { + $super(); + this.element = $(element); + + Element.Layout.PROPERTIES.each( function(property) { + this._set(property, null); + }, this); + + if (preCompute) { + this._preComputing = true; + this._begin(); + Element.Layout.PROPERTIES.each( this._compute, this ); + this._end(); + this._preComputing = false; + } }, - // IE improperly serializes _countedByPrototype in (inner|outer)HTML. - unmark: function(nodes) { - for (var i = 0, node; node = nodes[i]; i++) - node.removeAttribute('_countedByPrototype'); - return nodes; + _set: function(property, value) { + return Hash.prototype.set.call(this, property, value); + }, + + set: function(property, value) { + throw "Properties of Element.Layout are read-only."; + }, + + get: function($super, property) { + var value = $super(property); + return value === null ? this._compute(property) : value; + }, + + _begin: function() { + if (this._prepared) return; + + var element = this.element; + if (isDisplayed(element)) { + this._prepared = true; + return; + } + + var originalStyles = { + position: element.style.position || '', + width: element.style.width || '', + visibility: element.style.visibility || '', + display: element.style.display || '' + }; + + element.store('prototype_original_styles', originalStyles); + + var position = element.getStyle('position'), + width = element.getStyle('width'); + + if (width === "0px" || width === null) { + element.style.display = 'block'; + width = element.getStyle('width'); + } + + var context = (position === 'fixed') ? document.viewport : + element.parentNode; + + element.setStyle({ + position: 'absolute', + visibility: 'hidden', + display: 'block' + }); + + var positionedWidth = element.getStyle('width'); + + var newWidth; + if (width && (positionedWidth === width)) { + newWidth = getPixelValue(element, 'width', context); + } else if (position === 'absolute' || position === 'fixed') { + newWidth = getPixelValue(element, 'width', context); + } else { + var parent = element.parentNode, pLayout = $(parent).getLayout(); + + newWidth = pLayout.get('width') - + this.get('margin-left') - + this.get('border-left') - + this.get('padding-left') - + this.get('padding-right') - + this.get('border-right') - + this.get('margin-right'); + } + + element.setStyle({ width: newWidth + 'px' }); + + this._prepared = true; + }, + + _end: function() { + var element = this.element; + var originalStyles = element.retrieve('prototype_original_styles'); + element.store('prototype_original_styles', null); + element.setStyle(originalStyles); + this._prepared = false; + }, + + _compute: function(property) { + var COMPUTATIONS = Element.Layout.COMPUTATIONS; + if (!(property in COMPUTATIONS)) { + throw "Property not found."; + } + + return this._set(property, COMPUTATIONS[property].call(this, this.element)); + }, + + toObject: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var obj = {}; + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + var value = this.get(key); + if (value != null) obj[key] = value; + }, this); + return obj; + }, + + toHash: function() { + var obj = this.toObject.apply(this, arguments); + return new Hash(obj); + }, + + toCSS: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var css = {}; + + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; + + var value = this.get(key); + if (value != null) css[cssNameFor(key)] = value + 'px'; + }, this); + return css; + }, + + inspect: function() { + return "#"; } }); + + Object.extend(Element.Layout, { + PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), + + COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), + + COMPUTATIONS: { + 'height': function(element) { + if (!this._preComputing) this._begin(); + + var bHeight = this.get('border-box-height'); + if (bHeight <= 0) { + if (!this._preComputing) this._end(); + return 0; + } + + var bTop = this.get('border-top'), + bBottom = this.get('border-bottom'); + + var pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + if (!this._preComputing) this._end(); + + return bHeight - bTop - bBottom - pTop - pBottom; + }, + + 'width': function(element) { + if (!this._preComputing) this._begin(); + + var bWidth = this.get('border-box-width'); + if (bWidth <= 0) { + if (!this._preComputing) this._end(); + return 0; + } + + var bLeft = this.get('border-left'), + bRight = this.get('border-right'); + + var pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + if (!this._preComputing) this._end(); + + return bWidth - bLeft - bRight - pLeft - pRight; + }, + + 'padding-box-height': function(element) { + var height = this.get('height'), + pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + return height + pTop + pBottom; + }, + + 'padding-box-width': function(element) { + var width = this.get('width'), + pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + return width + pLeft + pRight; + }, + + 'border-box-height': function(element) { + if (!this._preComputing) this._begin(); + var height = element.offsetHeight; + if (!this._preComputing) this._end(); + return height; + }, + + 'border-box-width': function(element) { + if (!this._preComputing) this._begin(); + var width = element.offsetWidth; + if (!this._preComputing) this._end(); + return width; + }, + + 'margin-box-height': function(element) { + var bHeight = this.get('border-box-height'), + mTop = this.get('margin-top'), + mBottom = this.get('margin-bottom'); + + if (bHeight <= 0) return 0; + + return bHeight + mTop + mBottom; + }, + + 'margin-box-width': function(element) { + var bWidth = this.get('border-box-width'), + mLeft = this.get('margin-left'), + mRight = this.get('margin-right'); + + if (bWidth <= 0) return 0; + + return bWidth + mLeft + mRight; + }, + + 'top': function(element) { + var offset = element.positionedOffset(); + return offset.top; + }, + + 'bottom': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pHeight = parent.measure('height'); + + var mHeight = this.get('border-box-height'); + + return pHeight - mHeight - offset.top; + }, + + 'left': function(element) { + var offset = element.positionedOffset(); + return offset.left; + }, + + 'right': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pWidth = parent.measure('width'); + + var mWidth = this.get('border-box-width'); + + return pWidth - mWidth - offset.left; + }, + + 'padding-top': function(element) { + return getPixelValue(element, 'paddingTop'); + }, + + 'padding-bottom': function(element) { + return getPixelValue(element, 'paddingBottom'); + }, + + 'padding-left': function(element) { + return getPixelValue(element, 'paddingLeft'); + }, + + 'padding-right': function(element) { + return getPixelValue(element, 'paddingRight'); + }, + + 'border-top': function(element) { + return getPixelValue(element, 'borderTopWidth'); + }, + + 'border-bottom': function(element) { + return getPixelValue(element, 'borderBottomWidth'); + }, + + 'border-left': function(element) { + return getPixelValue(element, 'borderLeftWidth'); + }, + + 'border-right': function(element) { + return getPixelValue(element, 'borderRightWidth'); + }, + + 'margin-top': function(element) { + return getPixelValue(element, 'marginTop'); + }, + + 'margin-bottom': function(element) { + return getPixelValue(element, 'marginBottom'); + }, + + 'margin-left': function(element) { + return getPixelValue(element, 'marginLeft'); + }, + + 'margin-right': function(element) { + return getPixelValue(element, 'marginRight'); + } + } + }); + + if ('getBoundingClientRect' in document.documentElement) { + Object.extend(Element.Layout.COMPUTATIONS, { + 'right': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); + + return (pRect.right - rect.right).round(); + }, + + 'bottom': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); + + return (pRect.bottom - rect.bottom).round(); + } + }); + } + + Element.Offset = Class.create({ + initialize: function(left, top) { + this.left = left.round(); + this.top = top.round(); + + this[0] = this.left; + this[1] = this.top; + }, + + relativeTo: function(offset) { + return new Element.Offset( + this.left - offset.left, + this.top - offset.top + ); + }, + + inspect: function() { + return "#".interpolate(this); + }, + + toString: function() { + return "[#{left}, #{top}]".interpolate(this); + }, + + toArray: function() { + return [this.left, this.top]; + } + }); + + function getLayout(element, preCompute) { + return new Element.Layout(element, preCompute); + } + + function measure(element, property) { + return $(element).getLayout().get(property); + } + + function getDimensions(element) { + element = $(element); + var display = Element.getStyle(element, 'display'); + + if (display && display !== 'none') { + return { width: element.offsetWidth, height: element.offsetHeight }; + } + + var style = element.style; + var originalStyles = { + visibility: style.visibility, + position: style.position, + display: style.display + }; + + var newStyles = { + visibility: 'hidden', + display: 'block' + }; + + if (originalStyles.position !== 'fixed') + newStyles.position = 'absolute'; + + Element.setStyle(element, newStyles); + + var dimensions = { + width: element.offsetWidth, + height: element.offsetHeight + }; + + Element.setStyle(element, originalStyles); + + return dimensions; + } + + function getOffsetParent(element) { + element = $(element); + + if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) + return $(document.body); + + var isInline = (Element.getStyle(element, 'display') === 'inline'); + if (!isInline && element.offsetParent) return $(element.offsetParent); + + while ((element = element.parentNode) && element !== document.body) { + if (Element.getStyle(element, 'position') !== 'static') { + return isHtml(element) ? $(document.body) : $(element); + } + } + + return $(document.body); + } + + + function cumulativeOffset(element) { + element = $(element); + var valueT = 0, valueL = 0; + if (element.parentNode) { + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + } + return new Element.Offset(valueL, valueT); + } + + function positionedOffset(element) { + element = $(element); + + var layout = element.getLayout(); + + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (isBody(element)) break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + + valueL -= layout.get('margin-top'); + valueT -= layout.get('margin-left'); + + return new Element.Offset(valueL, valueT); + } + + function cumulativeScrollOffset(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return new Element.Offset(valueL, valueT); + } + + function viewportOffset(forElement) { + element = $(element); + var valueT = 0, valueL = 0, docBody = document.body; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == docBody && + Element.getStyle(element, 'position') == 'absolute') break; + } while (element = element.offsetParent); + + element = forElement; + do { + if (element != docBody) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + return new Element.Offset(valueL, valueT); + } + + function absolutize(element) { + element = $(element); + + if (Element.getStyle(element, 'position') === 'absolute') { + return element; + } + + var offsetParent = getOffsetParent(element); + var eOffset = element.viewportOffset(), + pOffset = offsetParent.viewportOffset(); + + var offset = eOffset.relativeTo(pOffset); + var layout = element.getLayout(); + + element.store('prototype_absolutize_original_styles', { + left: element.getStyle('left'), + top: element.getStyle('top'), + width: element.getStyle('width'), + height: element.getStyle('height') + }); + + element.setStyle({ + position: 'absolute', + top: offset.top + 'px', + left: offset.left + 'px', + width: layout.get('width') + 'px', + height: layout.get('height') + 'px' + }); + + return element; + } + + function relativize(element) { + element = $(element); + if (Element.getStyle(element, 'position') === 'relative') { + return element; + } + + var originalStyles = + element.retrieve('prototype_absolutize_original_styles'); + + if (originalStyles) element.setStyle(originalStyles); + return element; + } + + if (Prototype.Browser.IE) { + getOffsetParent = getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + + if (isDocument(element) || isDetached(element) || isBody(element) || isHtml(element)) + return $(document.body); + + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + positionedOffset = positionedOffset.wrap(function(proceed, element) { + element = $(element); + if (!element.parentNode) return new Element.Offset(0, 0); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + hasLayout(offsetParent); + + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + }); + } else if (Prototype.Browser.Webkit) { + cumulativeOffset = function(element) { + element = $(element); + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return new Element.Offset(valueL, valueT); + }; + } + + + Element.addMethods({ + getLayout: getLayout, + measure: measure, + getDimensions: getDimensions, + getOffsetParent: getOffsetParent, + cumulativeOffset: cumulativeOffset, + positionedOffset: positionedOffset, + cumulativeScrollOffset: cumulativeScrollOffset, + viewportOffset: viewportOffset, + absolutize: absolutize, + relativize: relativize + }); + + function isBody(element) { + return element.nodeName.toUpperCase() === 'BODY'; + } + + function isHtml(element) { + return element.nodeName.toUpperCase() === 'HTML'; + } + + function isDocument(element) { + return element.nodeType === Node.DOCUMENT_NODE; + } + + function isDetached(element) { + return element !== document.body && + !Element.descendantOf(element, document.body); + } + + if ('getBoundingClientRect' in document.documentElement) { + Element.addMethods({ + viewportOffset: function(element) { + element = $(element); + if (isDetached(element)) return new Element.Offset(0, 0); + + var rect = element.getBoundingClientRect(), + docEl = document.documentElement; + return new Element.Offset(rect.left - docEl.clientLeft, + rect.top - docEl.clientTop); + } + }); + } +})(); +window.$$ = function() { + var expression = $A(arguments).join(', '); + return Prototype.Selector.select(expression, document); +}; + +Prototype.Selector = (function() { + + function select() { + throw new Error('Method "Prototype.Selector.select" must be defined.'); + } + + function match() { + throw new Error('Method "Prototype.Selector.match" must be defined.'); + } + + function find(elements, expression, index) { + index = index || 0; + var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; + + for (i = 0; i < length; i++) { + if (match(elements[i], expression) && index == matchIndex++) { + return Element.extend(elements[i]); + } + } + } + + function extendElements(elements) { + for (var i = 0, length = elements.length; i < length; i++) { + Element.extend(elements[i]); + } + return elements; + } + + + var K = Prototype.K; + + return { + select: select, + match: match, + find: find, + extendElements: (Element.extend === K) ? K : extendElements, + extendElement: Element.extend + }; +})(); +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } + } + } else { + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; + + if ( curLoop == result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); } -function $$() { - return Selector.findChildElements(document, $A(arguments)); +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; } + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +(function(){ + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

    "; + + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
    "; + + if ( div.getElementsByClassName("e").length === 0 ) + return; + + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) + return; + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + + +window.Sizzle = Sizzle; + +})(); + +Prototype._original_property = window.Sizzle; + +;(function(engine) { + var extendElements = Prototype.Selector.extendElements; + + function select(selector, scope) { + return extendElements(engine(selector, scope || document)); + } + + function match(element, selector) { + return engine.matches(selector, [element]).length == 1; + } + + Prototype.Selector.engine = engine; + Prototype.Selector.select = select; + Prototype.Selector.match = match; +})(Sizzle); + +window.Sizzle = Prototype._original_property; +delete Prototype._original_property; + var Form = { reset: function(form) { - $(form).reset(); + form = $(form); + form.reset(); return form; }, serializeElements: function(elements, options) { if (typeof options != 'object') options = { hash: !!options }; else if (Object.isUndefined(options.hash)) options.hash = true; - var key, value, submitted = false, submit = options.submit; + var key, value, submitted = false, submit = options.submit, accumulator, initial; - var data = elements.inject({ }, function(result, element) { + if (options.hash) { + initial = {}; + accumulator = function(result, key, value) { + if (key in result) { + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } else result[key] = value; + return result; + }; + } else { + initial = ''; + accumulator = function(result, key, value) { + return result + (result ? '&' : '') + encodeURIComponent(key) + '=' + encodeURIComponent(value); + } + } + + return elements.inject(initial, function(result, element) { if (!element.disabled && element.name) { key = element.name; value = $(element).getValue(); if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && submit !== false && (!submit || key == submit) && (submitted = true)))) { - if (key in result) { - // a key is already present; construct an array of values - if (!Object.isArray(result[key])) result[key] = [result[key]]; - result[key].push(value); - } - else result[key] = value; + result = accumulator(result, key, value); } } return result; }); - - return options.hash ? data : Object.toQueryString(data); } }; @@ -3480,13 +5006,18 @@ Form.Methods = { }, getElements: function(form) { - return $A($(form).getElementsByTagName('*')).inject([], - function(elements, child) { - if (Form.Element.Serializers[child.tagName.toLowerCase()]) - elements.push(Element.extend(child)); - return elements; - } - ); + var elements = $(form).getElementsByTagName('*'), + element, + arr = [ ], + serializers = Form.Element.Serializers; + for (var i = 0; element = elements[i]; i++) { + arr.push(element); + } + return arr.inject([], function(elements, child) { + if (serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + }) }, getInputs: function(form, typeName, name) { @@ -3526,13 +5057,14 @@ Form.Methods = { }).sortBy(function(element) { return element.tabIndex }).first(); return firstByIndex ? firstByIndex : elements.find(function(element) { - return ['input', 'select', 'textarea'].include(element.tagName.toLowerCase()); + return /^(?:input|select|textarea)$/i.test(element.tagName); }); }, focusFirstElement: function(form) { form = $(form); - form.findFirstElement().activate(); + var element = form.findFirstElement(); + if (element) element.activate(); return form; }, @@ -3557,6 +5089,7 @@ Form.Methods = { /*--------------------------------------------------------------------------*/ + Form.Element = { focus: function(element) { $(element).focus(); @@ -3570,6 +5103,7 @@ Form.Element = { }; Form.Element.Methods = { + serialize: function(element) { element = $(element); if (!element.disabled && element.name) { @@ -3610,7 +5144,7 @@ Form.Element.Methods = { try { element.focus(); if (element.select && (element.tagName.toLowerCase() != 'input' || - !['button', 'reset', 'submit'].include(element.type))) + !(/^(?:button|reset|submit)$/i.test(element.type)))) element.select(); } catch (e) { } return element; @@ -3632,75 +5166,86 @@ Form.Element.Methods = { /*--------------------------------------------------------------------------*/ var Field = Form.Element; + var $F = Form.Element.Methods.getValue; /*--------------------------------------------------------------------------*/ -Form.Element.Serializers = { - input: function(element, value) { +Form.Element.Serializers = (function() { + function input(element, value) { switch (element.type.toLowerCase()) { case 'checkbox': case 'radio': - return Form.Element.Serializers.inputSelector(element, value); + return inputSelector(element, value); default: - return Form.Element.Serializers.textarea(element, value); + return valueSelector(element, value); } - }, + } - inputSelector: function(element, value) { - if (Object.isUndefined(value)) return element.checked ? element.value : null; + function inputSelector(element, value) { + if (Object.isUndefined(value)) + return element.checked ? element.value : null; else element.checked = !!value; - }, + } - textarea: function(element, value) { + function valueSelector(element, value) { if (Object.isUndefined(value)) return element.value; else element.value = value; - }, + } - select: function(element, value) { + function select(element, value) { if (Object.isUndefined(value)) - return this[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - else { - var opt, currentValue, single = !Object.isArray(value); - for (var i = 0, length = element.length; i < length; i++) { - opt = element.options[i]; - currentValue = this.optionValue(opt); - if (single) { - if (currentValue == value) { - opt.selected = true; - return; - } + return (element.type === 'select-one' ? selectOne : selectMany)(element); + + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; } - else opt.selected = value.include(currentValue); } + else opt.selected = value.include(currentValue); } - }, + } - selectOne: function(element) { + function selectOne(element) { var index = element.selectedIndex; - return index >= 0 ? this.optionValue(element.options[index]) : null; - }, + return index >= 0 ? optionValue(element.options[index]) : null; + } - selectMany: function(element) { + function selectMany(element) { var values, length = element.length; if (!length) return null; for (var i = 0, values = []; i < length; i++) { var opt = element.options[i]; - if (opt.selected) values.push(this.optionValue(opt)); + if (opt.selected) values.push(optionValue(opt)); } return values; - }, - - optionValue: function(opt) { - // extend element because hasAttribute may not be native - return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; } -}; + + function optionValue(opt) { + return Element.hasAttribute(opt, 'value') ? opt.value : opt.text; + } + + return { + input: input, + inputSelector: inputSelector, + textarea: valueSelector, + select: select, + selectOne: selectOne, + selectMany: selectMany, + optionValue: optionValue, + button: valueSelector + }; +})(); /*--------------------------------------------------------------------------*/ + Abstract.TimedObserver = Class.create(PeriodicalExecuter, { initialize: function($super, element, frequency, callback) { $super(callback, frequency); @@ -3782,354 +5327,527 @@ Form.EventObserver = Class.create(Abstract.EventObserver, { return Form.serialize(this.element); } }); -if (!window.Event) var Event = { }; +(function() { -Object.extend(Event, { - KEY_BACKSPACE: 8, - KEY_TAB: 9, - KEY_RETURN: 13, - KEY_ESC: 27, - KEY_LEFT: 37, - KEY_UP: 38, - KEY_RIGHT: 39, - KEY_DOWN: 40, - KEY_DELETE: 46, - KEY_HOME: 36, - KEY_END: 35, - KEY_PAGEUP: 33, - KEY_PAGEDOWN: 34, - KEY_INSERT: 45, + var Event = { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, - cache: { }, - - relatedTarget: function(event) { - var element; - switch(event.type) { - case 'mouseover': element = event.fromElement; break; - case 'mouseout': element = event.toElement; break; - default: return null; - } - return Element.extend(element); - } -}); - -Event.Methods = (function() { - var isButton; - - if (Prototype.Browser.IE) { - var buttonMap = { 0: 1, 1: 4, 2: 2 }; - isButton = function(event, code) { - return event.button == buttonMap[code]; - }; - - } else if (Prototype.Browser.WebKit) { - isButton = function(event, code) { - switch (code) { - case 0: return event.which == 1 && !event.metaKey; - case 1: return event.which == 1 && event.metaKey; - default: return false; - } - }; - - } else { - isButton = function(event, code) { - return event.which ? (event.which === code + 1) : (event.button === code); - }; - } - - return { - isLeftClick: function(event) { return isButton(event, 0) }, - isMiddleClick: function(event) { return isButton(event, 1) }, - isRightClick: function(event) { return isButton(event, 2) }, - - element: function(event) { - event = Event.extend(event); - - var node = event.target, - type = event.type, - currentTarget = event.currentTarget; - - if (currentTarget && currentTarget.tagName) { - // Firefox screws up the "click" event when moving between radio buttons - // via arrow keys. It also screws up the "load" and "error" events on images, - // reporting the document as the target instead of the original image. - if (type === 'load' || type === 'error' || - (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' - && currentTarget.type === 'radio')) - node = currentTarget; - } - if (node.nodeType == Node.TEXT_NODE) node = node.parentNode; - return Element.extend(node); - }, - - findElement: function(event, expression) { - var element = Event.element(event); - if (!expression) return element; - var elements = [element].concat(element.ancestors()); - return Selector.findElement(elements, expression, 0); - }, - - pointer: function(event) { - var docElement = document.documentElement, - body = document.body || { scrollLeft: 0, scrollTop: 0 }; - return { - x: event.pageX || (event.clientX + - (docElement.scrollLeft || body.scrollLeft) - - (docElement.clientLeft || 0)), - y: event.pageY || (event.clientY + - (docElement.scrollTop || body.scrollTop) - - (docElement.clientTop || 0)) - }; - }, - - pointerX: function(event) { return Event.pointer(event).x }, - pointerY: function(event) { return Event.pointer(event).y }, - - stop: function(event) { - Event.extend(event); - event.preventDefault(); - event.stopPropagation(); - event.stopped = true; - } + cache: {} + }; + + var docEl = document.documentElement; + var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl + && 'onmouseleave' in docEl; + + + + var isIELegacyEvent = function(event) { return false; }; + + if (window.attachEvent) { + if (window.addEventListener) { + isIELegacyEvent = function(event) { + return !(event instanceof window.Event); + }; + } else { + isIELegacyEvent = function(event) { return true; }; + } + } + + var _isButton; + + function _isButtonForDOMEvents(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + } + + var legacyButtonMap = { 0: 1, 1: 4, 2: 2 }; + function _isButtonForLegacyEvents(event, code) { + return event.button === legacyButtonMap[code]; + } + + function _isButtonForWebKit(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 2 || (event.which == 1 && event.metaKey); + case 2: return event.which == 3; + default: return false; + } + } + + if (window.attachEvent) { + if (!window.addEventListener) { + _isButton = _isButtonForLegacyEvents; + } else { + _isButton = function(event, code) { + return isIELegacyEvent(event) ? _isButtonForLegacyEvents(event, code) : + _isButtonForDOMEvents(event, code); + } + } + } else if (Prototype.Browser.WebKit) { + _isButton = _isButtonForWebKit; + } else { + _isButton = _isButtonForDOMEvents; + } + + function isLeftClick(event) { return _isButton(event, 0) } + + function isMiddleClick(event) { return _isButton(event, 1) } + + function isRightClick(event) { return _isButton(event, 2) } + + function element(event) { + event = Event.extend(event); + + var node = event.target, type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + + if (node.nodeType == Node.TEXT_NODE) + node = node.parentNode; + + return Element.extend(node); + } + + function findElement(event, expression) { + var element = Event.element(event); + + if (!expression) return element; + while (element) { + if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { + return Element.extend(element); + } + element = element.parentNode; + } + } + + function pointer(event) { + return { x: pointerX(event), y: pointerY(event) }; + } + + function pointerX(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0 }; + + return event.pageX || (event.clientX + + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)); + } + + function pointerY(event) { + var docElement = document.documentElement, + body = document.body || { scrollTop: 0 }; + + return event.pageY || (event.clientY + + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)); + } + + + function stop(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + + event.stopped = true; + } + + + Event.Methods = { + isLeftClick: isLeftClick, + isMiddleClick: isMiddleClick, + isRightClick: isRightClick, + + element: element, + findElement: findElement, + + pointer: pointer, + pointerX: pointerX, + pointerY: pointerY, + + stop: stop }; -})(); -Event.extend = (function() { var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { m[name] = Event.Methods[name].methodize(); return m; }); - if (Prototype.Browser.IE) { - Object.extend(methods, { + if (window.attachEvent) { + function _relatedTarget(event) { + var element; + switch (event.type) { + case 'mouseover': + case 'mouseenter': + element = event.fromElement; + break; + case 'mouseout': + case 'mouseleave': + element = event.toElement; + break; + default: + return null; + } + return Element.extend(element); + } + + var additionalMethods = { stopPropagation: function() { this.cancelBubble = true }, preventDefault: function() { this.returnValue = false }, - inspect: function() { return "[object Event]" } - }); + inspect: function() { return '[object Event]' } + }; - return function(event) { + Event.extend = function(event, element) { if (!event) return false; - if (event._extendedByPrototype) return event; + if (!isIELegacyEvent(event)) return event; + + if (event._extendedByPrototype) return event; event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + Object.extend(event, { - target: event.srcElement, - relatedTarget: Event.relatedTarget(event), + target: event.srcElement || element, + relatedTarget: _relatedTarget(event), pageX: pointer.x, pageY: pointer.y }); - return Object.extend(event, methods); + + Object.extend(event, methods); + Object.extend(event, additionalMethods); + + return event; }; - } else { - Event.prototype = Event.prototype || document.createEvent("HTMLEvents")['__proto__']; + Event.extend = Prototype.K; + } + + if (window.addEventListener) { + Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; Object.extend(Event.prototype, methods); - return Prototype.K; - } -})(); - -Object.extend(Event, (function() { - var cache = Event.cache; - - function getEventID(element) { - if (element._prototypeEventID) return element._prototypeEventID[0]; - arguments.callee.id = arguments.callee.id || 1; - return element._prototypeEventID = [++arguments.callee.id]; } - function getDOMEventName(eventName) { - if (eventName && eventName.include(':')) return "dataavailable"; - return eventName; - } + function _createResponder(element, eventName, handler) { + var registry = Element.retrieve(element, 'prototype_event_registry'); - function getCacheForID(id) { - return cache[id] = cache[id] || { }; - } + if (Object.isUndefined(registry)) { + CACHE.push(element); + registry = Element.retrieve(element, 'prototype_event_registry', $H()); + } - function getWrappersForEventName(id, eventName) { - var c = getCacheForID(id); - return c[eventName] = c[eventName] || []; - } + var respondersForEvent = registry.get(eventName); + if (Object.isUndefined(respondersForEvent)) { + respondersForEvent = []; + registry.set(eventName, respondersForEvent); + } - function createWrapper(element, eventName, handler) { - var id = getEventID(element); - var c = getWrappersForEventName(id, eventName); - if (c.pluck("handler").include(handler)) return false; + if (respondersForEvent.pluck('handler').include(handler)) return false; - var wrapper = function(event) { - if (!Event || !Event.extend || - (event.eventName && event.eventName != eventName)) + var responder; + if (eventName.include(":")) { + responder = function(event) { + if (Object.isUndefined(event.eventName)) return false; - Event.extend(event); - handler.call(element, event); - }; + if (event.eventName !== eventName) + return false; - wrapper.handler = handler; - c.push(wrapper); - return wrapper; - } + Event.extend(event, element); + handler.call(element, event); + }; + } else { + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && + (eventName === "mouseenter" || eventName === "mouseleave")) { + if (eventName === "mouseenter" || eventName === "mouseleave") { + responder = function(event) { + Event.extend(event, element); - function findWrapper(id, eventName, handler) { - var c = getWrappersForEventName(id, eventName); - return c.find(function(wrapper) { return wrapper.handler == handler }); - } + var parent = event.relatedTarget; + while (parent && parent !== element) { + try { parent = parent.parentNode; } + catch(e) { parent = element; } + } - function destroyWrapper(id, eventName, handler) { - var c = getCacheForID(id); - if (!c[eventName]) return false; - c[eventName] = c[eventName].without(findWrapper(id, eventName, handler)); - } + if (parent === element) return; - function destroyCache() { - for (var id in cache) - for (var eventName in cache[id]) - cache[id][eventName] = null; - } - - - // Internet Explorer needs to remove event handlers on page unload - // in order to avoid memory leaks. - if (window.attachEvent) { - window.attachEvent("onunload", destroyCache); - } - - // Safari has a dummy event handler on page unload so that it won't - // use its bfcache. Safari <= 3.1 has an issue with restoring the "document" - // object when page is returned to via the back button using its bfcache. - if (Prototype.Browser.WebKit) { - window.addEventListener('unload', Prototype.emptyFunction, false); - } - - return { - observe: function(element, eventName, handler) { - element = $(element); - var name = getDOMEventName(eventName); - - var wrapper = createWrapper(element, eventName, handler); - if (!wrapper) return element; - - if (element.addEventListener) { - element.addEventListener(name, wrapper, false); + handler.call(element, event); + }; + } } else { - element.attachEvent("on" + name, wrapper); + responder = function(event) { + Event.extend(event, element); + handler.call(element, event); + }; } - - return element; - }, - - stopObserving: function(element, eventName, handler) { - element = $(element); - var id = getEventID(element), name = getDOMEventName(eventName); - - if (!handler && eventName) { - getWrappersForEventName(id, eventName).each(function(wrapper) { - element.stopObserving(eventName, wrapper.handler); - }); - return element; - - } else if (!eventName) { - Object.keys(getCacheForID(id)).each(function(eventName) { - element.stopObserving(eventName); - }); - return element; - } - - var wrapper = findWrapper(id, eventName, handler); - if (!wrapper) return element; - - if (element.removeEventListener) { - element.removeEventListener(name, wrapper, false); - } else { - element.detachEvent("on" + name, wrapper); - } - - destroyWrapper(id, eventName, handler); - - return element; - }, - - fire: function(element, eventName, memo) { - element = $(element); - if (element == document && document.createEvent && !element.dispatchEvent) - element = document.documentElement; - - var event; - if (document.createEvent) { - event = document.createEvent("HTMLEvents"); - event.initEvent("dataavailable", true, true); - } else { - event = document.createEventObject(); - event.eventType = "ondataavailable"; - } - - event.eventName = eventName; - event.memo = memo || { }; - - if (document.createEvent) { - element.dispatchEvent(event); - } else { - element.fireEvent(event.eventType, event); - } - - return Event.extend(event); } - }; -})()); -Object.extend(Event, Event.Methods); + responder.handler = handler; + respondersForEvent.push(responder); + return responder; + } -Element.addMethods({ - fire: Event.fire, - observe: Event.observe, - stopObserving: Event.stopObserving -}); + function _destroyCache() { + for (var i = 0, length = CACHE.length; i < length; i++) { + Event.stopObserving(CACHE[i]); + CACHE[i] = null; + } + } -Object.extend(document, { - fire: Element.Methods.fire.methodize(), - observe: Element.Methods.observe.methodize(), - stopObserving: Element.Methods.stopObserving.methodize(), - loaded: false -}); + var CACHE = []; + + if (Prototype.Browser.IE) + window.attachEvent('onunload', _destroyCache); + + if (Prototype.Browser.WebKit) + window.addEventListener('unload', Prototype.emptyFunction, false); + + + var _getDOMEventName = Prototype.K, + translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; + + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { + _getDOMEventName = function(eventName) { + return (translations[eventName] || eventName); + }; + } + + function observe(element, eventName, handler) { + element = $(element); + + var responder = _createResponder(element, eventName, handler); + + if (!responder) return element; + + if (eventName.include(':')) { + if (element.addEventListener) + element.addEventListener("dataavailable", responder, false); + else { + element.attachEvent("ondataavailable", responder); + element.attachEvent("onlosecapture", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + + if (element.addEventListener) + element.addEventListener(actualEventName, responder, false); + else + element.attachEvent("on" + actualEventName, responder); + } + + return element; + } + + function stopObserving(element, eventName, handler) { + element = $(element); + + var registry = Element.retrieve(element, 'prototype_event_registry'); + if (!registry) return element; + + if (!eventName) { + registry.each( function(pair) { + var eventName = pair.key; + stopObserving(element, eventName); + }); + return element; + } + + var responders = registry.get(eventName); + if (!responders) return element; + + if (!handler) { + responders.each(function(r) { + stopObserving(element, eventName, r.handler); + }); + return element; + } + + var i = responders.length, responder; + while (i--) { + if (responders[i].handler === handler) { + responder = responders[i]; + break; + } + } + if (!responder) return element; + + if (eventName.include(':')) { + if (element.removeEventListener) + element.removeEventListener("dataavailable", responder, false); + else { + element.detachEvent("ondataavailable", responder); + element.detachEvent("onlosecapture", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + if (element.removeEventListener) + element.removeEventListener(actualEventName, responder, false); + else + element.detachEvent('on' + actualEventName, responder); + } + + registry.set(eventName, responders.without(responder)); + + return element; + } + + function fire(element, eventName, memo, bubble) { + element = $(element); + + if (Object.isUndefined(bubble)) + bubble = true; + + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent('HTMLEvents'); + event.initEvent('dataavailable', bubble, true); + } else { + event = document.createEventObject(); + event.eventType = bubble ? 'ondataavailable' : 'onlosecapture'; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) + element.dispatchEvent(event); + else + element.fireEvent(event.eventType, event); + + return Event.extend(event); + } + + Event.Handler = Class.create({ + initialize: function(element, eventName, selector, callback) { + this.element = $(element); + this.eventName = eventName; + this.selector = selector; + this.callback = callback; + this.handler = this.handleEvent.bind(this); + }, + + start: function() { + Event.observe(this.element, this.eventName, this.handler); + return this; + }, + + stop: function() { + Event.stopObserving(this.element, this.eventName, this.handler); + return this; + }, + + handleEvent: function(event) { + var element = Event.findElement(event, this.selector); + if (element) this.callback.call(this.element, event, element); + } + }); + + function on(element, eventName, selector, callback) { + element = $(element); + if (Object.isFunction(selector) && Object.isUndefined(callback)) { + callback = selector, selector = null; + } + + return new Event.Handler(element, eventName, selector, callback).start(); + } + + Object.extend(Event, Event.Methods); + + Object.extend(Event, { + fire: fire, + observe: observe, + stopObserving: stopObserving, + on: on + }); + + Element.addMethods({ + fire: fire, + + observe: observe, + + stopObserving: stopObserving, + + on: on + }); + + Object.extend(document, { + fire: fire.methodize(), + + observe: observe.methodize(), + + stopObserving: stopObserving.methodize(), + + on: on.methodize(), + + loaded: false + }); + + if (window.Event) Object.extend(window.Event, Event); + else window.Event = Event; +})(); (function() { /* Support for the DOMContentLoaded event is based on work by Dan Webb, - Matthias Miller, Dean Edwards and John Resig. */ + Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ var timer; function fireContentLoadedEvent() { if (document.loaded) return; - if (timer) window.clearInterval(timer); - document.fire("dom:loaded"); + if (timer) window.clearTimeout(timer); document.loaded = true; + document.fire('dom:loaded'); + } + + function checkReadyState() { + if (document.readyState === 'complete') { + document.stopObserving('readystatechange', checkReadyState); + fireContentLoadedEvent(); + } + } + + function pollDoScroll() { + try { document.documentElement.doScroll('left'); } + catch(e) { + timer = pollDoScroll.defer(); + return; + } + fireContentLoadedEvent(); } if (document.addEventListener) { - if (Prototype.Browser.WebKit) { - timer = window.setInterval(function() { - if (/loaded|complete/.test(document.readyState)) - fireContentLoadedEvent(); - }, 0); - - Event.observe(window, "load", fireContentLoadedEvent); - - } else { - document.addEventListener("DOMContentLoaded", - fireContentLoadedEvent, false); - } - + document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); } else { - document.write(" <% tabs.each do |tab| -%> - <%= content_tag('div', render(:partial => tab[:partial], :locals => {:tab => tab} ), + <%= content_tag('div', render(:partial => tab[:partial], :locals => {:tab => tab} ), :id => "tab-content-#{tab[:name]}", :style => (tab[:name] != selected_tab ? 'display:none' : nil), :class => 'tab-content') %> diff --git a/app/views/context_menus/issues.html.erb b/app/views/context_menus/issues.html.erb index f0fa350a..71bac63b 100644 --- a/app/views/context_menus/issues.html.erb +++ b/app/views/context_menus/issues.html.erb @@ -10,7 +10,7 @@ <% end %> <% if @allowed_statuses.present? %> -
  • +
  • <%= l(:field_status) %>
      <% @statuses.each do |s| -%> @@ -22,7 +22,7 @@ <% end %> <% unless @trackers.nil? %> -
    • +
    • <%= l(:field_tracker) %>
        <% @trackers.each do |t| -%> @@ -33,7 +33,7 @@ <% end %> -
      • +
      • <%= l(:field_priority) %>
          <% @priorities.each do |p| -%> @@ -45,7 +45,7 @@ <% #TODO: allow editing versions when multiple projects %> <% unless @project.nil? || @project.shared_versions.open.empty? -%> -
        • +
        • <%= l(:field_fixed_version) %>
            <% @project.shared_versions.open.sort.each do |v| -%> @@ -58,7 +58,7 @@ <% end %> <% if @assignables.present? -%> -
          • +
          • <%= l(:field_assigned_to) %>
              <% @assignables.each do |u| -%> @@ -71,7 +71,7 @@ <% end %> <% unless @project.nil? || @project.issue_categories.empty? -%> -
            • +
            • <%= l(:field_category) %>
                <% @project.issue_categories.each do |u| -%> diff --git a/app/views/custom_fields/_form.rhtml b/app/views/custom_fields/_form.rhtml index 2900af90..ec265aca 100644 --- a/app/views/custom_fields/_form.rhtml +++ b/app/views/custom_fields/_form.rhtml @@ -9,10 +9,10 @@ function toggle_custom_field_format() { p_values = $("custom_field_possible_values"); p_searchable = $("custom_field_searchable"); p_default = $("custom_field_default_value"); - + p_default.setAttribute('type','text'); Element.show(p_default.parentNode); - + switch (format.value) { case "list": Element.hide(p_length.parentNode); @@ -65,7 +65,7 @@ function toggle_custom_field_format() {

                <%= f.select :field_format, custom_field_formats_for_select(@custom_field), {}, :onchange => "toggle_custom_field_format();", :disabled => !@custom_field.new_record? %>

                - <%= f.text_field :min_length, :size => 5, :no_label => true %> - + <%= f.text_field :min_length, :size => 5, :no_label => true %> - <%= f.text_field :max_length, :size => 5, :no_label => true %>
                (<%=l(:text_min_max_length_info)%>)

                <%= f.text_field :regexp, :size => 50 %>
                (<%=l(:text_regexp_info)%>)

                @@ -79,7 +79,7 @@ function toggle_custom_field_format() {

                <% case @custom_field.class.name when "IssueCustomField" %> - +
                <%=l(:label_tracker_plural)%> <% for tracker in @trackers %> <%= check_box_tag "custom_field[tracker_ids][]", tracker.id, (@custom_field.trackers.include? tracker) %> <%= tracker.name %> @@ -91,7 +91,7 @@ when "IssueCustomField" %>

                <%= f.check_box :is_for_all %>

                <%= f.check_box :is_filter %>

                <%= f.check_box :searchable %>

                - + <% when "UserCustomField" %>

                <%= f.check_box :is_required %>

                <%= f.check_box :visible %>

                @@ -107,7 +107,7 @@ when "IssueCustomField" %> <% else %>

                <%= f.check_box :is_required %>

                - + <% end %> <%= call_hook(:"view_custom_fields_form_#{@custom_field.type.to_s.underscore}", :custom_field => @custom_field, :form => f) %>
                diff --git a/app/views/custom_fields/edit.rhtml b/app/views/custom_fields/edit.rhtml index d8a94a95..bc266784 100644 --- a/app/views/custom_fields/edit.rhtml +++ b/app/views/custom_fields/edit.rhtml @@ -1,4 +1,4 @@ -

                <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> +

                <%= link_to l(:label_custom_field_plural), :controller => 'custom_fields', :action => 'index' %> » <%= link_to l(@custom_field.type_name), :controller => 'custom_fields', :action => 'index', :tab => @custom_field.type %> » <%=h @custom_field.name %>

                diff --git a/app/views/documents/show.rhtml b/app/views/documents/show.rhtml index 63e32101..75854357 100644 --- a/app/views/documents/show.rhtml +++ b/app/views/documents/show.rhtml @@ -22,7 +22,7 @@

                <%= render :partial => 'attachments/form' %>

                <%= submit_tag l(:button_add) %> - <% end %> + <% end %> <% end %> <% html_title @document.title -%> diff --git a/app/views/enumerations/list.rhtml b/app/views/enumerations/list.rhtml index 62e3f648..64ab4f6b 100644 --- a/app/views/enumerations/list.rhtml +++ b/app/views/enumerations/list.rhtml @@ -20,7 +20,7 @@
  • -<% @containers.each do |container| %> +<% @containers.each do |container| %> <% next if container.attachments.empty? -%> <% if container.is_a?(Version) -%> @@ -25,7 +25,7 @@ <% end -%> - <% container.attachments.each do |file| %> + <% container.attachments.each do |file| %> "> @@ -36,7 +36,7 @@ <%= link_to(image_tag('delete.png'), {:controller => 'attachments', :action => 'destroy', :id => file}, :confirm => l(:text_are_you_sure), :method => :post) if delete_allowed %> - + <% end reset_cycle %> <% end %> diff --git a/app/views/files/new.html.erb b/app/views/files/new.html.erb index d9d1b6ee..8a3ae686 100644 --- a/app/views/files/new.html.erb +++ b/app/views/files/new.html.erb @@ -13,4 +13,4 @@

    <%= render :partial => 'attachments/form' %>

    <%= submit_tag l(:button_add) %> -<% end %> +<% end %> diff --git a/app/views/gantts/show.html.erb b/app/views/gantts/show.html.erb index 8007bbab..0c024528 100644 --- a/app/views/gantts/show.html.erb +++ b/app/views/gantts/show.html.erb @@ -22,14 +22,14 @@ <%= select_year(@gantt.year_from, :prefix => "year", :discard_type => true) %> <%= hidden_field_tag 'zoom', @gantt.zoom %> -<%= link_to_remote l(:button_apply), +<%= link_to_remote l(:button_apply), { :url => { :set_filter => 1 }, :update => "content", :with => "Form.serialize('query_form')" }, :class => 'icon icon-checked' %> - + <%= link_to_remote l(:button_clear), - { :url => { :project_id => @project, :set_filter => 1 }, + { :url => { :project_id => @project, :set_filter => 1 }, :method => :put, :update => "content", }, :class => 'icon icon-reload' %> @@ -57,7 +57,7 @@ if @gantt.zoom >1 end end -# Width of the entire chart +# Width of the entire chart g_width = (@gantt.date_to - @gantt.date_from + 1)*zoom @gantt.render(:top => headers_height + 8, :zoom => zoom, :g_width => g_width, :subject_width => subject_width) @@ -90,25 +90,25 @@ t_height = g_height + headers_height
     
    -<% +<% # # Months headers # month_f = @gantt.date_from left = 0 height = (show_weeks ? header_heigth : header_heigth + g_height) -@gantt.months.times do +@gantt.months.times do width = ((month_f >> 1) - month_f) * zoom - 1 %>
    <%= link_to "#{month_f.year}-#{month_f.month}", @gantt.params.merge(:year => month_f.year, :month => month_f.month), :title => "#{month_name(month_f.month)} #{month_f.year}"%>
    - <% + <% left = left + width + 1 month_f = month_f >> 1 end %> -<% +<% # # Weeks headers # @@ -124,7 +124,7 @@ if show_weeks width = (7 - @gantt.date_from.cwday + 1) * zoom-1 %>
     
    - <% + <% left = left + width+1 end %> <% @@ -134,13 +134,13 @@ if show_weeks
    <%= week_f.cweek if width >= 16 %>
    - <% + <% left = left + width+1 week_f = week_f+7 end end %> -<% +<% # # Days headers # @@ -148,13 +148,13 @@ if show_days left = 0 height = g_height + header_heigth - 1 wday = @gantt.date_from.cwday - (@gantt.date_to - @gantt.date_from + 1).to_i.times do + (@gantt.date_to - @gantt.date_from + 1).to_i.times do width = zoom - 1 %>
    5 %>" class="gantt_hdr"> <%= day_name(wday).first %>
    - <% + <% left = left + width+1 wday = wday + 1 wday = 1 if wday > 7 diff --git a/app/views/groups/_users.html.erb b/app/views/groups/_users.html.erb index d7c462e1..33091ea3 100644 --- a/app/views/groups/_users.html.erb +++ b/app/views/groups/_users.html.erb @@ -28,7 +28,7 @@ <% if users.any? %> <% remote_form_for(:group, @group, :url => {:controller => 'groups', :action => 'add_users', :id => @group}, :method => :post) do |f| %>
    <%=l(:label_user_new)%> - +

    <%= label_tag "user_search", l(:label_user_search) %><%= text_field_tag 'user_search', nil %>

    <%= observe_field(:user_search, :frequency => 0.5, @@ -36,11 +36,11 @@ :url => { :controller => 'groups', :action => 'autocomplete_for_user', :id => @group }, :with => 'q') %> - +
    <%= principals_check_box_tags 'user_ids[]', users %>
    - +

    <%= submit_tag l(:button_add) %>

    <% end %> diff --git a/app/views/help/wiki_syntax_detailed.html.erb b/app/views/help/wiki_syntax_detailed.html.erb index b25911d0..26603f5f 100644 --- a/app/views/help/wiki_syntax_detailed.html.erb +++ b/app/views/help/wiki_syntax_detailed.html.erb @@ -253,9 +253,9 @@ To go live, all you need to add is a database and a web server. 3 def initialize(name) 4 @name = name.capitalize 5 end - 6 + 6 7 def salute - 8 puts "Hello #{@name}!" + 8 puts "Hello #{@name}!" 9 end 10 end diff --git a/app/views/issue_statuses/index.html.erb b/app/views/issue_statuses/index.html.erb index 03f76725..5bc139d8 100644 --- a/app/views/issue_statuses/index.html.erb +++ b/app/views/issue_statuses/index.html.erb @@ -4,7 +4,7 @@

    <%=l(:label_issue_status_plural)%>

    - +
    <%= line_num %>
    test
    <%= checked_image enumeration.active? %> <%= reorder_links('enumeration', {:action => 'update', :id => enumeration}) %> - <%= link_to l(:button_delete), { :action => 'destroy', :id => enumeration }, + <%= link_to l(:button_delete), { :action => 'destroy', :id => enumeration }, :method => :post, :confirm => l(:text_are_you_sure), :class => 'icon icon-del' %> diff --git a/app/views/files/index.html.erb b/app/views/files/index.html.erb index 5a9a5e6f..f788db3e 100644 --- a/app/views/files/index.html.erb +++ b/app/views/files/index.html.erb @@ -16,7 +16,7 @@
    <%= link_to_attachment file, :download => true, :title => file.description %> <%= format_time(file.created_on) %>
    @@ -16,7 +16,7 @@ - + <% for status in @issue_statuses %> "> diff --git a/app/views/issues/_attributes.rhtml b/app/views/issues/_attributes.rhtml index e10858b0..7f5151df 100644 --- a/app/views/issues/_attributes.rhtml +++ b/app/views/issues/_attributes.rhtml @@ -13,18 +13,18 @@

    <%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %> <%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), l(:label_issue_category_new), - 'category[name]', + 'category[name]', {:controller => 'issue_categories', :action => 'new', :project_id => @project}, - :title => l(:label_issue_category_new), + :title => l(:label_issue_category_new), :tabindex => 199) if authorize_for('issue_categories', 'new') %>

    <% end %> <% unless @issue.assignable_versions.empty? %>

    <%= f.select :fixed_version_id, version_options_for_select(@issue.assignable_versions, @issue.fixed_version), :include_blank => true %> <%= prompt_to_remote(image_tag('add.png', :style => 'vertical-align: middle;'), l(:label_version_new), - 'version[name]', + 'version[name]', {:controller => 'versions', :action => 'create', :project_id => @project}, - :title => l(:label_version_new), + :title => l(:label_version_new), :tabindex => 200) if authorize_for('versions', 'new') %>

    <% end %> diff --git a/app/views/issues/_edit.rhtml b/app/views/issues/_edit.rhtml index 6c9bc3d7..d376b36a 100644 --- a/app/views/issues/_edit.rhtml +++ b/app/views/issues/_edit.rhtml @@ -31,13 +31,13 @@ <% end %> <% end %> - +
    <%= l(:field_notes) %> <%= text_area_tag 'notes', @notes, :cols => 60, :rows => 10, :class => 'wiki-edit' %> <%= wikitoolbar_for 'notes' %> <%= call_hook(:view_issues_edit_notes_bottom, { :issue => @issue, :notes => @notes, :form => f }) %>
    - +
    <%=l(:field_status)%><%=l(:button_sort)%>
    <%= link_to status.name, :action => 'edit', :id => status %>
    diff --git a/app/views/issues/_list_simple.rhtml b/app/views/issues/_list_simple.rhtml index dd7f4894..22e61478 100644 --- a/app/views/issues/_list_simple.rhtml +++ b/app/views/issues/_list_simple.rhtml @@ -1,13 +1,13 @@ <% if issues && issues.any? %> <% form_tag({}) do %> -
    +
    - + <% for issue in issues %> - @@ -25,7 +25,7 @@
    # <%=l(:field_project)%> <%=l(:field_tracker)%> <%=l(:field_subject)%>
    diff --git a/app/views/issues/_relations.rhtml b/app/views/issues/_relations.rhtml index f8535b82..e7672dca 100644 --- a/app/views/issues/_relations.rhtml +++ b/app/views/issues/_relations.rhtml @@ -17,7 +17,7 @@ <%= relation.other_issue(@issue).status.name %> <%= format_date(relation.other_issue(@issue).start_date) %> <%= format_date(relation.other_issue(@issue).due_date) %><%= link_to_remote(image_tag('delete.png'), { :url => {:controller => 'issue_relations', :action => 'destroy', :issue_id => @issue, :id => relation}, +<%= link_to_remote(image_tag('delete.png'), { :url => {:controller => 'issue_relations', :action => 'destroy', :issue_id => @issue, :id => relation}, :method => :post }, :title => l(:label_relation_delete)) if authorize_for('issue_relations', 'destroy') %>
    <% end %> -<% remote_form_for(:relation, @relation, +<% remote_form_for(:relation, @relation, :url => {:controller => 'issue_relations', :action => 'new', :issue_id => @issue}, :method => :post, :complete => "Form.Element.focus('relation_issue_to_id');", diff --git a/app/views/issues/bulk_edit.rhtml b/app/views/issues/bulk_edit.rhtml index e9525482..eceb11b8 100644 --- a/app/views/issues/bulk_edit.rhtml +++ b/app/views/issues/bulk_edit.rhtml @@ -20,18 +20,18 @@

    <% end %>

    - + <%= select_tag('issue[priority_id]', "" + options_from_collection_for_select(IssuePriority.all, :id, :name)) %>

    - + <%= select_tag('issue[assigned_to_id]', content_tag('option', l(:label_no_change_option), :value => '') + content_tag('option', l(:label_nobody), :value => 'none') + options_from_collection_for_select(@assignables, :id, :name)) %>

    <% if @project %>

    - + <%= select_tag('issue[category_id]', content_tag('option', l(:label_no_change_option), :value => '') + content_tag('option', l(:label_none), :value => 'none') + options_from_collection_for_select(@project.issue_categories, :id, :name)) %> @@ -40,7 +40,7 @@ <% #TODO: allow editing versions when multiple projects %> <% if @project %>

    - + <%= select_tag('issue[fixed_version_id]', content_tag('option', l(:label_no_change_option), :value => '') + content_tag('option', l(:label_none), :value => 'none') + version_options_for_select(@project.shared_versions.open.sort)) %> @@ -68,12 +68,12 @@ <%= text_field_tag 'issue[start_date]', '', :size => 10 %><%= calendar_for('issue_start_date') %>

    - + <%= text_field_tag 'issue[due_date]', '', :size => 10 %><%= calendar_for('issue_due_date') %>

    <% if Issue.use_field_for_done_ratio? %>

    - + <%= select_tag 'issue[done_ratio]', options_for_select([[l(:label_no_change_option), '']] + (0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %>

    <% end %> diff --git a/app/views/issues/index.api.rsb b/app/views/issues/index.api.rsb index 1ec2acc1..a299ff01 100644 --- a/app/views/issues/index.api.rsb +++ b/app/views/issues/index.api.rsb @@ -11,16 +11,16 @@ api.array :issues, api_meta(:total_count => @issue_count, :offset => @offset, :l api.category(:id => issue.category_id, :name => issue.category.name) unless issue.category.nil? api.fixed_version(:id => issue.fixed_version_id, :name => issue.fixed_version.name) unless issue.fixed_version.nil? api.parent(:id => issue.parent_id) unless issue.parent.nil? - + api.subject issue.subject api.description issue.description api.start_date issue.start_date api.due_date issue.due_date api.done_ratio issue.done_ratio api.estimated_hours issue.estimated_hours - + render_api_custom_values issue.custom_field_values, api - + api.created_on issue.created_on api.updated_on issue.updated_on end diff --git a/app/views/issues/index.rhtml b/app/views/issues/index.rhtml index ddd5d908..3a5c41c5 100644 --- a/app/views/issues/index.rhtml +++ b/app/views/issues/index.rhtml @@ -35,20 +35,20 @@

    - <%= link_to_remote l(:button_apply), + <%= link_to_remote l(:button_apply), { :url => { :set_filter => 1 }, :before => 'selectAllOptions("selected_columns");', :update => "content", :complete => "apply_filters_observer()", :with => "Form.serialize('query_form')" }, :class => 'icon icon-checked' %> - + <%= link_to_remote l(:button_clear), { :url => { :set_filter => 1, :project_id => @project }, :method => :get, :update => "content", }, :class => 'icon icon-reload' %> - + <% if @query.new_record? && User.current.allowed_to?(:save_queries, @project, :global => true) %> <%= link_to l(:button_save), {}, :onclick => "selectAllOptions('selected_columns'); $('query_form').submit(); return false;", :class => 'icon icon-save' %> <% end %> diff --git a/app/views/issues/new.rhtml b/app/views/issues/new.rhtml index b9d6f414..23b4770e 100644 --- a/app/views/issues/new.rhtml +++ b/app/views/issues/new.rhtml @@ -9,14 +9,14 @@

    <%= submit_tag l(:button_create) %> <%= submit_tag l(:button_create_and_continue), :name => 'continue' %> - <%= link_to_remote l(:label_preview), + <%= link_to_remote l(:label_preview), { :url => preview_issue_path(:project_id => @project), :method => 'post', :update => 'preview', :with => "Form.serialize('issue-form')", :complete => "Element.scrollTo('preview')" }, :accesskey => accesskey(:preview) %> - + <%= javascript_tag "Form.Element.focus('issue_subject');" %> <% end %> diff --git a/app/views/issues/show.api.rsb b/app/views/issues/show.api.rsb index 40de41fb..12e5f78d 100644 --- a/app/views/issues/show.api.rsb +++ b/app/views/issues/show.api.rsb @@ -9,7 +9,7 @@ api.issue do api.category(:id => @issue.category_id, :name => @issue.category.name) unless @issue.category.nil? api.fixed_version(:id => @issue.fixed_version_id, :name => @issue.fixed_version.name) unless @issue.fixed_version.nil? api.parent(:id => @issue.parent_id) unless @issue.parent.nil? - + api.subject @issue.subject api.description @issue.description api.start_date @issue.start_date @@ -17,20 +17,20 @@ api.issue do api.done_ratio @issue.done_ratio api.estimated_hours @issue.estimated_hours api.spent_hours(@issue.spent_hours) if User.current.allowed_to?(:view_time_entries, @project) - + render_api_custom_values @issue.custom_field_values, api - + api.created_on @issue.created_on api.updated_on @issue.updated_on - + render_api_issue_children(@issue, api) if include_in_api_response?('children') - + api.array :relations do @relations.each do |relation| api.relation(:id => relation.id, :issue_id => relation.other_issue(@issue).id, :relation_type => relation.relation_type_for(@issue), :delay => relation.delay) end end if include_in_api_response?('relations') && @relations.present? - + api.array :changesets do @issue.changesets.each do |changeset| api.changeset :revision => changeset.revision do @@ -40,7 +40,7 @@ api.issue do end end end if include_in_api_response?('changesets') && User.current.allowed_to?(:view_changesets, @project) - + api.array :journals do @issue.journals.each do |journal| api.journal :id => journal.id do diff --git a/app/views/issues/show.rhtml b/app/views/issues/show.rhtml index 8ff405bb..4b7daba7 100644 --- a/app/views/issues/show.rhtml +++ b/app/views/issues/show.rhtml @@ -4,8 +4,8 @@
    <%= avatar(@issue.author, :size => "50") %> - -
    + +
    <%= render_issue_subject_with_tree(@issue) %>

    @@ -51,7 +51,7 @@

    <%= link_to_remote_if_authorized(l(:button_quote), { :url => {:controller => 'journals', :action => 'new', :id => @issue} }, :class => 'icon icon-comment') %>
    - +

    <%=l(:field_description)%>

    <%= textilizable @issue, :description, :attachments => @issue.attachments %> diff --git a/app/views/journals/_notes_form.rhtml b/app/views/journals/_notes_form.rhtml index 610260b3..2b0a467c 100644 --- a/app/views/journals/_notes_form.rhtml +++ b/app/views/journals/_notes_form.rhtml @@ -3,7 +3,7 @@ :rows => (@journal.notes.blank? ? 10 : [[10, @journal.notes.length / 50].max, 100].min) %> <%= call_hook(:view_journals_notes_form_after_notes, { :journal => @journal}) %>

    <%= submit_tag l(:button_save) %> - <%= link_to_remote l(:label_preview), + <%= link_to_remote l(:label_preview), { :url => preview_issue_path(:project_id => @project, :id => @journal.issue), :method => 'post', :update => "journal_#{@journal.id}_preview", diff --git a/app/views/layouts/base.rhtml b/app/views/layouts/base.rhtml index cb701f93..ea485225 100644 --- a/app/views/layouts/base.rhtml +++ b/app/views/layouts/base.rhtml @@ -31,7 +31,7 @@ <%= content_tag('div', "#{l(:label_logged_as)} #{link_to_user(User.current, :format => :username)}", :id => 'loggedas') if User.current.logged? %> <%= render_menu :top_menu if User.current.logged? || !Setting.login_required? -%>

    - +