@@ -0,0 +1,8 | |||||
|
1 | <h2><%= l(:label_settings) %>: <%=h @plugin.name %></h2> | |||
|
2 | ||||
|
3 | <% form_tag({:action => 'plugin'}) do %> | |||
|
4 | <div class="box tabular"> | |||
|
5 | <%= render :partial => @partial, :locals => {:settings => @settings}%> | |||
|
6 | </div> | |||
|
7 | <%= submit_tag l(:button_apply) %> | |||
|
8 | <% end %> |
@@ -0,0 +1,124 | |||||
|
1 | # redMine - project management software | |||
|
2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |||
|
3 | # | |||
|
4 | # This program is free software; you can redistribute it and/or | |||
|
5 | # modify it under the terms of the GNU General Public License | |||
|
6 | # as published by the Free Software Foundation; either version 2 | |||
|
7 | # of the License, or (at your option) any later version. | |||
|
8 | # | |||
|
9 | # This program is distributed in the hope that it will be useful, | |||
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
|
12 | # GNU General Public License for more details. | |||
|
13 | # | |||
|
14 | # You should have received a copy of the GNU General Public License | |||
|
15 | # along with this program; if not, write to the Free Software | |||
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
|
17 | ||||
|
18 | module Redmine #:nodoc: | |||
|
19 | ||||
|
20 | # Base class for Redmine plugins. | |||
|
21 | # Plugins are registered using the <tt>register</tt> class method that acts as the public constructor. | |||
|
22 | # | |||
|
23 | # Redmine::Plugin.register :example do | |||
|
24 | # name 'Example plugin' | |||
|
25 | # author 'John Smith' | |||
|
26 | # description 'This is an example plugin for Redmine' | |||
|
27 | # version '0.0.1' | |||
|
28 | # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings' | |||
|
29 | # end | |||
|
30 | # | |||
|
31 | # === Plugin attributes | |||
|
32 | # | |||
|
33 | # +settings+ is an optional attribute that let the plugin be configurable. | |||
|
34 | # It must be a hash with the following keys: | |||
|
35 | # * <tt>:default</tt>: default value for the plugin settings | |||
|
36 | # * <tt>:partial</tt>: path of the configuration partial view, relative to the plugin <tt>app/views</tt> directory | |||
|
37 | # Example: | |||
|
38 | # settings :default => {'foo'=>'bar'}, :partial => 'settings/settings' | |||
|
39 | # In this example, the settings partial will be found here in the plugin directory: <tt>app/views/settings/_settings.rhtml</tt>. | |||
|
40 | # | |||
|
41 | # When rendered, the plugin settings value is available as the local variable +settings+ | |||
|
42 | class Plugin | |||
|
43 | @registered_plugins = {} | |||
|
44 | class << self | |||
|
45 | attr_reader :registered_plugins | |||
|
46 | private :new | |||
|
47 | ||||
|
48 | def def_field(*names) | |||
|
49 | class_eval do | |||
|
50 | names.each do |name| | |||
|
51 | define_method(name) do |*args| | |||
|
52 | args.empty? ? instance_variable_get("@#{name}") : instance_variable_set("@#{name}", *args) | |||
|
53 | end | |||
|
54 | end | |||
|
55 | end | |||
|
56 | end | |||
|
57 | end | |||
|
58 | def_field :name, :description, :author, :version, :settings | |||
|
59 | ||||
|
60 | # Plugin constructor | |||
|
61 | def self.register(name, &block) | |||
|
62 | p = new | |||
|
63 | p.instance_eval(&block) | |||
|
64 | Plugin.registered_plugins[name] = p | |||
|
65 | end | |||
|
66 | ||||
|
67 | # Adds an item to the given +menu+. | |||
|
68 | # The +id+ parameter (equals to the project id) is automatically added to the url. | |||
|
69 | # menu :project_menu, :label_plugin_example, :controller => 'example', :action => 'say_hello' | |||
|
70 | # | |||
|
71 | # Currently, only the project menu can be extended. Thus, the +name+ parameter must be +:project_menu+ | |||
|
72 | def menu(name, label, url) | |||
|
73 | Redmine::MenuManager.map(name) {|menu| menu.push label, url} | |||
|
74 | end | |||
|
75 | ||||
|
76 | # Defines a permission called +name+ for the given +actions+. | |||
|
77 | # | |||
|
78 | # The +actions+ argument is a hash with controllers as keys and actions as values (a single value or an array): | |||
|
79 | # permission :destroy_contacts, { :contacts => :destroy } | |||
|
80 | # permission :view_contacts, { :contacts => [:index, :show] } | |||
|
81 | # | |||
|
82 | # The +options+ argument can be used to make the permission public (implicitly given to any user) | |||
|
83 | # or to restrict users the permission can be given to. | |||
|
84 | # | |||
|
85 | # Examples | |||
|
86 | # # A permission that is implicitly given to any user | |||
|
87 | # # This permission won't appear on the Roles & Permissions setup screen | |||
|
88 | # permission :say_hello, { :example => :say_hello }, :public => true | |||
|
89 | # | |||
|
90 | # # A permission that can be given to any user | |||
|
91 | # permission :say_hello, { :example => :say_hello } | |||
|
92 | # | |||
|
93 | # # A permission that can be given to registered users only | |||
|
94 | # permission :say_hello, { :example => :say_hello }, :require => loggedin | |||
|
95 | # | |||
|
96 | # # A permission that can be given to project members only | |||
|
97 | # permission :say_hello, { :example => :say_hello }, :require => member | |||
|
98 | def permission(name, actions, options = {}) | |||
|
99 | if @project_module | |||
|
100 | Redmine::AccessControl.map {|map| map.project_module(@project_module) {|map|map.permission(name, actions, options)}} | |||
|
101 | else | |||
|
102 | Redmine::AccessControl.map {|map| map.permission(name, actions, options)} | |||
|
103 | end | |||
|
104 | end | |||
|
105 | ||||
|
106 | # Defines a project module, that can be enabled/disabled for each project. | |||
|
107 | # Permissions defined inside +block+ will be bind to the module. | |||
|
108 | # | |||
|
109 | # project_module :things do | |||
|
110 | # permission :view_contacts, { :contacts => [:list, :show] }, :public => true | |||
|
111 | # permission :destroy_contacts, { :contacts => :destroy } | |||
|
112 | # end | |||
|
113 | def project_module(name, &block) | |||
|
114 | @project_module = name | |||
|
115 | self.instance_eval(&block) | |||
|
116 | @project_module = nil | |||
|
117 | end | |||
|
118 | ||||
|
119 | # Returns +true+ if the plugin can be configured. | |||
|
120 | def configurable? | |||
|
121 | settings && settings.is_a?(Hash) && !settings[:partial].blank? | |||
|
122 | end | |||
|
123 | end | |||
|
124 | end |
@@ -0,0 +1,15 | |||||
|
1 | namespace :db do | |||
|
2 | desc 'Migrates installed plugins.' | |||
|
3 | task :migrate_plugins => :environment do | |||
|
4 | if Rails.respond_to?('plugins') | |||
|
5 | Rails.plugins.each do |plugin| | |||
|
6 | next unless plugin.respond_to?('migrate') | |||
|
7 | puts "Migrating #{plugin.name}..." | |||
|
8 | plugin.migrate | |||
|
9 | end | |||
|
10 | else | |||
|
11 | puts "Undefined method plugins for Rails!" | |||
|
12 | puts "Make sure engines plugin is installed." | |||
|
13 | end | |||
|
14 | end | |||
|
15 | end |
1 | NO CONTENT: new file 100644, binary diff hidden |
|
NO CONTENT: new file 100644, binary diff hidden |
@@ -1,79 +1,80 | |||||
1 | # redMine - project management software |
|
1 | # redMine - project management software | |
2 | # Copyright (C) 2006 Jean-Philippe Lang |
|
2 | # Copyright (C) 2006 Jean-Philippe Lang | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
4 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
5 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
6 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
7 | # of the License, or (at your option) any later version. | |
8 | # |
|
8 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
12 | # GNU General Public License for more details. | |
13 | # |
|
13 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
14 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
15 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
17 | |||
18 | class AdminController < ApplicationController |
|
18 | class AdminController < ApplicationController | |
19 | layout 'base' |
|
19 | layout 'base' | |
20 | before_filter :require_admin |
|
20 | before_filter :require_admin | |
21 |
|
21 | |||
22 | helper :sort |
|
22 | helper :sort | |
23 | include SortHelper |
|
23 | include SortHelper | |
24 |
|
24 | |||
25 | def index |
|
25 | def index | |
26 | end |
|
26 | end | |
27 |
|
27 | |||
28 | def projects |
|
28 | def projects | |
29 | sort_init 'name', 'asc' |
|
29 | sort_init 'name', 'asc' | |
30 | sort_update |
|
30 | sort_update | |
31 |
|
31 | |||
32 | @status = params[:status] ? params[:status].to_i : 0 |
|
32 | @status = params[:status] ? params[:status].to_i : 0 | |
33 | conditions = nil |
|
33 | conditions = nil | |
34 | conditions = ["status=?", @status] unless @status == 0 |
|
34 | conditions = ["status=?", @status] unless @status == 0 | |
35 |
|
35 | |||
36 | @project_count = Project.count(:conditions => conditions) |
|
36 | @project_count = Project.count(:conditions => conditions) | |
37 | @project_pages = Paginator.new self, @project_count, |
|
37 | @project_pages = Paginator.new self, @project_count, | |
38 | 25, |
|
38 | 25, | |
39 | params['page'] |
|
39 | params['page'] | |
40 | @projects = Project.find :all, :order => sort_clause, |
|
40 | @projects = Project.find :all, :order => sort_clause, | |
41 | :conditions => conditions, |
|
41 | :conditions => conditions, | |
42 | :limit => @project_pages.items_per_page, |
|
42 | :limit => @project_pages.items_per_page, | |
43 | :offset => @project_pages.current.offset |
|
43 | :offset => @project_pages.current.offset | |
44 |
|
44 | |||
45 | render :action => "projects", :layout => false if request.xhr? |
|
45 | render :action => "projects", :layout => false if request.xhr? | |
46 | end |
|
46 | end | |
47 |
|
47 | |||
48 | def mail_options |
|
48 | def mail_options | |
49 | @notifiables = %w(issue_added issue_updated news_added document_added file_added message_posted) |
|
49 | @notifiables = %w(issue_added issue_updated news_added document_added file_added message_posted) | |
50 | if request.post? |
|
50 | if request.post? | |
51 | Setting.notified_events = (params[:notified_events] || []) |
|
51 | Setting.notified_events = (params[:notified_events] || []) | |
52 | flash[:notice] = l(:notice_successful_update) |
|
52 | flash[:notice] = l(:notice_successful_update) | |
53 | redirect_to :controller => 'admin', :action => 'mail_options' |
|
53 | redirect_to :controller => 'admin', :action => 'mail_options' | |
54 | end |
|
54 | end | |
55 | end |
|
55 | end | |
56 |
|
56 | |||
57 | def test_email |
|
57 | def test_email | |
58 | raise_delivery_errors = ActionMailer::Base.raise_delivery_errors |
|
58 | raise_delivery_errors = ActionMailer::Base.raise_delivery_errors | |
59 | # Force ActionMailer to raise delivery errors so we can catch it |
|
59 | # Force ActionMailer to raise delivery errors so we can catch it | |
60 | ActionMailer::Base.raise_delivery_errors = true |
|
60 | ActionMailer::Base.raise_delivery_errors = true | |
61 | begin |
|
61 | begin | |
62 | @test = Mailer.deliver_test(User.current) |
|
62 | @test = Mailer.deliver_test(User.current) | |
63 | flash[:notice] = l(:notice_email_sent, User.current.mail) |
|
63 | flash[:notice] = l(:notice_email_sent, User.current.mail) | |
64 | rescue Exception => e |
|
64 | rescue Exception => e | |
65 | flash[:error] = l(:notice_email_error, e.message) |
|
65 | flash[:error] = l(:notice_email_error, e.message) | |
66 | end |
|
66 | end | |
67 | ActionMailer::Base.raise_delivery_errors = raise_delivery_errors |
|
67 | ActionMailer::Base.raise_delivery_errors = raise_delivery_errors | |
68 | redirect_to :action => 'mail_options' |
|
68 | redirect_to :action => 'mail_options' | |
69 | end |
|
69 | end | |
70 |
|
70 | |||
71 | def info |
|
71 | def info | |
72 | @db_adapter_name = ActiveRecord::Base.connection.adapter_name |
|
72 | @db_adapter_name = ActiveRecord::Base.connection.adapter_name | |
73 | @flags = { |
|
73 | @flags = { | |
74 | :default_admin_changed => User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?, |
|
74 | :default_admin_changed => User.find(:first, :conditions => ["login=? and hashed_password=?", 'admin', User.hash_password('admin')]).nil?, | |
75 | :file_repository_writable => File.writable?(Attachment.storage_path), |
|
75 | :file_repository_writable => File.writable?(Attachment.storage_path), | |
76 | :rmagick_available => Object.const_defined?(:Magick) |
|
76 | :rmagick_available => Object.const_defined?(:Magick) | |
77 |
|
|
77 | } | |
|
78 | @plugins = Redmine::Plugin.registered_plugins | |||
78 | end |
|
79 | end | |
79 | end |
|
80 | end |
@@ -1,33 +1,45 | |||||
1 | # redMine - project management software |
|
1 | # redMine - project management software | |
2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
4 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
5 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
6 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
7 | # of the License, or (at your option) any later version. | |
8 | # |
|
8 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
12 | # GNU General Public License for more details. | |
13 | # |
|
13 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
14 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
15 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
17 | |||
18 | class SettingsController < ApplicationController |
|
18 | class SettingsController < ApplicationController | |
19 | layout 'base' |
|
19 | layout 'base' | |
20 | before_filter :require_admin |
|
20 | before_filter :require_admin | |
21 |
|
21 | |||
22 | def index |
|
22 | def index | |
23 | edit |
|
23 | edit | |
24 | render :action => 'edit' |
|
24 | render :action => 'edit' | |
25 | end |
|
25 | end | |
26 |
|
26 | |||
27 | def edit |
|
27 | def edit | |
28 | if request.post? and params[:settings] and params[:settings].is_a? Hash |
|
28 | if request.post? and params[:settings] and params[:settings].is_a? Hash | |
29 | params[:settings].each { |name, value| Setting[name] = value } |
|
29 | params[:settings].each { |name, value| Setting[name] = value } | |
30 | redirect_to :action => 'edit' and return |
|
30 | redirect_to :action => 'edit' and return | |
31 | end |
|
31 | end | |
32 | end |
|
32 | end | |
|
33 | ||||
|
34 | def plugin | |||
|
35 | plugin_id = params[:id].to_sym | |||
|
36 | @plugin = Redmine::Plugin.registered_plugins[plugin_id] | |||
|
37 | if request.post? | |||
|
38 | Setting["plugin_#{plugin_id}"] = params[:settings] | |||
|
39 | flash[:notice] = l(:notice_successful_update) | |||
|
40 | redirect_to :action => 'plugin', :id => params[:id] | |||
|
41 | end | |||
|
42 | @partial = "../../vendor/plugins/#{plugin_id}/app/views/" + @plugin.settings[:partial] | |||
|
43 | @settings = Setting["plugin_#{plugin_id}"] | |||
|
44 | end | |||
33 | end |
|
45 | end |
@@ -1,98 +1,102 | |||||
1 | # redMine - project management software |
|
1 | # redMine - project management software | |
2 | # Copyright (C) 2006-2007 Jean-Philippe Lang |
|
2 | # Copyright (C) 2006-2007 Jean-Philippe Lang | |
3 | # |
|
3 | # | |
4 | # This program is free software; you can redistribute it and/or |
|
4 | # This program is free software; you can redistribute it and/or | |
5 | # modify it under the terms of the GNU General Public License |
|
5 | # modify it under the terms of the GNU General Public License | |
6 | # as published by the Free Software Foundation; either version 2 |
|
6 | # as published by the Free Software Foundation; either version 2 | |
7 | # of the License, or (at your option) any later version. |
|
7 | # of the License, or (at your option) any later version. | |
8 | # |
|
8 | # | |
9 | # This program is distributed in the hope that it will be useful, |
|
9 | # This program is distributed in the hope that it will be useful, | |
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | # GNU General Public License for more details. |
|
12 | # GNU General Public License for more details. | |
13 | # |
|
13 | # | |
14 | # You should have received a copy of the GNU General Public License |
|
14 | # You should have received a copy of the GNU General Public License | |
15 | # along with this program; if not, write to the Free Software |
|
15 | # along with this program; if not, write to the Free Software | |
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
|
16 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
17 |
|
17 | |||
18 | class Setting < ActiveRecord::Base |
|
18 | class Setting < ActiveRecord::Base | |
19 |
|
19 | |||
20 | cattr_accessor :available_settings |
|
20 | cattr_accessor :available_settings | |
21 | @@available_settings = YAML::load(File.open("#{RAILS_ROOT}/config/settings.yml")) |
|
21 | @@available_settings = YAML::load(File.open("#{RAILS_ROOT}/config/settings.yml")) | |
22 |
|
22 | Redmine::Plugin.registered_plugins.each do |id, plugin| | ||
|
23 | next unless plugin.settings | |||
|
24 | @@available_settings["plugin_#{id}"] = {'default' => plugin.settings[:default], 'serialized' => true} | |||
|
25 | end | |||
|
26 | ||||
23 | validates_uniqueness_of :name |
|
27 | validates_uniqueness_of :name | |
24 | validates_inclusion_of :name, :in => @@available_settings.keys |
|
28 | validates_inclusion_of :name, :in => @@available_settings.keys | |
25 | validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting| @@available_settings[setting.name]['format'] == 'int' } |
|
29 | validates_numericality_of :value, :only_integer => true, :if => Proc.new { |setting| @@available_settings[setting.name]['format'] == 'int' } | |
26 |
|
30 | |||
27 | # Hash used to cache setting values |
|
31 | # Hash used to cache setting values | |
28 | @cached_settings = {} |
|
32 | @cached_settings = {} | |
29 | @cached_cleared_on = Time.now |
|
33 | @cached_cleared_on = Time.now | |
30 |
|
34 | |||
31 | def value |
|
35 | def value | |
32 | v = read_attribute(:value) |
|
36 | v = read_attribute(:value) | |
33 | # Unserialize serialized settings |
|
37 | # Unserialize serialized settings | |
34 | v = YAML::load(v) if @@available_settings[name]['serialized'] && v.is_a?(String) |
|
38 | v = YAML::load(v) if @@available_settings[name]['serialized'] && v.is_a?(String) | |
35 | v |
|
39 | v | |
36 | end |
|
40 | end | |
37 |
|
41 | |||
38 | def value=(v) |
|
42 | def value=(v) | |
39 | v = v.to_yaml if v && @@available_settings[name]['serialized'] |
|
43 | v = v.to_yaml if v && @@available_settings[name]['serialized'] | |
40 | write_attribute(:value, v) |
|
44 | write_attribute(:value, v) | |
41 | end |
|
45 | end | |
42 |
|
46 | |||
43 | # Returns the value of the setting named name |
|
47 | # Returns the value of the setting named name | |
44 | def self.[](name) |
|
48 | def self.[](name) | |
45 | v = @cached_settings[name] |
|
49 | v = @cached_settings[name] | |
46 | v ? v : (@cached_settings[name] = find_or_default(name).value) |
|
50 | v ? v : (@cached_settings[name] = find_or_default(name).value) | |
47 | end |
|
51 | end | |
48 |
|
52 | |||
49 | def self.[]=(name, v) |
|
53 | def self.[]=(name, v) | |
50 | setting = find_or_default(name) |
|
54 | setting = find_or_default(name) | |
51 | setting.value = (v ? v : "") |
|
55 | setting.value = (v ? v : "") | |
52 | @cached_settings[name] = nil |
|
56 | @cached_settings[name] = nil | |
53 | setting.save |
|
57 | setting.save | |
54 | setting.value |
|
58 | setting.value | |
55 | end |
|
59 | end | |
56 |
|
60 | |||
57 | # Defines getter and setter for each setting |
|
61 | # Defines getter and setter for each setting | |
58 | # Then setting values can be read using: Setting.some_setting_name |
|
62 | # Then setting values can be read using: Setting.some_setting_name | |
59 | # or set using Setting.some_setting_name = "some value" |
|
63 | # or set using Setting.some_setting_name = "some value" | |
60 | @@available_settings.each do |name, params| |
|
64 | @@available_settings.each do |name, params| | |
61 | src = <<-END_SRC |
|
65 | src = <<-END_SRC | |
62 | def self.#{name} |
|
66 | def self.#{name} | |
63 | self[:#{name}] |
|
67 | self[:#{name}] | |
64 | end |
|
68 | end | |
65 |
|
69 | |||
66 | def self.#{name}? |
|
70 | def self.#{name}? | |
67 | self[:#{name}].to_i > 0 |
|
71 | self[:#{name}].to_i > 0 | |
68 | end |
|
72 | end | |
69 |
|
73 | |||
70 | def self.#{name}=(value) |
|
74 | def self.#{name}=(value) | |
71 | self[:#{name}] = value |
|
75 | self[:#{name}] = value | |
72 | end |
|
76 | end | |
73 | END_SRC |
|
77 | END_SRC | |
74 | class_eval src, __FILE__, __LINE__ |
|
78 | class_eval src, __FILE__, __LINE__ | |
75 | end |
|
79 | end | |
76 |
|
80 | |||
77 | # Checks if settings have changed since the values were read |
|
81 | # Checks if settings have changed since the values were read | |
78 | # and clears the cache hash if it's the case |
|
82 | # and clears the cache hash if it's the case | |
79 | # Called once per request |
|
83 | # Called once per request | |
80 | def self.check_cache |
|
84 | def self.check_cache | |
81 | settings_updated_on = Setting.maximum(:updated_on) |
|
85 | settings_updated_on = Setting.maximum(:updated_on) | |
82 | if settings_updated_on && @cached_cleared_on <= settings_updated_on |
|
86 | if settings_updated_on && @cached_cleared_on <= settings_updated_on | |
83 | @cached_settings.clear |
|
87 | @cached_settings.clear | |
84 | @cached_cleared_on = Time.now |
|
88 | @cached_cleared_on = Time.now | |
85 | logger.info "Settings cache cleared." if logger |
|
89 | logger.info "Settings cache cleared." if logger | |
86 | end |
|
90 | end | |
87 | end |
|
91 | end | |
88 |
|
92 | |||
89 | private |
|
93 | private | |
90 | # Returns the Setting instance for the setting named name |
|
94 | # Returns the Setting instance for the setting named name | |
91 | # (record found in database or new record with default value) |
|
95 | # (record found in database or new record with default value) | |
92 | def self.find_or_default(name) |
|
96 | def self.find_or_default(name) | |
93 | name = name.to_s |
|
97 | name = name.to_s | |
94 | raise "There's no setting named #{name}" unless @@available_settings.has_key?(name) |
|
98 | raise "There's no setting named #{name}" unless @@available_settings.has_key?(name) | |
95 | setting = find_by_name(name) |
|
99 | setting = find_by_name(name) | |
96 | setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name |
|
100 | setting ||= new(:name => name, :value => @@available_settings[name]['default']) if @@available_settings.has_key? name | |
97 | end |
|
101 | end | |
98 | end |
|
102 | end |
@@ -1,9 +1,25 | |||||
1 | <h2><%=l(:label_information_plural)%></h2> |
|
1 | <h2><%=l(:label_information_plural)%></h2> | |
2 |
|
2 | |||
3 | <p><%=l(:field_version)%>: <strong><%= Redmine::Info.versioned_name %></strong> (<%= @db_adapter_name %>)</p> |
|
3 | <p><%=l(:field_version)%>: <strong><%= Redmine::Info.versioned_name %></strong> (<%= @db_adapter_name %>)</p> | |
4 |
|
4 | |||
5 | <table class="list"> |
|
5 | <table class="list"> | |
6 | <tr class="odd"><td>Default administrator account changed</td><td><%= image_tag (@flags[:default_admin_changed] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> |
|
6 | <tr class="odd"><td>Default administrator account changed</td><td><%= image_tag (@flags[:default_admin_changed] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> | |
7 | <tr class="even"><td>File repository writable</td><td><%= image_tag (@flags[:file_repository_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> |
|
7 | <tr class="even"><td>File repository writable</td><td><%= image_tag (@flags[:file_repository_writable] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> | |
8 | <tr class="odd"><td>RMagick available</td><td><%= image_tag (@flags[:rmagick_available] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> |
|
8 | <tr class="odd"><td>RMagick available</td><td><%= image_tag (@flags[:rmagick_available] ? 'true.png' : 'false.png'), :style => "vertical-align:bottom;" %></td></tr> | |
9 | </table> |
|
9 | </table> | |
|
10 | ||||
|
11 | <% if @plugins.any? %> | |||
|
12 | | |||
|
13 | <h3 class="icon22 icon22-plugin">Plugins</h3> | |||
|
14 | <table class="list"> | |||
|
15 | <% @plugins.keys.sort.each do |plugin| %> | |||
|
16 | <tr class="<%= cycle('odd', 'even') %>"> | |||
|
17 | <td><%=h @plugins[plugin].name %></td> | |||
|
18 | <td><%=h @plugins[plugin].description %></td> | |||
|
19 | <td><%=h @plugins[plugin].author %></td> | |||
|
20 | <td><%=h @plugins[plugin].version %></td> | |||
|
21 | <td><%= link_to('Configure', :controller => 'settings', :action => 'plugin', :id => plugin.to_s) if @plugins[plugin].configurable? %></td> | |||
|
22 | </tr> | |||
|
23 | <% end %> | |||
|
24 | </table> | |||
|
25 | <% end %> |
@@ -1,87 +1,91 | |||||
1 | # Be sure to restart your web server when you modify this file. |
|
1 | # Be sure to restart your web server when you modify this file. | |
2 |
|
2 | |||
3 | # Uncomment below to force Rails into production mode when |
|
3 | # Uncomment below to force Rails into production mode when | |
4 | # you don't control web/app server and can't set it the proper way |
|
4 | # you don't control web/app server and can't set it the proper way | |
5 | # ENV['RAILS_ENV'] ||= 'production' |
|
5 | # ENV['RAILS_ENV'] ||= 'production' | |
6 |
|
6 | |||
7 | # Bootstrap the Rails environment, frameworks, and default configuration |
|
7 | # Bootstrap the Rails environment, frameworks, and default configuration | |
8 | require File.join(File.dirname(__FILE__), 'boot') |
|
8 | require File.join(File.dirname(__FILE__), 'boot') | |
9 |
|
9 | |||
10 | Rails::Initializer.run do |config| |
|
10 | Rails::Initializer.run do |config| | |
11 | # Settings in config/environments/* take precedence those specified here |
|
11 | # Settings in config/environments/* take precedence those specified here | |
12 |
|
12 | |||
13 | # Skip frameworks you're not going to use |
|
13 | # Skip frameworks you're not going to use | |
14 | # config.frameworks -= [ :action_web_service, :action_mailer ] |
|
14 | # config.frameworks -= [ :action_web_service, :action_mailer ] | |
15 |
|
15 | |||
16 | # Add additional load paths for sweepers |
|
16 | # Add additional load paths for sweepers | |
17 | config.load_paths += %W( #{RAILS_ROOT}/app/sweepers ) |
|
17 | config.load_paths += %W( #{RAILS_ROOT}/app/sweepers ) | |
18 |
|
18 | |||
19 | # Force all environments to use the same logger level |
|
19 | # Force all environments to use the same logger level | |
20 | # (by default production uses :info, the others :debug) |
|
20 | # (by default production uses :info, the others :debug) | |
21 | # config.log_level = :debug |
|
21 | # config.log_level = :debug | |
22 |
|
22 | |||
23 | # Use the database for sessions instead of the file system |
|
23 | # Use the database for sessions instead of the file system | |
24 | # (create the session table with 'rake create_sessions_table') |
|
24 | # (create the session table with 'rake create_sessions_table') | |
25 | # config.action_controller.session_store = :active_record_store |
|
25 | # config.action_controller.session_store = :active_record_store | |
26 |
|
26 | |||
27 | # Enable page/fragment caching by setting a file-based store |
|
27 | # Enable page/fragment caching by setting a file-based store | |
28 | # (remember to create the caching directory and make it readable to the application) |
|
28 | # (remember to create the caching directory and make it readable to the application) | |
29 | # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" |
|
29 | # config.action_controller.fragment_cache_store = :file_store, "#{RAILS_ROOT}/cache" | |
30 |
|
30 | |||
31 | # Activate observers that should always be running |
|
31 | # Activate observers that should always be running | |
32 | # config.active_record.observers = :cacher, :garbage_collector |
|
32 | # config.active_record.observers = :cacher, :garbage_collector | |
33 | config.active_record.observers = :message_observer |
|
33 | config.active_record.observers = :message_observer | |
34 |
|
34 | |||
35 | # Make Active Record use UTC-base instead of local time |
|
35 | # Make Active Record use UTC-base instead of local time | |
36 | # config.active_record.default_timezone = :utc |
|
36 | # config.active_record.default_timezone = :utc | |
37 |
|
37 | |||
38 | # Use Active Record's schema dumper instead of SQL when creating the test database |
|
38 | # Use Active Record's schema dumper instead of SQL when creating the test database | |
39 | # (enables use of different database adapters for development and test environments) |
|
39 | # (enables use of different database adapters for development and test environments) | |
40 | # config.active_record.schema_format = :ruby |
|
40 | # config.active_record.schema_format = :ruby | |
41 |
|
41 | |||
42 | # See Rails::Configuration for more options |
|
42 | # See Rails::Configuration for more options | |
43 |
|
43 | |||
44 | # SMTP server configuration |
|
44 | # SMTP server configuration | |
45 | config.action_mailer.smtp_settings = { |
|
45 | config.action_mailer.smtp_settings = { | |
46 | :address => "127.0.0.1", |
|
46 | :address => "127.0.0.1", | |
47 | :port => 25, |
|
47 | :port => 25, | |
48 | :domain => "somenet.foo", |
|
48 | :domain => "somenet.foo", | |
49 | :authentication => :login, |
|
49 | :authentication => :login, | |
50 | :user_name => "redmine", |
|
50 | :user_name => "redmine", | |
51 | :password => "redmine", |
|
51 | :password => "redmine", | |
52 | } |
|
52 | } | |
53 |
|
53 | |||
54 | config.action_mailer.perform_deliveries = true |
|
54 | config.action_mailer.perform_deliveries = true | |
55 |
|
55 | |||
56 | # Tell ActionMailer not to deliver emails to the real world. |
|
56 | # Tell ActionMailer not to deliver emails to the real world. | |
57 | # The :test delivery method accumulates sent emails in the |
|
57 | # The :test delivery method accumulates sent emails in the | |
58 | # ActionMailer::Base.deliveries array. |
|
58 | # ActionMailer::Base.deliveries array. | |
59 | #config.action_mailer.delivery_method = :test |
|
59 | #config.action_mailer.delivery_method = :test | |
60 | config.action_mailer.delivery_method = :smtp |
|
60 | config.action_mailer.delivery_method = :smtp | |
|
61 | ||||
|
62 | # Uncomment this line if the engines plugin is installed. | |||
|
63 | # This will ensure that engines is loaded first. | |||
|
64 | # config.plugins = ["engines", "*"] | |||
61 | end |
|
65 | end | |
62 |
|
66 | |||
63 | ActiveRecord::Errors.default_error_messages = { |
|
67 | ActiveRecord::Errors.default_error_messages = { | |
64 | :inclusion => "activerecord_error_inclusion", |
|
68 | :inclusion => "activerecord_error_inclusion", | |
65 | :exclusion => "activerecord_error_exclusion", |
|
69 | :exclusion => "activerecord_error_exclusion", | |
66 | :invalid => "activerecord_error_invalid", |
|
70 | :invalid => "activerecord_error_invalid", | |
67 | :confirmation => "activerecord_error_confirmation", |
|
71 | :confirmation => "activerecord_error_confirmation", | |
68 | :accepted => "activerecord_error_accepted", |
|
72 | :accepted => "activerecord_error_accepted", | |
69 | :empty => "activerecord_error_empty", |
|
73 | :empty => "activerecord_error_empty", | |
70 | :blank => "activerecord_error_blank", |
|
74 | :blank => "activerecord_error_blank", | |
71 | :too_long => "activerecord_error_too_long", |
|
75 | :too_long => "activerecord_error_too_long", | |
72 | :too_short => "activerecord_error_too_short", |
|
76 | :too_short => "activerecord_error_too_short", | |
73 | :wrong_length => "activerecord_error_wrong_length", |
|
77 | :wrong_length => "activerecord_error_wrong_length", | |
74 | :taken => "activerecord_error_taken", |
|
78 | :taken => "activerecord_error_taken", | |
75 | :not_a_number => "activerecord_error_not_a_number" |
|
79 | :not_a_number => "activerecord_error_not_a_number" | |
76 | } |
|
80 | } | |
77 |
|
81 | |||
78 | ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" } |
|
82 | ActionView::Base.field_error_proc = Proc.new{ |html_tag, instance| "#{html_tag}" } | |
79 |
|
83 | |||
80 | GLoc.set_config :default_language => :en |
|
84 | GLoc.set_config :default_language => :en | |
81 | GLoc.clear_strings |
|
85 | GLoc.clear_strings | |
82 | GLoc.set_kcode |
|
86 | GLoc.set_kcode | |
83 | GLoc.load_localized_strings |
|
87 | GLoc.load_localized_strings | |
84 | GLoc.set_config(:raise_string_not_found_errors => false) |
|
88 | GLoc.set_config(:raise_string_not_found_errors => false) | |
85 |
|
89 | |||
86 | require 'redmine' |
|
90 | require 'redmine' | |
87 |
|
91 |
@@ -1,102 +1,103 | |||||
1 | require 'redmine/access_control' |
|
1 | require 'redmine/access_control' | |
2 | require 'redmine/menu_manager' |
|
2 | require 'redmine/menu_manager' | |
3 | require 'redmine/mime_type' |
|
3 | require 'redmine/mime_type' | |
4 | require 'redmine/acts_as_watchable/init' |
|
4 | require 'redmine/acts_as_watchable/init' | |
5 | require 'redmine/acts_as_event/init' |
|
5 | require 'redmine/acts_as_event/init' | |
|
6 | require 'redmine/plugin' | |||
6 |
|
7 | |||
7 | begin |
|
8 | begin | |
8 | require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick) |
|
9 | require_library_or_gem 'RMagick' unless Object.const_defined?(:Magick) | |
9 | rescue LoadError |
|
10 | rescue LoadError | |
10 | # RMagick is not available |
|
11 | # RMagick is not available | |
11 | end |
|
12 | end | |
12 |
|
13 | |||
13 | REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs ) |
|
14 | REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs ) | |
14 |
|
15 | |||
15 | # Permissions |
|
16 | # Permissions | |
16 | Redmine::AccessControl.map do |map| |
|
17 | Redmine::AccessControl.map do |map| | |
17 | map.permission :view_project, {:projects => [:show, :activity, :feeds]}, :public => true |
|
18 | map.permission :view_project, {:projects => [:show, :activity, :feeds]}, :public => true | |
18 | map.permission :search_project, {:search => :index}, :public => true |
|
19 | map.permission :search_project, {:search => :index}, :public => true | |
19 | map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member |
|
20 | map.permission :edit_project, {:projects => [:settings, :edit]}, :require => :member | |
20 | map.permission :select_project_modules, {:projects => :modules}, :require => :member |
|
21 | map.permission :select_project_modules, {:projects => :modules}, :require => :member | |
21 | map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy]}, :require => :member |
|
22 | map.permission :manage_members, {:projects => :settings, :members => [:new, :edit, :destroy]}, :require => :member | |
22 | map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member |
|
23 | map.permission :manage_versions, {:projects => [:settings, :add_version], :versions => [:edit, :destroy]}, :require => :member | |
23 |
|
24 | |||
24 | map.project_module :issue_tracking do |map| |
|
25 | map.project_module :issue_tracking do |map| | |
25 | # Issue categories |
|
26 | # Issue categories | |
26 | map.permission :manage_categories, {:projects => [:settings, :add_issue_category], :issue_categories => [:edit, :destroy]}, :require => :member |
|
27 | map.permission :manage_categories, {:projects => [:settings, :add_issue_category], :issue_categories => [:edit, :destroy]}, :require => :member | |
27 | # Issues |
|
28 | # Issues | |
28 | map.permission :view_issues, {:projects => [:list_issues, :export_issues_csv, :export_issues_pdf, :changelog, :roadmap], |
|
29 | map.permission :view_issues, {:projects => [:list_issues, :export_issues_csv, :export_issues_pdf, :changelog, :roadmap], | |
29 | :issues => [:show, :export_pdf], |
|
30 | :issues => [:show, :export_pdf], | |
30 | :queries => :index, |
|
31 | :queries => :index, | |
31 | :reports => :issue_report}, :public => true |
|
32 | :reports => :issue_report}, :public => true | |
32 | map.permission :add_issues, {:projects => :add_issue}, :require => :loggedin |
|
33 | map.permission :add_issues, {:projects => :add_issue}, :require => :loggedin | |
33 | map.permission :edit_issues, {:issues => [:edit, :destroy_attachment]}, :require => :loggedin |
|
34 | map.permission :edit_issues, {:issues => [:edit, :destroy_attachment]}, :require => :loggedin | |
34 | map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}, :require => :loggedin |
|
35 | map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]}, :require => :loggedin | |
35 | map.permission :add_issue_notes, {:issues => :add_note}, :require => :loggedin |
|
36 | map.permission :add_issue_notes, {:issues => :add_note}, :require => :loggedin | |
36 | map.permission :change_issue_status, {:issues => :change_status}, :require => :loggedin |
|
37 | map.permission :change_issue_status, {:issues => :change_status}, :require => :loggedin | |
37 | map.permission :move_issues, {:projects => :move_issues}, :require => :loggedin |
|
38 | map.permission :move_issues, {:projects => :move_issues}, :require => :loggedin | |
38 | map.permission :delete_issues, {:issues => :destroy}, :require => :member |
|
39 | map.permission :delete_issues, {:issues => :destroy}, :require => :member | |
39 | # Queries |
|
40 | # Queries | |
40 | map.permission :manage_pulic_queries, {:queries => [:new, :edit, :destroy]}, :require => :member |
|
41 | map.permission :manage_pulic_queries, {:queries => [:new, :edit, :destroy]}, :require => :member | |
41 | map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin |
|
42 | map.permission :save_queries, {:queries => [:new, :edit, :destroy]}, :require => :loggedin | |
42 | # Gantt & calendar |
|
43 | # Gantt & calendar | |
43 | map.permission :view_gantt, :projects => :gantt |
|
44 | map.permission :view_gantt, :projects => :gantt | |
44 | map.permission :view_calendar, :projects => :calendar |
|
45 | map.permission :view_calendar, :projects => :calendar | |
45 | end |
|
46 | end | |
46 |
|
47 | |||
47 | map.project_module :time_tracking do |map| |
|
48 | map.project_module :time_tracking do |map| | |
48 | map.permission :log_time, {:timelog => :edit}, :require => :loggedin |
|
49 | map.permission :log_time, {:timelog => :edit}, :require => :loggedin | |
49 | map.permission :view_time_entries, :timelog => [:details, :report] |
|
50 | map.permission :view_time_entries, :timelog => [:details, :report] | |
50 | end |
|
51 | end | |
51 |
|
52 | |||
52 | map.project_module :news do |map| |
|
53 | map.project_module :news do |map| | |
53 | map.permission :manage_news, {:projects => :add_news, :news => [:edit, :destroy, :destroy_comment]}, :require => :member |
|
54 | map.permission :manage_news, {:projects => :add_news, :news => [:edit, :destroy, :destroy_comment]}, :require => :member | |
54 | map.permission :view_news, {:projects => :list_news, :news => :show}, :public => true |
|
55 | map.permission :view_news, {:projects => :list_news, :news => :show}, :public => true | |
55 | map.permission :comment_news, {:news => :add_comment}, :require => :loggedin |
|
56 | map.permission :comment_news, {:news => :add_comment}, :require => :loggedin | |
56 | end |
|
57 | end | |
57 |
|
58 | |||
58 | map.project_module :documents do |map| |
|
59 | map.project_module :documents do |map| | |
59 | map.permission :manage_documents, {:projects => :add_document, :documents => [:edit, :destroy, :add_attachment, :destroy_attachment]}, :require => :loggedin |
|
60 | map.permission :manage_documents, {:projects => :add_document, :documents => [:edit, :destroy, :add_attachment, :destroy_attachment]}, :require => :loggedin | |
60 | map.permission :view_documents, :projects => :list_documents, :documents => [:show, :download] |
|
61 | map.permission :view_documents, :projects => :list_documents, :documents => [:show, :download] | |
61 | end |
|
62 | end | |
62 |
|
63 | |||
63 | map.project_module :files do |map| |
|
64 | map.project_module :files do |map| | |
64 | map.permission :manage_files, {:projects => :add_file, :versions => :destroy_file}, :require => :loggedin |
|
65 | map.permission :manage_files, {:projects => :add_file, :versions => :destroy_file}, :require => :loggedin | |
65 | map.permission :view_files, :projects => :list_files, :versions => :download |
|
66 | map.permission :view_files, :projects => :list_files, :versions => :download | |
66 | end |
|
67 | end | |
67 |
|
68 | |||
68 | map.project_module :wiki do |map| |
|
69 | map.project_module :wiki do |map| | |
69 | map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member |
|
70 | map.permission :manage_wiki, {:wikis => [:edit, :destroy]}, :require => :member | |
70 | map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member |
|
71 | map.permission :rename_wiki_pages, {:wiki => :rename}, :require => :member | |
71 | map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member |
|
72 | map.permission :delete_wiki_pages, {:wiki => :destroy}, :require => :member | |
72 | map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :special] |
|
73 | map.permission :view_wiki_pages, :wiki => [:index, :history, :diff, :special] | |
73 | map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment] |
|
74 | map.permission :edit_wiki_pages, :wiki => [:edit, :preview, :add_attachment, :destroy_attachment] | |
74 | end |
|
75 | end | |
75 |
|
76 | |||
76 | map.project_module :repository do |map| |
|
77 | map.project_module :repository do |map| | |
77 | map.permission :manage_repository, :repositories => [:edit, :destroy] |
|
78 | map.permission :manage_repository, :repositories => [:edit, :destroy] | |
78 | map.permission :browse_repository, :repositories => [:show, :browse, :entry, :changes, :diff, :stats, :graph] |
|
79 | map.permission :browse_repository, :repositories => [:show, :browse, :entry, :changes, :diff, :stats, :graph] | |
79 | map.permission :view_changesets, :repositories => [:show, :revisions, :revision] |
|
80 | map.permission :view_changesets, :repositories => [:show, :revisions, :revision] | |
80 | end |
|
81 | end | |
81 |
|
82 | |||
82 | map.project_module :boards do |map| |
|
83 | map.project_module :boards do |map| | |
83 | map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member |
|
84 | map.permission :manage_boards, {:boards => [:new, :edit, :destroy]}, :require => :member | |
84 | map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true |
|
85 | map.permission :view_messages, {:boards => [:index, :show], :messages => [:show]}, :public => true | |
85 | map.permission :add_messages, {:messages => [:new, :reply]}, :require => :loggedin |
|
86 | map.permission :add_messages, {:messages => [:new, :reply]}, :require => :loggedin | |
86 | end |
|
87 | end | |
87 | end |
|
88 | end | |
88 |
|
89 | |||
89 | # Project menu configuration |
|
90 | # Project menu configuration | |
90 | Redmine::MenuManager.map :project_menu do |menu| |
|
91 | Redmine::MenuManager.map :project_menu do |menu| | |
91 | menu.push :label_overview, :controller => 'projects', :action => 'show' |
|
92 | menu.push :label_overview, :controller => 'projects', :action => 'show' | |
92 | menu.push :label_activity, :controller => 'projects', :action => 'activity' |
|
93 | menu.push :label_activity, :controller => 'projects', :action => 'activity' | |
93 | menu.push :label_roadmap, :controller => 'projects', :action => 'roadmap' |
|
94 | menu.push :label_roadmap, :controller => 'projects', :action => 'roadmap' | |
94 | menu.push :label_issue_plural, :controller => 'projects', :action => 'list_issues' |
|
95 | menu.push :label_issue_plural, :controller => 'projects', :action => 'list_issues' | |
95 | menu.push :label_news_plural, :controller => 'projects', :action => 'list_news' |
|
96 | menu.push :label_news_plural, :controller => 'projects', :action => 'list_news' | |
96 | menu.push :label_document_plural, :controller => 'projects', :action => 'list_documents' |
|
97 | menu.push :label_document_plural, :controller => 'projects', :action => 'list_documents' | |
97 | menu.push :label_wiki, { :controller => 'wiki', :action => 'index', :page => nil }, :if => Proc.new { |p| p.wiki && !p.wiki.new_record? } |
|
98 | menu.push :label_wiki, { :controller => 'wiki', :action => 'index', :page => nil }, :if => Proc.new { |p| p.wiki && !p.wiki.new_record? } | |
98 | menu.push :label_board_plural, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, :if => Proc.new { |p| p.boards.any? } |
|
99 | menu.push :label_board_plural, { :controller => 'boards', :action => 'index', :id => nil }, :param => :project_id, :if => Proc.new { |p| p.boards.any? } | |
99 | menu.push :label_attachment_plural, :controller => 'projects', :action => 'list_files' |
|
100 | menu.push :label_attachment_plural, :controller => 'projects', :action => 'list_files' | |
100 | menu.push :label_repository, { :controller => 'repositories', :action => 'show' }, :if => Proc.new { |p| p.repository && !p.repository.new_record? } |
|
101 | menu.push :label_repository, { :controller => 'repositories', :action => 'show' }, :if => Proc.new { |p| p.repository && !p.repository.new_record? } | |
101 | menu.push :label_settings, :controller => 'projects', :action => 'settings' |
|
102 | menu.push :label_settings, :controller => 'projects', :action => 'settings' | |
102 | end |
|
103 | end |
@@ -1,448 +1,449 | |||||
1 | body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; } |
|
1 | body { font-family: Verdana, sans-serif; font-size: 12px; color:#484848; margin: 0; padding: 0; min-width: 900px; } | |
2 |
|
2 | |||
3 | h1, h2, h3 { font-family: "Trebuchet MS", Verdana, sans-serif;} |
|
3 | h1, h2, h3 { font-family: "Trebuchet MS", Verdana, sans-serif;} | |
4 | h1 {margin:0; padding:0; font-size: 24px;} |
|
4 | h1 {margin:0; padding:0; font-size: 24px;} | |
5 | h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;} |
|
5 | h2, .wiki h1 {font-size: 20px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;} | |
6 | h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;} |
|
6 | h3, .wiki h2 {font-size: 16px;padding: 2px 10px 1px 0px;margin: 0 0 10px 0; border-bottom: 1px solid #bbbbbb; color: #444;} | |
7 | h4, .wiki h3 {font-size: 11px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;} |
|
7 | h4, .wiki h3 {font-size: 11px;padding: 2px 10px 1px 0px;margin-bottom: 5px; border-bottom: 1px dotted #bbbbbb; color: #444;} | |
8 |
|
8 | |||
9 | /***** Layout *****/ |
|
9 | /***** Layout *****/ | |
10 | #top-menu {background: #22344A;color: #fff;height:1.5em; padding: 2px 6px 0px 6px;} |
|
10 | #top-menu {background: #22344A;color: #fff;height:1.5em; padding: 2px 6px 0px 6px;} | |
11 | #top-menu a {color: #fff; padding-right: 4px;} |
|
11 | #top-menu a {color: #fff; padding-right: 4px;} | |
12 | #account {float:right;} |
|
12 | #account {float:right;} | |
13 |
|
13 | |||
14 | #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 6px 0px 6px;} |
|
14 | #header {height:5.3em;margin:0;background-color:#507AAA;color:#f8f8f8; padding: 4px 6px 0px 6px;} | |
15 | #header a {color:#f8f8f8;} |
|
15 | #header a {color:#f8f8f8;} | |
16 | #quick-search {float:right;} |
|
16 | #quick-search {float:right;} | |
17 |
|
17 | |||
18 | #main-menu {position: absolute; top: 5.5em; left:8px;} |
|
18 | #main-menu {position: absolute; top: 5.5em; left:8px;} | |
19 | #main-menu ul {margin: 0; padding: 0;} |
|
19 | #main-menu ul {margin: 0; padding: 0;} | |
20 | #main-menu li { |
|
20 | #main-menu li { | |
21 | float:left; |
|
21 | float:left; | |
22 | list-style-type:none; |
|
22 | list-style-type:none; | |
23 | margin: 0px 10px 0px 0px; |
|
23 | margin: 0px 10px 0px 0px; | |
24 | padding: 0px 0px 0px 0px; |
|
24 | padding: 0px 0px 0px 0px; | |
25 | white-space:nowrap; |
|
25 | white-space:nowrap; | |
26 | } |
|
26 | } | |
27 | #main-menu li a { |
|
27 | #main-menu li a { | |
28 | display: block; |
|
28 | display: block; | |
29 | color: #fff; |
|
29 | color: #fff; | |
30 | text-decoration: none; |
|
30 | text-decoration: none; | |
31 | margin: 0; |
|
31 | margin: 0; | |
32 | padding: 4px 4px 4px 4px; |
|
32 | padding: 4px 4px 4px 4px; | |
33 | background: #22344A; |
|
33 | background: #22344A; | |
34 | } |
|
34 | } | |
35 | #main-menu li a:hover {background:#759FCF;} |
|
35 | #main-menu li a:hover {background:#759FCF;} | |
36 |
|
36 | |||
37 | #main {background: url(../images/mainbg.png) repeat-x; background-color:#EEEEEE;} |
|
37 | #main {background: url(../images/mainbg.png) repeat-x; background-color:#EEEEEE;} | |
38 |
|
38 | |||
39 | #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;} |
|
39 | #sidebar{ float: right; width: 17%; position: relative; z-index: 9; min-height: 600px; padding: 0; margin: 0;} | |
40 | * html #sidebar{ width: 17%; } |
|
40 | * html #sidebar{ width: 17%; } | |
41 | #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; } |
|
41 | #sidebar h3{ font-size: 14px; margin-top:14px; color: #666; } | |
42 | #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } |
|
42 | #sidebar hr{ width: 100%; margin: 0 auto; height: 1px; background: #ccc; border: 0; } | |
43 | * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } |
|
43 | * html #sidebar hr{ width: 95%; position: relative; left: -6px; color: #ccc; } | |
44 |
|
44 | |||
45 | #content { width: 80%; background: url(../images/contentbg.png) repeat-x; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; position: relative; z-index: 10; height:600px; min-height: 600px;} |
|
45 | #content { width: 80%; background: url(../images/contentbg.png) repeat-x; background-color: #fff; margin: 0px; border-right: 1px solid #ddd; padding: 6px 10px 10px 10px; position: relative; z-index: 10; height:600px; min-height: 600px;} | |
46 | * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} |
|
46 | * html #content{ width: 80%; padding-left: 0; margin-top: 0px; padding: 6px 10px 10px 10px;} | |
47 | html>body #content { |
|
47 | html>body #content { | |
48 | height: auto; |
|
48 | height: auto; | |
49 | min-height: 600px; |
|
49 | min-height: 600px; | |
50 | } |
|
50 | } | |
51 |
|
51 | |||
52 | #main.nosidebar #sidebar{ display: none; } |
|
52 | #main.nosidebar #sidebar{ display: none; } | |
53 | #main.nosidebar #content{ width: auto; border-right: 0; } |
|
53 | #main.nosidebar #content{ width: auto; border-right: 0; } | |
54 |
|
54 | |||
55 | #footer {clear: both; border-top: 1px solid #bbb; font-size: 11px; padding: 5px; text-align:center; background:#fff;} |
|
55 | #footer {clear: both; border-top: 1px solid #bbb; font-size: 11px; padding: 5px; text-align:center; background:#fff;} | |
56 |
|
56 | |||
57 | #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; } |
|
57 | #login-form table {margin-top:5em; padding:1em; margin-left: auto; margin-right: auto; border: 2px solid #FDBF3B; background-color:#FFEBC1; } | |
58 | #login-form table td {padding: 6px;} |
|
58 | #login-form table td {padding: 6px;} | |
59 | #login-form label {font-weight: bold;} |
|
59 | #login-form label {font-weight: bold;} | |
60 |
|
60 | |||
61 | .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } |
|
61 | .clear:after{ content: "."; display: block; height: 0; clear: both; visibility: hidden; } | |
62 |
|
62 | |||
63 | /***** Links *****/ |
|
63 | /***** Links *****/ | |
64 | a, a:link, a:visited{ color: #2A5685; text-decoration: none; } |
|
64 | a, a:link, a:visited{ color: #2A5685; text-decoration: none; } | |
65 | a:hover, a:active{ color: #c61a1a; text-decoration: underline;} |
|
65 | a:hover, a:active{ color: #c61a1a; text-decoration: underline;} | |
66 | a img{ border: 0; } |
|
66 | a img{ border: 0; } | |
67 |
|
67 | |||
68 | /***** Tables *****/ |
|
68 | /***** Tables *****/ | |
69 | table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; } |
|
69 | table.list { border: 1px solid #e4e4e4; border-collapse: collapse; width: 100%; margin-bottom: 4px; } | |
70 | table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; } |
|
70 | table.list th { background-color:#EEEEEE; padding: 4px; white-space:nowrap; } | |
71 | table.list tbody th { text-align: left; padding: 0px; } |
|
71 | table.list tbody th { text-align: left; padding: 0px; } | |
72 | table.list td { overflow: hidden; text-overflow: ellipsis; vertical-align: top;} |
|
72 | table.list td { overflow: hidden; text-overflow: ellipsis; vertical-align: top;} | |
73 | table.list tbody tr:hover { background-color:#ffffdd; } |
|
73 | table.list tbody tr:hover { background-color:#ffffdd; } | |
74 | table td {padding:2px;} |
|
74 | table td {padding:2px;} | |
75 | table p {margin:0;} |
|
75 | table p {margin:0;} | |
76 | .odd {background-color:#f6f7f8;} |
|
76 | .odd {background-color:#f6f7f8;} | |
77 | .even {background-color: #fff;} |
|
77 | .even {background-color: #fff;} | |
78 |
|
78 | |||
79 | .highlight { background-color: #FCFD8D;} |
|
79 | .highlight { background-color: #FCFD8D;} | |
80 |
|
80 | |||
81 | .box{ |
|
81 | .box{ | |
82 | padding:6px; |
|
82 | padding:6px; | |
83 | margin-bottom: 10px; |
|
83 | margin-bottom: 10px; | |
84 | background-color:#f6f6f6; |
|
84 | background-color:#f6f6f6; | |
85 | color:#505050; |
|
85 | color:#505050; | |
86 | line-height:1.5em; |
|
86 | line-height:1.5em; | |
87 | border: 1px solid #e4e4e4; |
|
87 | border: 1px solid #e4e4e4; | |
88 | } |
|
88 | } | |
89 |
|
89 | |||
90 | div.square { |
|
90 | div.square { | |
91 | border: 1px solid #999; |
|
91 | border: 1px solid #999; | |
92 | float: left; |
|
92 | float: left; | |
93 | margin: .3em .4em 0 .4em; |
|
93 | margin: .3em .4em 0 .4em; | |
94 | overflow: hidden; |
|
94 | overflow: hidden; | |
95 | width: .6em; height: .6em; |
|
95 | width: .6em; height: .6em; | |
96 | } |
|
96 | } | |
97 |
|
97 | |||
98 | .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px;font-size:0.9em;} |
|
98 | .contextual {float:right; white-space: nowrap; line-height:1.4em;margin-top:5px;font-size:0.9em;} | |
99 | .splitcontentleft{float:left; width:49%;} |
|
99 | .splitcontentleft{float:left; width:49%;} | |
100 | .splitcontentright{float:right; width:49%;} |
|
100 | .splitcontentright{float:right; width:49%;} | |
101 | form {display: inline;} |
|
101 | form {display: inline;} | |
102 | input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;} |
|
102 | input, select {vertical-align: middle; margin-top: 1px; margin-bottom: 1px;} | |
103 | fieldset {border: 1px solid #e4e4e4; margin:0;} |
|
103 | fieldset {border: 1px solid #e4e4e4; margin:0;} | |
104 | hr { width: 100%; height: 1px; background: #ccc; border: 0;} |
|
104 | hr { width: 100%; height: 1px; background: #ccc; border: 0;} | |
105 | textarea.wiki-edit { width: 99%; } |
|
105 | textarea.wiki-edit { width: 99%; } | |
106 | li p {margin-top: 0;} |
|
106 | li p {margin-top: 0;} | |
107 | div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} |
|
107 | div.issue {background:#ffffdd; padding:6px; margin-bottom:6px;border: 1px solid #d7d7d7;} | |
108 | .autoscroll {overflow-x: auto; padding:1px; width:100%;} |
|
108 | .autoscroll {overflow-x: auto; padding:1px; width:100%;} | |
109 |
|
109 | |||
110 | /***** Tabular forms ******/ |
|
110 | /***** Tabular forms ******/ | |
111 | .tabular p{ |
|
111 | .tabular p{ | |
112 | margin: 0; |
|
112 | margin: 0; | |
113 | padding: 5px 0 8px 0; |
|
113 | padding: 5px 0 8px 0; | |
114 | padding-left: 180px; /*width of left column containing the label elements*/ |
|
114 | padding-left: 180px; /*width of left column containing the label elements*/ | |
115 | height: 1%; |
|
115 | height: 1%; | |
116 | clear:left; |
|
116 | clear:left; | |
117 | } |
|
117 | } | |
118 |
|
118 | |||
119 | .tabular label{ |
|
119 | .tabular label{ | |
120 | font-weight: bold; |
|
120 | font-weight: bold; | |
121 | float: left; |
|
121 | float: left; | |
122 | text-align: right; |
|
122 | text-align: right; | |
123 | margin-left: -180px; /*width of left column*/ |
|
123 | margin-left: -180px; /*width of left column*/ | |
124 | width: 175px; /*width of labels. Should be smaller than left column to create some right |
|
124 | width: 175px; /*width of labels. Should be smaller than left column to create some right | |
125 | margin*/ |
|
125 | margin*/ | |
126 | } |
|
126 | } | |
127 |
|
127 | |||
128 | #settings .tabular p{ padding-left: 300px; } |
|
128 | #settings .tabular p{ padding-left: 300px; } | |
129 | #settings .tabular label{ margin-left: -300px; width: 295px; } |
|
129 | #settings .tabular label{ margin-left: -300px; width: 295px; } | |
130 |
|
130 | |||
131 | .required {color: #bb0000;} |
|
131 | .required {color: #bb0000;} | |
132 | .summary {font-style: italic;} |
|
132 | .summary {font-style: italic;} | |
133 |
|
133 | |||
134 | /***** Flash & error messages ****/ |
|
134 | /***** Flash & error messages ****/ | |
135 | #flash div, #errorExplanation, .nodata { |
|
135 | #flash div, #errorExplanation, .nodata { | |
136 | padding: 4px 4px 4px 30px; |
|
136 | padding: 4px 4px 4px 30px; | |
137 | margin-bottom: 12px; |
|
137 | margin-bottom: 12px; | |
138 | font-size: 1.1em; |
|
138 | font-size: 1.1em; | |
139 | border: 2px solid; |
|
139 | border: 2px solid; | |
140 | } |
|
140 | } | |
141 |
|
141 | |||
142 | #flash div {margin-top: 6px;} |
|
142 | #flash div {margin-top: 6px;} | |
143 |
|
143 | |||
144 | #flash div.error, #errorExplanation { |
|
144 | #flash div.error, #errorExplanation { | |
145 | background: url(../images/false.png) 8px 5px no-repeat; |
|
145 | background: url(../images/false.png) 8px 5px no-repeat; | |
146 | background-color: #ffe3e3; |
|
146 | background-color: #ffe3e3; | |
147 | border-color: #dd0000; |
|
147 | border-color: #dd0000; | |
148 | color: #550000; |
|
148 | color: #550000; | |
149 | } |
|
149 | } | |
150 |
|
150 | |||
151 | #flash div.notice { |
|
151 | #flash div.notice { | |
152 | background: url(../images/true.png) 8px 5px no-repeat; |
|
152 | background: url(../images/true.png) 8px 5px no-repeat; | |
153 | background-color: #dfffdf; |
|
153 | background-color: #dfffdf; | |
154 | border-color: #9fcf9f; |
|
154 | border-color: #9fcf9f; | |
155 | color: #005f00; |
|
155 | color: #005f00; | |
156 | } |
|
156 | } | |
157 |
|
157 | |||
158 | .nodata { |
|
158 | .nodata { | |
159 | text-align: center; |
|
159 | text-align: center; | |
160 | background-color: #FFEBC1; |
|
160 | background-color: #FFEBC1; | |
161 | border-color: #FDBF3B; |
|
161 | border-color: #FDBF3B; | |
162 | color: #A6750C; |
|
162 | color: #A6750C; | |
163 | } |
|
163 | } | |
164 |
|
164 | |||
165 | #errorExplanation ul { font-size: 0.9em;} |
|
165 | #errorExplanation ul { font-size: 0.9em;} | |
166 |
|
166 | |||
167 | /***** Ajax indicator ******/ |
|
167 | /***** Ajax indicator ******/ | |
168 | #ajax-indicator { |
|
168 | #ajax-indicator { | |
169 | position: absolute; /* fixed not supported by IE */ |
|
169 | position: absolute; /* fixed not supported by IE */ | |
170 | background-color:#eee; |
|
170 | background-color:#eee; | |
171 | border: 1px solid #bbb; |
|
171 | border: 1px solid #bbb; | |
172 | top:35%; |
|
172 | top:35%; | |
173 | left:40%; |
|
173 | left:40%; | |
174 | width:20%; |
|
174 | width:20%; | |
175 | font-weight:bold; |
|
175 | font-weight:bold; | |
176 | text-align:center; |
|
176 | text-align:center; | |
177 | padding:0.6em; |
|
177 | padding:0.6em; | |
178 | z-index:100; |
|
178 | z-index:100; | |
179 | filter:alpha(opacity=50); |
|
179 | filter:alpha(opacity=50); | |
180 | -moz-opacity:0.5; |
|
180 | -moz-opacity:0.5; | |
181 | opacity: 0.5; |
|
181 | opacity: 0.5; | |
182 | -khtml-opacity: 0.5; |
|
182 | -khtml-opacity: 0.5; | |
183 | } |
|
183 | } | |
184 |
|
184 | |||
185 | html>body #ajax-indicator { position: fixed; } |
|
185 | html>body #ajax-indicator { position: fixed; } | |
186 |
|
186 | |||
187 | #ajax-indicator span { |
|
187 | #ajax-indicator span { | |
188 | background-position: 0% 40%; |
|
188 | background-position: 0% 40%; | |
189 | background-repeat: no-repeat; |
|
189 | background-repeat: no-repeat; | |
190 | background-image: url(../images/loading.gif); |
|
190 | background-image: url(../images/loading.gif); | |
191 | padding-left: 26px; |
|
191 | padding-left: 26px; | |
192 | vertical-align: bottom; |
|
192 | vertical-align: bottom; | |
193 | } |
|
193 | } | |
194 |
|
194 | |||
195 | /***** Calendar *****/ |
|
195 | /***** Calendar *****/ | |
196 | table.cal {border-collapse: collapse; width: 100%; margin: 8px 0 6px 0;border: 1px solid #d7d7d7;} |
|
196 | table.cal {border-collapse: collapse; width: 100%; margin: 8px 0 6px 0;border: 1px solid #d7d7d7;} | |
197 | table.cal th { background-color:#EEEEEE; padding: 4px; } |
|
197 | table.cal th { background-color:#EEEEEE; padding: 4px; } | |
198 | table.cal td {border: 1px solid #d7d7d7;} |
|
198 | table.cal td {border: 1px solid #d7d7d7;} | |
199 | table.cal td.today {background:#ffffdd;} |
|
199 | table.cal td.today {background:#ffffdd;} | |
200 |
|
200 | |||
201 | /***** Tooltips ******/ |
|
201 | /***** Tooltips ******/ | |
202 | .tooltip{position:relative;z-index:24;} |
|
202 | .tooltip{position:relative;z-index:24;} | |
203 | .tooltip:hover{z-index:25;color:#000;} |
|
203 | .tooltip:hover{z-index:25;color:#000;} | |
204 | .tooltip span.tip{display: none; text-align:left;} |
|
204 | .tooltip span.tip{display: none; text-align:left;} | |
205 |
|
205 | |||
206 | div.tooltip:hover span.tip{ |
|
206 | div.tooltip:hover span.tip{ | |
207 | display:block; |
|
207 | display:block; | |
208 | position:absolute; |
|
208 | position:absolute; | |
209 | top:12px; left:24px; width:270px; |
|
209 | top:12px; left:24px; width:270px; | |
210 | border:1px solid #555; |
|
210 | border:1px solid #555; | |
211 | background-color:#fff; |
|
211 | background-color:#fff; | |
212 | padding: 4px; |
|
212 | padding: 4px; | |
213 | font-size: 0.8em; |
|
213 | font-size: 0.8em; | |
214 | color:#505050; |
|
214 | color:#505050; | |
215 | } |
|
215 | } | |
216 |
|
216 | |||
217 | /***** Progress bar *****/ |
|
217 | /***** Progress bar *****/ | |
218 | .progress { |
|
218 | .progress { | |
219 | border: 1px solid #D7D7D7; |
|
219 | border: 1px solid #D7D7D7; | |
220 | border-collapse: collapse; |
|
220 | border-collapse: collapse; | |
221 | border-spacing: 0pt; |
|
221 | border-spacing: 0pt; | |
222 | empty-cells: show; |
|
222 | empty-cells: show; | |
223 | padding: 3px; |
|
223 | padding: 3px; | |
224 | width: 40em; |
|
224 | width: 40em; | |
225 | text-align: center; |
|
225 | text-align: center; | |
226 | } |
|
226 | } | |
227 |
|
227 | |||
228 | .progress td { height: 1em; } |
|
228 | .progress td { height: 1em; } | |
229 | .progress .closed { background: #BAE0BA none repeat scroll 0%; } |
|
229 | .progress .closed { background: #BAE0BA none repeat scroll 0%; } | |
230 | .progress .open { background: #FFF none repeat scroll 0%; } |
|
230 | .progress .open { background: #FFF none repeat scroll 0%; } | |
231 |
|
231 | |||
232 | /***** Tabs *****/ |
|
232 | /***** Tabs *****/ | |
233 | #content .tabs{height: 2.6em;} |
|
233 | #content .tabs{height: 2.6em;} | |
234 | #content .tabs ul{margin:0;} |
|
234 | #content .tabs ul{margin:0;} | |
235 | #content .tabs ul li{ |
|
235 | #content .tabs ul li{ | |
236 | float:left; |
|
236 | float:left; | |
237 | list-style-type:none; |
|
237 | list-style-type:none; | |
238 | white-space:nowrap; |
|
238 | white-space:nowrap; | |
239 | margin-right:8px; |
|
239 | margin-right:8px; | |
240 | background:#fff; |
|
240 | background:#fff; | |
241 | } |
|
241 | } | |
242 | #content .tabs ul li a{ |
|
242 | #content .tabs ul li a{ | |
243 | display:block; |
|
243 | display:block; | |
244 | font-size: 0.9em; |
|
244 | font-size: 0.9em; | |
245 | text-decoration:none; |
|
245 | text-decoration:none; | |
246 | line-height:1em; |
|
246 | line-height:1em; | |
247 | padding:4px; |
|
247 | padding:4px; | |
248 | border: 1px solid #c0c0c0; |
|
248 | border: 1px solid #c0c0c0; | |
249 | } |
|
249 | } | |
250 |
|
250 | |||
251 | #content .tabs ul li a.selected, #content .tabs ul li a:hover{ |
|
251 | #content .tabs ul li a.selected, #content .tabs ul li a:hover{ | |
252 | background-color: #507AAA; |
|
252 | background-color: #507AAA; | |
253 | border: 1px solid #507AAA; |
|
253 | border: 1px solid #507AAA; | |
254 | color: #fff; |
|
254 | color: #fff; | |
255 | text-decoration:none; |
|
255 | text-decoration:none; | |
256 | } |
|
256 | } | |
257 |
|
257 | |||
258 | /***** Diff *****/ |
|
258 | /***** Diff *****/ | |
259 | .diff_out { background: #fcc; } |
|
259 | .diff_out { background: #fcc; } | |
260 | .diff_in { background: #cfc; } |
|
260 | .diff_in { background: #cfc; } | |
261 |
|
261 | |||
262 | /***** Wiki *****/ |
|
262 | /***** Wiki *****/ | |
263 | div.wiki table { |
|
263 | div.wiki table { | |
264 | border: 1px solid #505050; |
|
264 | border: 1px solid #505050; | |
265 | border-collapse: collapse; |
|
265 | border-collapse: collapse; | |
266 | } |
|
266 | } | |
267 |
|
267 | |||
268 | div.wiki table, div.wiki td, div.wiki th { |
|
268 | div.wiki table, div.wiki td, div.wiki th { | |
269 | border: 1px solid #bbb; |
|
269 | border: 1px solid #bbb; | |
270 | padding: 4px; |
|
270 | padding: 4px; | |
271 | } |
|
271 | } | |
272 |
|
272 | |||
273 | div.wiki a { |
|
273 | div.wiki a { | |
274 | background-position: 0% 60%; |
|
274 | background-position: 0% 60%; | |
275 | background-repeat: no-repeat; |
|
275 | background-repeat: no-repeat; | |
276 | padding-left: 12px; |
|
276 | padding-left: 12px; | |
277 | background-image: url(../images/external.png); |
|
277 | background-image: url(../images/external.png); | |
278 | } |
|
278 | } | |
279 |
|
279 | |||
280 | div.wiki a.wiki-page, div.wiki a.issue, div.wiki a.changeset, div.wiki a.email, div.wiki div.toc a { |
|
280 | div.wiki a.wiki-page, div.wiki a.issue, div.wiki a.changeset, div.wiki a.email, div.wiki div.toc a { | |
281 | padding-left: 0; |
|
281 | padding-left: 0; | |
282 | background-image: none; |
|
282 | background-image: none; | |
283 | } |
|
283 | } | |
284 |
|
284 | |||
285 | div.wiki a.new { |
|
285 | div.wiki a.new { | |
286 | color: #b73535; |
|
286 | color: #b73535; | |
287 | } |
|
287 | } | |
288 |
|
288 | |||
289 | div.wiki pre { |
|
289 | div.wiki pre { | |
290 | margin: 1em 1em 1em 1.6em; |
|
290 | margin: 1em 1em 1em 1.6em; | |
291 | padding: 2px; |
|
291 | padding: 2px; | |
292 | background-color: #fafafa; |
|
292 | background-color: #fafafa; | |
293 | border: 1px solid #dadada; |
|
293 | border: 1px solid #dadada; | |
294 | width:95%; |
|
294 | width:95%; | |
295 | overflow-x: auto; |
|
295 | overflow-x: auto; | |
296 | } |
|
296 | } | |
297 |
|
297 | |||
298 | div.wiki div.toc { |
|
298 | div.wiki div.toc { | |
299 | background-color: #ffffdd; |
|
299 | background-color: #ffffdd; | |
300 | border: 1px solid #e4e4e4; |
|
300 | border: 1px solid #e4e4e4; | |
301 | padding: 4px; |
|
301 | padding: 4px; | |
302 | line-height: 1.2em; |
|
302 | line-height: 1.2em; | |
303 | margin-bottom: 12px; |
|
303 | margin-bottom: 12px; | |
304 | margin-right: 12px; |
|
304 | margin-right: 12px; | |
305 | float: left; |
|
305 | float: left; | |
306 | } |
|
306 | } | |
307 |
|
307 | |||
308 | div.wiki div.toc.right { |
|
308 | div.wiki div.toc.right { | |
309 | float: right; |
|
309 | float: right; | |
310 | margin-left: 12px; |
|
310 | margin-left: 12px; | |
311 | margin-right: 0; |
|
311 | margin-right: 0; | |
312 | } |
|
312 | } | |
313 |
|
313 | |||
314 | div.wiki div.toc a { |
|
314 | div.wiki div.toc a { | |
315 | display: block; |
|
315 | display: block; | |
316 | font-size: 0.9em; |
|
316 | font-size: 0.9em; | |
317 | font-weight: normal; |
|
317 | font-weight: normal; | |
318 | text-decoration: none; |
|
318 | text-decoration: none; | |
319 | color: #606060; |
|
319 | color: #606060; | |
320 | } |
|
320 | } | |
321 | div.wiki div.toc a:hover { color: #c61a1a; text-decoration: underline;} |
|
321 | div.wiki div.toc a:hover { color: #c61a1a; text-decoration: underline;} | |
322 |
|
322 | |||
323 | div.wiki div.toc a.heading2 { margin-left: 6px; } |
|
323 | div.wiki div.toc a.heading2 { margin-left: 6px; } | |
324 | div.wiki div.toc a.heading3 { margin-left: 12px; font-size: 0.8em; } |
|
324 | div.wiki div.toc a.heading3 { margin-left: 12px; font-size: 0.8em; } | |
325 |
|
325 | |||
326 | /***** My page layout *****/ |
|
326 | /***** My page layout *****/ | |
327 | .block-receiver { |
|
327 | .block-receiver { | |
328 | border:1px dashed #c0c0c0; |
|
328 | border:1px dashed #c0c0c0; | |
329 | margin-bottom: 20px; |
|
329 | margin-bottom: 20px; | |
330 | padding: 15px 0 15px 0; |
|
330 | padding: 15px 0 15px 0; | |
331 | } |
|
331 | } | |
332 |
|
332 | |||
333 | .mypage-box { |
|
333 | .mypage-box { | |
334 | margin:0 0 20px 0; |
|
334 | margin:0 0 20px 0; | |
335 | color:#505050; |
|
335 | color:#505050; | |
336 | line-height:1.5em; |
|
336 | line-height:1.5em; | |
337 | } |
|
337 | } | |
338 |
|
338 | |||
339 | .handle { |
|
339 | .handle { | |
340 | cursor: move; |
|
340 | cursor: move; | |
341 | } |
|
341 | } | |
342 |
|
342 | |||
343 | a.close-icon { |
|
343 | a.close-icon { | |
344 | display:block; |
|
344 | display:block; | |
345 | margin-top:3px; |
|
345 | margin-top:3px; | |
346 | overflow:hidden; |
|
346 | overflow:hidden; | |
347 | width:12px; |
|
347 | width:12px; | |
348 | height:12px; |
|
348 | height:12px; | |
349 | background-repeat: no-repeat; |
|
349 | background-repeat: no-repeat; | |
350 | cursor:pointer; |
|
350 | cursor:pointer; | |
351 | background-image:url('../images/close.png'); |
|
351 | background-image:url('../images/close.png'); | |
352 | } |
|
352 | } | |
353 |
|
353 | |||
354 | a.close-icon:hover { |
|
354 | a.close-icon:hover { | |
355 | background-image:url('../images/close_hl.png'); |
|
355 | background-image:url('../images/close_hl.png'); | |
356 | } |
|
356 | } | |
357 |
|
357 | |||
358 | /***** Gantt chart *****/ |
|
358 | /***** Gantt chart *****/ | |
359 | .gantt_hdr { |
|
359 | .gantt_hdr { | |
360 | position:absolute; |
|
360 | position:absolute; | |
361 | top:0; |
|
361 | top:0; | |
362 | height:16px; |
|
362 | height:16px; | |
363 | border-top: 1px solid #c0c0c0; |
|
363 | border-top: 1px solid #c0c0c0; | |
364 | border-bottom: 1px solid #c0c0c0; |
|
364 | border-bottom: 1px solid #c0c0c0; | |
365 | border-right: 1px solid #c0c0c0; |
|
365 | border-right: 1px solid #c0c0c0; | |
366 | text-align: center; |
|
366 | text-align: center; | |
367 | overflow: hidden; |
|
367 | overflow: hidden; | |
368 | } |
|
368 | } | |
369 |
|
369 | |||
370 | .task { |
|
370 | .task { | |
371 | position: absolute; |
|
371 | position: absolute; | |
372 | height:8px; |
|
372 | height:8px; | |
373 | font-size:0.8em; |
|
373 | font-size:0.8em; | |
374 | color:#888; |
|
374 | color:#888; | |
375 | padding:0; |
|
375 | padding:0; | |
376 | margin:0; |
|
376 | margin:0; | |
377 | line-height:0.8em; |
|
377 | line-height:0.8em; | |
378 | } |
|
378 | } | |
379 |
|
379 | |||
380 | .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } |
|
380 | .task_late { background:#f66 url(../images/task_late.png); border: 1px solid #f66; } | |
381 | .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; } |
|
381 | .task_done { background:#66f url(../images/task_done.png); border: 1px solid #66f; } | |
382 | .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } |
|
382 | .task_todo { background:#aaa url(../images/task_todo.png); border: 1px solid #aaa; } | |
383 | .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; } |
|
383 | .milestone { background-image:url(../images/milestone.png); background-repeat: no-repeat; border: 0; } | |
384 |
|
384 | |||
385 | /***** Icons *****/ |
|
385 | /***** Icons *****/ | |
386 | .icon { |
|
386 | .icon { | |
387 | background-position: 0% 40%; |
|
387 | background-position: 0% 40%; | |
388 | background-repeat: no-repeat; |
|
388 | background-repeat: no-repeat; | |
389 | padding-left: 20px; |
|
389 | padding-left: 20px; | |
390 | padding-top: 2px; |
|
390 | padding-top: 2px; | |
391 | padding-bottom: 3px; |
|
391 | padding-bottom: 3px; | |
392 | } |
|
392 | } | |
393 |
|
393 | |||
394 | .icon22 { |
|
394 | .icon22 { | |
395 | background-position: 0% 40%; |
|
395 | background-position: 0% 40%; | |
396 | background-repeat: no-repeat; |
|
396 | background-repeat: no-repeat; | |
397 | padding-left: 26px; |
|
397 | padding-left: 26px; | |
398 | line-height: 22px; |
|
398 | line-height: 22px; | |
399 | vertical-align: middle; |
|
399 | vertical-align: middle; | |
400 | } |
|
400 | } | |
401 |
|
401 | |||
402 | .icon-add { background-image: url(../images/add.png); } |
|
402 | .icon-add { background-image: url(../images/add.png); } | |
403 | .icon-edit { background-image: url(../images/edit.png); } |
|
403 | .icon-edit { background-image: url(../images/edit.png); } | |
404 | .icon-del { background-image: url(../images/delete.png); } |
|
404 | .icon-del { background-image: url(../images/delete.png); } | |
405 | .icon-move { background-image: url(../images/move.png); } |
|
405 | .icon-move { background-image: url(../images/move.png); } | |
406 | .icon-save { background-image: url(../images/save.png); } |
|
406 | .icon-save { background-image: url(../images/save.png); } | |
407 | .icon-cancel { background-image: url(../images/cancel.png); } |
|
407 | .icon-cancel { background-image: url(../images/cancel.png); } | |
408 | .icon-pdf { background-image: url(../images/pdf.png); } |
|
408 | .icon-pdf { background-image: url(../images/pdf.png); } | |
409 | .icon-csv { background-image: url(../images/csv.png); } |
|
409 | .icon-csv { background-image: url(../images/csv.png); } | |
410 | .icon-html { background-image: url(../images/html.png); } |
|
410 | .icon-html { background-image: url(../images/html.png); } | |
411 | .icon-image { background-image: url(../images/image.png); } |
|
411 | .icon-image { background-image: url(../images/image.png); } | |
412 | .icon-txt { background-image: url(../images/txt.png); } |
|
412 | .icon-txt { background-image: url(../images/txt.png); } | |
413 | .icon-file { background-image: url(../images/file.png); } |
|
413 | .icon-file { background-image: url(../images/file.png); } | |
414 | .icon-folder { background-image: url(../images/folder.png); } |
|
414 | .icon-folder { background-image: url(../images/folder.png); } | |
415 | .icon-package { background-image: url(../images/package.png); } |
|
415 | .icon-package { background-image: url(../images/package.png); } | |
416 | .icon-home { background-image: url(../images/home.png); } |
|
416 | .icon-home { background-image: url(../images/home.png); } | |
417 | .icon-user { background-image: url(../images/user.png); } |
|
417 | .icon-user { background-image: url(../images/user.png); } | |
418 | .icon-mypage { background-image: url(../images/user_page.png); } |
|
418 | .icon-mypage { background-image: url(../images/user_page.png); } | |
419 | .icon-admin { background-image: url(../images/admin.png); } |
|
419 | .icon-admin { background-image: url(../images/admin.png); } | |
420 | .icon-projects { background-image: url(../images/projects.png); } |
|
420 | .icon-projects { background-image: url(../images/projects.png); } | |
421 | .icon-logout { background-image: url(../images/logout.png); } |
|
421 | .icon-logout { background-image: url(../images/logout.png); } | |
422 | .icon-help { background-image: url(../images/help.png); } |
|
422 | .icon-help { background-image: url(../images/help.png); } | |
423 | .icon-attachment { background-image: url(../images/attachment.png); } |
|
423 | .icon-attachment { background-image: url(../images/attachment.png); } | |
424 | .icon-index { background-image: url(../images/index.png); } |
|
424 | .icon-index { background-image: url(../images/index.png); } | |
425 | .icon-history { background-image: url(../images/history.png); } |
|
425 | .icon-history { background-image: url(../images/history.png); } | |
426 | .icon-feed { background-image: url(../images/feed.png); } |
|
426 | .icon-feed { background-image: url(../images/feed.png); } | |
427 | .icon-time { background-image: url(../images/time.png); } |
|
427 | .icon-time { background-image: url(../images/time.png); } | |
428 | .icon-stats { background-image: url(../images/stats.png); } |
|
428 | .icon-stats { background-image: url(../images/stats.png); } | |
429 | .icon-warning { background-image: url(../images/warning.png); } |
|
429 | .icon-warning { background-image: url(../images/warning.png); } | |
430 | .icon-fav { background-image: url(../images/fav.png); } |
|
430 | .icon-fav { background-image: url(../images/fav.png); } | |
431 | .icon-fav-off { background-image: url(../images/fav_off.png); } |
|
431 | .icon-fav-off { background-image: url(../images/fav_off.png); } | |
432 | .icon-reload { background-image: url(../images/reload.png); } |
|
432 | .icon-reload { background-image: url(../images/reload.png); } | |
433 | .icon-lock { background-image: url(../images/locked.png); } |
|
433 | .icon-lock { background-image: url(../images/locked.png); } | |
434 | .icon-unlock { background-image: url(../images/unlock.png); } |
|
434 | .icon-unlock { background-image: url(../images/unlock.png); } | |
435 | .icon-note { background-image: url(../images/note.png); } |
|
435 | .icon-note { background-image: url(../images/note.png); } | |
436 |
|
436 | |||
437 | .icon22-projects { background-image: url(../images/22x22/projects.png); } |
|
437 | .icon22-projects { background-image: url(../images/22x22/projects.png); } | |
438 | .icon22-users { background-image: url(../images/22x22/users.png); } |
|
438 | .icon22-users { background-image: url(../images/22x22/users.png); } | |
439 | .icon22-tracker { background-image: url(../images/22x22/tracker.png); } |
|
439 | .icon22-tracker { background-image: url(../images/22x22/tracker.png); } | |
440 | .icon22-role { background-image: url(../images/22x22/role.png); } |
|
440 | .icon22-role { background-image: url(../images/22x22/role.png); } | |
441 | .icon22-workflow { background-image: url(../images/22x22/workflow.png); } |
|
441 | .icon22-workflow { background-image: url(../images/22x22/workflow.png); } | |
442 | .icon22-options { background-image: url(../images/22x22/options.png); } |
|
442 | .icon22-options { background-image: url(../images/22x22/options.png); } | |
443 | .icon22-notifications { background-image: url(../images/22x22/notifications.png); } |
|
443 | .icon22-notifications { background-image: url(../images/22x22/notifications.png); } | |
444 | .icon22-authent { background-image: url(../images/22x22/authent.png); } |
|
444 | .icon22-authent { background-image: url(../images/22x22/authent.png); } | |
445 | .icon22-info { background-image: url(../images/22x22/info.png); } |
|
445 | .icon22-info { background-image: url(../images/22x22/info.png); } | |
446 | .icon22-comment { background-image: url(../images/22x22/comment.png); } |
|
446 | .icon22-comment { background-image: url(../images/22x22/comment.png); } | |
447 | .icon22-package { background-image: url(../images/22x22/package.png); } |
|
447 | .icon22-package { background-image: url(../images/22x22/package.png); } | |
448 | .icon22-settings { background-image: url(../images/22x22/settings.png); } |
|
448 | .icon22-settings { background-image: url(../images/22x22/settings.png); } | |
|
449 | .icon22-plugin { background-image: url(../images/22x22/plugin.png); } |
@@ -1,134 +1,134 | |||||
1 | # Copyright (c) 2005-2006 David Barri |
|
1 | # Copyright (c) 2005-2006 David Barri | |
2 |
|
2 | |||
3 | require 'iconv' |
|
3 | require 'iconv' | |
4 | require 'gloc-version' |
|
4 | require 'gloc-version' | |
5 |
|
5 | |||
6 | module GLoc |
|
6 | module GLoc | |
7 | class GLocError < StandardError #:nodoc: |
|
7 | class GLocError < StandardError #:nodoc: | |
8 | end |
|
8 | end | |
9 | class InvalidArgumentsError < GLocError #:nodoc: |
|
9 | class InvalidArgumentsError < GLocError #:nodoc: | |
10 | end |
|
10 | end | |
11 | class InvalidKeyError < GLocError #:nodoc: |
|
11 | class InvalidKeyError < GLocError #:nodoc: | |
12 | end |
|
12 | end | |
13 | class RuleNotFoundError < GLocError #:nodoc: |
|
13 | class RuleNotFoundError < GLocError #:nodoc: | |
14 | end |
|
14 | end | |
15 | class StringNotFoundError < GLocError #:nodoc: |
|
15 | class StringNotFoundError < GLocError #:nodoc: | |
16 | end |
|
16 | end | |
17 |
|
17 | |||
18 | class << self |
|
18 | class << self | |
19 | private |
|
19 | private | |
20 |
|
20 | |||
21 | def _add_localized_data(lang, symbol_hash, override, target) #:nodoc: |
|
21 | def _add_localized_data(lang, symbol_hash, override, target) #:nodoc: | |
22 | lang= lang.to_sym |
|
22 | lang= lang.to_sym | |
23 | if override |
|
23 | if override | |
24 | target[lang] ||= {} |
|
24 | target[lang] ||= {} | |
25 | target[lang].merge!(symbol_hash) |
|
25 | target[lang].merge!(symbol_hash) | |
26 | else |
|
26 | else | |
27 | symbol_hash.merge!(target[lang]) if target[lang] |
|
27 | symbol_hash.merge!(target[lang]) if target[lang] | |
28 | target[lang]= symbol_hash |
|
28 | target[lang]= symbol_hash | |
29 | end |
|
29 | end | |
30 | end |
|
30 | end | |
31 |
|
31 | |||
32 | def _add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) #:nodoc: |
|
32 | def _add_localized_strings(lang, symbol_hash, override=true, strings_charset=nil) #:nodoc: | |
33 | _charset_required |
|
33 | _charset_required | |
34 |
|
34 | |||
35 | # Convert all incoming strings to the gloc charset |
|
35 | # Convert all incoming strings to the gloc charset | |
36 | if strings_charset |
|
36 | if strings_charset | |
37 | Iconv.open(get_charset(lang), strings_charset) do |i| |
|
37 | Iconv.open(get_charset(lang), strings_charset) do |i| | |
38 | symbol_hash.each_pair {|k,v| symbol_hash[k]= i.iconv(v)} |
|
38 | symbol_hash.each_pair {|k,v| symbol_hash[k]= i.iconv(v)} | |
39 | end |
|
39 | end | |
40 | end |
|
40 | end | |
41 |
|
41 | |||
42 | # Convert rules |
|
42 | # Convert rules | |
43 | rules= {} |
|
43 | rules= {} | |
44 | old_kcode= $KCODE |
|
44 | old_kcode= $KCODE | |
45 | begin |
|
45 | begin | |
46 | $KCODE= 'u' |
|
46 | $KCODE= 'u' | |
47 | Iconv.open(UTF_8, get_charset(lang)) do |i| |
|
47 | Iconv.open(UTF_8, get_charset(lang)) do |i| | |
48 | symbol_hash.each {|k,v| |
|
48 | symbol_hash.each {|k,v| | |
49 | if /^_gloc_rule_(.+)$/ =~ k.to_s |
|
49 | if /^_gloc_rule_(.+)$/ =~ k.to_s | |
50 | v= i.iconv(v) if v |
|
50 | v= i.iconv(v) if v | |
51 | v= '""' if v.nil? |
|
51 | v= '""' if v.nil? | |
52 | rules[$1.to_sym]= eval "Proc.new do #{v} end" |
|
52 | rules[$1.to_sym]= eval "Proc.new do #{v} end" | |
53 | end |
|
53 | end | |
54 | } |
|
54 | } | |
55 | end |
|
55 | end | |
56 | ensure |
|
56 | ensure | |
57 | $KCODE= old_kcode |
|
57 | $KCODE= old_kcode | |
58 | end |
|
58 | end | |
59 | rules.keys.each {|k| symbol_hash.delete "_gloc_rule_#{k}".to_sym} |
|
59 | rules.keys.each {|k| symbol_hash.delete "_gloc_rule_#{k}".to_sym} | |
60 |
|
60 | |||
61 | # Add new localized data |
|
61 | # Add new localized data | |
62 | LOWERCASE_LANGUAGES[lang.to_s.downcase]= lang |
|
62 | LOWERCASE_LANGUAGES[lang.to_s.downcase]= lang | |
63 | _add_localized_data(lang, symbol_hash, override, LOCALIZED_STRINGS) |
|
63 | _add_localized_data(lang, symbol_hash, override, LOCALIZED_STRINGS) | |
64 | _add_localized_data(lang, rules, override, RULES) |
|
64 | _add_localized_data(lang, rules, override, RULES) | |
65 | end |
|
65 | end | |
66 |
|
66 | |||
67 | def _charset_required #:nodoc: |
|
67 | def _charset_required #:nodoc: | |
68 | set_charset UTF_8 unless CONFIG[:internal_charset] |
|
68 | set_charset UTF_8 unless CONFIG[:internal_charset] | |
69 | end |
|
69 | end | |
70 |
|
70 | |||
71 | def _get_internal_state_vars |
|
71 | def _get_internal_state_vars | |
72 | [ CONFIG, LOCALIZED_STRINGS, RULES, LOWERCASE_LANGUAGES ] |
|
72 | [ CONFIG, LOCALIZED_STRINGS, RULES, LOWERCASE_LANGUAGES ] | |
73 | end |
|
73 | end | |
74 |
|
74 | |||
75 | def _get_lang_file_list(dir) #:nodoc: |
|
75 | def _get_lang_file_list(dir) #:nodoc: | |
76 | dir= File.join(RAILS_ROOT,'lang') if dir.nil? |
|
76 | dir= File.join(RAILS_ROOT,'{.,vendor/plugins/*}','lang') if dir.nil? | |
77 | Dir[File.join(dir,'*.{yaml,yml}')] |
|
77 | Dir[File.join(dir,'*.{yaml,yml}')] | |
78 | end |
|
78 | end | |
79 |
|
79 | |||
80 | def _l(symbol, language, *arguments) #:nodoc: |
|
80 | def _l(symbol, language, *arguments) #:nodoc: | |
81 | symbol= symbol.to_sym if symbol.is_a?(String) |
|
81 | symbol= symbol.to_sym if symbol.is_a?(String) | |
82 | raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol) |
|
82 | raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol) | |
83 |
|
83 | |||
84 | translation= LOCALIZED_STRINGS[language][symbol] rescue nil |
|
84 | translation= LOCALIZED_STRINGS[language][symbol] rescue nil | |
85 | if translation.nil? |
|
85 | if translation.nil? | |
86 | raise StringNotFoundError.new("There is no key called '#{symbol}' in the #{language} strings.") if CONFIG[:raise_string_not_found_errors] |
|
86 | raise StringNotFoundError.new("There is no key called '#{symbol}' in the #{language} strings.") if CONFIG[:raise_string_not_found_errors] | |
87 | translation= symbol.to_s |
|
87 | translation= symbol.to_s | |
88 | end |
|
88 | end | |
89 |
|
89 | |||
90 | begin |
|
90 | begin | |
91 | return translation % arguments |
|
91 | return translation % arguments | |
92 | rescue => e |
|
92 | rescue => e | |
93 | raise InvalidArgumentsError.new("Translation value #{translation.inspect} with arguments #{arguments.inspect} caused error '#{e.message}'") |
|
93 | raise InvalidArgumentsError.new("Translation value #{translation.inspect} with arguments #{arguments.inspect} caused error '#{e.message}'") | |
94 | end |
|
94 | end | |
95 | end |
|
95 | end | |
96 |
|
96 | |||
97 | def _l_has_string?(symbol,lang) #:nodoc: |
|
97 | def _l_has_string?(symbol,lang) #:nodoc: | |
98 | symbol= symbol.to_sym if symbol.is_a?(String) |
|
98 | symbol= symbol.to_sym if symbol.is_a?(String) | |
99 | LOCALIZED_STRINGS[lang].has_key?(symbol.to_sym) rescue false |
|
99 | LOCALIZED_STRINGS[lang].has_key?(symbol.to_sym) rescue false | |
100 | end |
|
100 | end | |
101 |
|
101 | |||
102 | def _l_rule(symbol,lang) #:nodoc: |
|
102 | def _l_rule(symbol,lang) #:nodoc: | |
103 | symbol= symbol.to_sym if symbol.is_a?(String) |
|
103 | symbol= symbol.to_sym if symbol.is_a?(String) | |
104 | raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol) |
|
104 | raise InvalidKeyError.new("Symbol or String expected as key.") unless symbol.kind_of?(Symbol) | |
105 |
|
105 | |||
106 | r= RULES[lang][symbol] rescue nil |
|
106 | r= RULES[lang][symbol] rescue nil | |
107 | raise RuleNotFoundError.new("There is no rule called '#{symbol}' in the #{lang} rules.") if r.nil? |
|
107 | raise RuleNotFoundError.new("There is no rule called '#{symbol}' in the #{lang} rules.") if r.nil? | |
108 | r |
|
108 | r | |
109 | end |
|
109 | end | |
110 |
|
110 | |||
111 | def _verbose_msg(type=nil) |
|
111 | def _verbose_msg(type=nil) | |
112 | return unless CONFIG[:verbose] |
|
112 | return unless CONFIG[:verbose] | |
113 | x= case type |
|
113 | x= case type | |
114 | when :stats |
|
114 | when :stats | |
115 | x= valid_languages.map{|l| ":#{l}(#{LOCALIZED_STRINGS[l].size}/#{RULES[l].size})"}.sort.join(', ') |
|
115 | x= valid_languages.map{|l| ":#{l}(#{LOCALIZED_STRINGS[l].size}/#{RULES[l].size})"}.sort.join(', ') | |
116 | "Current stats -- #{x}" |
|
116 | "Current stats -- #{x}" | |
117 | else |
|
117 | else | |
118 | yield |
|
118 | yield | |
119 | end |
|
119 | end | |
120 | puts "[GLoc] #{x}" |
|
120 | puts "[GLoc] #{x}" | |
121 | end |
|
121 | end | |
122 |
|
122 | |||
123 | public :_l, :_l_has_string?, :_l_rule |
|
123 | public :_l, :_l_has_string?, :_l_rule | |
124 | end |
|
124 | end | |
125 |
|
125 | |||
126 | private |
|
126 | private | |
127 |
|
127 | |||
128 | unless const_defined?(:LOCALIZED_STRINGS) |
|
128 | unless const_defined?(:LOCALIZED_STRINGS) | |
129 | LOCALIZED_STRINGS= {} |
|
129 | LOCALIZED_STRINGS= {} | |
130 | RULES= {} |
|
130 | RULES= {} | |
131 | LOWERCASE_LANGUAGES= {} |
|
131 | LOWERCASE_LANGUAGES= {} | |
132 | end |
|
132 | end | |
133 |
|
133 | |||
134 | end |
|
134 | end |
General Comments 0
You need to be logged in to leave comments.
Login now