##// END OF EJS Templates
Moves a method to the appropriate helper....
Jean-Philippe Lang -
r4167:a6f891d1b184
parent child
Show More
@@ -1,24 +1,51
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 module GanttHelper
18 module GanttHelper
19
20 def gantt_zoom_link(gantt, in_or_out)
21 img_attributes = {:style => 'height:1.4em; width:1.4em; margin-left: 3px;'} # em for accessibility
22
23 case in_or_out
24 when :in
25 if gantt.zoom < 4
26 link_to_remote(l(:text_zoom_in) + image_tag('zoom_in.png', img_attributes.merge(:alt => l(:text_zoom_in))),
27 {:url => gantt.params.merge(:zoom => (gantt.zoom+1)), :method => :get, :update => 'content'},
28 {:href => url_for(gantt.params.merge(:zoom => (gantt.zoom+1)))})
29 else
30 l(:text_zoom_in) +
31 image_tag('zoom_in_g.png', img_attributes.merge(:alt => l(:text_zoom_in)))
32 end
33
34 when :out
35 if gantt.zoom > 1
36 link_to_remote(l(:text_zoom_out) + image_tag('zoom_out.png', img_attributes.merge(:alt => l(:text_zoom_out))),
37 {:url => gantt.params.merge(:zoom => (gantt.zoom-1)), :method => :get, :update => 'content'},
38 {:href => url_for(gantt.params.merge(:zoom => (gantt.zoom-1)))})
39 else
40 l(:text_zoom_out) +
41 image_tag('zoom_out_g.png', img_attributes.merge(:alt => l(:text_zoom_out)))
42 end
43 end
44 end
45
19 def number_of_issues_on_versions(gantt)
46 def number_of_issues_on_versions(gantt)
20 versions = gantt.events.collect {|event| (event.is_a? Version) ? event : nil}.compact
47 versions = gantt.events.collect {|event| (event.is_a? Version) ? event : nil}.compact
21
48
22 versions.sum {|v| v.fixed_issues.for_gantt.with_query(@query).count}
49 versions.sum {|v| v.fixed_issues.for_gantt.with_query(@query).count}
23 end
50 end
24 end
51 end
@@ -1,275 +1,249
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 module IssuesHelper
18 module IssuesHelper
19 include ApplicationHelper
19 include ApplicationHelper
20
20
21 def issue_list(issues, &block)
21 def issue_list(issues, &block)
22 ancestors = []
22 ancestors = []
23 issues.each do |issue|
23 issues.each do |issue|
24 while (ancestors.any? && !issue.is_descendant_of?(ancestors.last))
24 while (ancestors.any? && !issue.is_descendant_of?(ancestors.last))
25 ancestors.pop
25 ancestors.pop
26 end
26 end
27 yield issue, ancestors.size
27 yield issue, ancestors.size
28 ancestors << issue unless issue.leaf?
28 ancestors << issue unless issue.leaf?
29 end
29 end
30 end
30 end
31
31
32 # Renders a HTML/CSS tooltip
32 # Renders a HTML/CSS tooltip
33 #
33 #
34 # To use, a trigger div is needed. This is a div with the class of "tooltip"
34 # To use, a trigger div is needed. This is a div with the class of "tooltip"
35 # that contains this method wrapped in a span with the class of "tip"
35 # that contains this method wrapped in a span with the class of "tip"
36 #
36 #
37 # <div class="tooltip"><%= link_to_issue(issue) %>
37 # <div class="tooltip"><%= link_to_issue(issue) %>
38 # <span class="tip"><%= render_issue_tooltip(issue) %></span>
38 # <span class="tip"><%= render_issue_tooltip(issue) %></span>
39 # </div>
39 # </div>
40 #
40 #
41 def render_issue_tooltip(issue)
41 def render_issue_tooltip(issue)
42 @cached_label_status ||= l(:field_status)
42 @cached_label_status ||= l(:field_status)
43 @cached_label_start_date ||= l(:field_start_date)
43 @cached_label_start_date ||= l(:field_start_date)
44 @cached_label_due_date ||= l(:field_due_date)
44 @cached_label_due_date ||= l(:field_due_date)
45 @cached_label_assigned_to ||= l(:field_assigned_to)
45 @cached_label_assigned_to ||= l(:field_assigned_to)
46 @cached_label_priority ||= l(:field_priority)
46 @cached_label_priority ||= l(:field_priority)
47 @cached_label_project ||= l(:field_project)
47 @cached_label_project ||= l(:field_project)
48
48
49 link_to_issue(issue) + "<br /><br />" +
49 link_to_issue(issue) + "<br /><br />" +
50 "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
50 "<strong>#{@cached_label_project}</strong>: #{link_to_project(issue.project)}<br />" +
51 "<strong>#{@cached_label_status}</strong>: #{issue.status.name}<br />" +
51 "<strong>#{@cached_label_status}</strong>: #{issue.status.name}<br />" +
52 "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
52 "<strong>#{@cached_label_start_date}</strong>: #{format_date(issue.start_date)}<br />" +
53 "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
53 "<strong>#{@cached_label_due_date}</strong>: #{format_date(issue.due_date)}<br />" +
54 "<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
54 "<strong>#{@cached_label_assigned_to}</strong>: #{issue.assigned_to}<br />" +
55 "<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
55 "<strong>#{@cached_label_priority}</strong>: #{issue.priority.name}"
56 end
56 end
57
57
58 def render_issue_subject_with_tree(issue)
58 def render_issue_subject_with_tree(issue)
59 s = ''
59 s = ''
60 issue.ancestors.each do |ancestor|
60 issue.ancestors.each do |ancestor|
61 s << '<div>' + content_tag('p', link_to_issue(ancestor))
61 s << '<div>' + content_tag('p', link_to_issue(ancestor))
62 end
62 end
63 s << '<div>' + content_tag('h3', h(issue.subject))
63 s << '<div>' + content_tag('h3', h(issue.subject))
64 s << '</div>' * (issue.ancestors.size + 1)
64 s << '</div>' * (issue.ancestors.size + 1)
65 s
65 s
66 end
66 end
67
67
68 def render_descendants_tree(issue)
68 def render_descendants_tree(issue)
69 s = '<form><table class="list issues">'
69 s = '<form><table class="list issues">'
70 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
70 issue_list(issue.descendants.sort_by(&:lft)) do |child, level|
71 s << content_tag('tr',
71 s << content_tag('tr',
72 content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
72 content_tag('td', check_box_tag("ids[]", child.id, false, :id => nil), :class => 'checkbox') +
73 content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
73 content_tag('td', link_to_issue(child, :truncate => 60), :class => 'subject') +
74 content_tag('td', h(child.status)) +
74 content_tag('td', h(child.status)) +
75 content_tag('td', link_to_user(child.assigned_to)) +
75 content_tag('td', link_to_user(child.assigned_to)) +
76 content_tag('td', progress_bar(child.done_ratio, :width => '80px')),
76 content_tag('td', progress_bar(child.done_ratio, :width => '80px')),
77 :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
77 :class => "issue issue-#{child.id} hascontextmenu #{level > 0 ? "idnt idnt-#{level}" : nil}")
78 end
78 end
79 s << '</form></table>'
79 s << '</form></table>'
80 s
80 s
81 end
81 end
82
82
83 def render_custom_fields_rows(issue)
83 def render_custom_fields_rows(issue)
84 return if issue.custom_field_values.empty?
84 return if issue.custom_field_values.empty?
85 ordered_values = []
85 ordered_values = []
86 half = (issue.custom_field_values.size / 2.0).ceil
86 half = (issue.custom_field_values.size / 2.0).ceil
87 half.times do |i|
87 half.times do |i|
88 ordered_values << issue.custom_field_values[i]
88 ordered_values << issue.custom_field_values[i]
89 ordered_values << issue.custom_field_values[i + half]
89 ordered_values << issue.custom_field_values[i + half]
90 end
90 end
91 s = "<tr>\n"
91 s = "<tr>\n"
92 n = 0
92 n = 0
93 ordered_values.compact.each do |value|
93 ordered_values.compact.each do |value|
94 s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0
94 s << "</tr>\n<tr>\n" if n > 0 && (n % 2) == 0
95 s << "\t<th>#{ h(value.custom_field.name) }:</th><td>#{ simple_format_without_paragraph(h(show_value(value))) }</td>\n"
95 s << "\t<th>#{ h(value.custom_field.name) }:</th><td>#{ simple_format_without_paragraph(h(show_value(value))) }</td>\n"
96 n += 1
96 n += 1
97 end
97 end
98 s << "</tr>\n"
98 s << "</tr>\n"
99 s
99 s
100 end
100 end
101
101
102 def sidebar_queries
102 def sidebar_queries
103 unless @sidebar_queries
103 unless @sidebar_queries
104 # User can see public queries and his own queries
104 # User can see public queries and his own queries
105 visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
105 visible = ARCondition.new(["is_public = ? OR user_id = ?", true, (User.current.logged? ? User.current.id : 0)])
106 # Project specific queries and global queries
106 # Project specific queries and global queries
107 visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
107 visible << (@project.nil? ? ["project_id IS NULL"] : ["project_id IS NULL OR project_id = ?", @project.id])
108 @sidebar_queries = Query.find(:all,
108 @sidebar_queries = Query.find(:all,
109 :select => 'id, name',
109 :select => 'id, name',
110 :order => "name ASC",
110 :order => "name ASC",
111 :conditions => visible.conditions)
111 :conditions => visible.conditions)
112 end
112 end
113 @sidebar_queries
113 @sidebar_queries
114 end
114 end
115
115
116 def show_detail(detail, no_html=false)
116 def show_detail(detail, no_html=false)
117 case detail.property
117 case detail.property
118 when 'attr'
118 when 'attr'
119 field = detail.prop_key.to_s.gsub(/\_id$/, "")
119 field = detail.prop_key.to_s.gsub(/\_id$/, "")
120 label = l(("field_" + field).to_sym)
120 label = l(("field_" + field).to_sym)
121 case
121 case
122 when ['due_date', 'start_date'].include?(detail.prop_key)
122 when ['due_date', 'start_date'].include?(detail.prop_key)
123 value = format_date(detail.value.to_date) if detail.value
123 value = format_date(detail.value.to_date) if detail.value
124 old_value = format_date(detail.old_value.to_date) if detail.old_value
124 old_value = format_date(detail.old_value.to_date) if detail.old_value
125
125
126 when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key)
126 when ['project_id', 'status_id', 'tracker_id', 'assigned_to_id', 'priority_id', 'category_id', 'fixed_version_id'].include?(detail.prop_key)
127 value = find_name_by_reflection(field, detail.value)
127 value = find_name_by_reflection(field, detail.value)
128 old_value = find_name_by_reflection(field, detail.old_value)
128 old_value = find_name_by_reflection(field, detail.old_value)
129
129
130 when detail.prop_key == 'estimated_hours'
130 when detail.prop_key == 'estimated_hours'
131 value = "%0.02f" % detail.value.to_f unless detail.value.blank?
131 value = "%0.02f" % detail.value.to_f unless detail.value.blank?
132 old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank?
132 old_value = "%0.02f" % detail.old_value.to_f unless detail.old_value.blank?
133
133
134 when detail.prop_key == 'parent_id'
134 when detail.prop_key == 'parent_id'
135 label = l(:field_parent_issue)
135 label = l(:field_parent_issue)
136 value = "##{detail.value}" unless detail.value.blank?
136 value = "##{detail.value}" unless detail.value.blank?
137 old_value = "##{detail.old_value}" unless detail.old_value.blank?
137 old_value = "##{detail.old_value}" unless detail.old_value.blank?
138 end
138 end
139 when 'cf'
139 when 'cf'
140 custom_field = CustomField.find_by_id(detail.prop_key)
140 custom_field = CustomField.find_by_id(detail.prop_key)
141 if custom_field
141 if custom_field
142 label = custom_field.name
142 label = custom_field.name
143 value = format_value(detail.value, custom_field.field_format) if detail.value
143 value = format_value(detail.value, custom_field.field_format) if detail.value
144 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
144 old_value = format_value(detail.old_value, custom_field.field_format) if detail.old_value
145 end
145 end
146 when 'attachment'
146 when 'attachment'
147 label = l(:label_attachment)
147 label = l(:label_attachment)
148 end
148 end
149 call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value })
149 call_hook(:helper_issues_show_detail_after_setting, {:detail => detail, :label => label, :value => value, :old_value => old_value })
150
150
151 label ||= detail.prop_key
151 label ||= detail.prop_key
152 value ||= detail.value
152 value ||= detail.value
153 old_value ||= detail.old_value
153 old_value ||= detail.old_value
154
154
155 unless no_html
155 unless no_html
156 label = content_tag('strong', label)
156 label = content_tag('strong', label)
157 old_value = content_tag("i", h(old_value)) if detail.old_value
157 old_value = content_tag("i", h(old_value)) if detail.old_value
158 old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
158 old_value = content_tag("strike", old_value) if detail.old_value and (!detail.value or detail.value.empty?)
159 if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
159 if detail.property == 'attachment' && !value.blank? && a = Attachment.find_by_id(detail.prop_key)
160 # Link to the attachment if it has not been removed
160 # Link to the attachment if it has not been removed
161 value = link_to_attachment(a)
161 value = link_to_attachment(a)
162 else
162 else
163 value = content_tag("i", h(value)) if value
163 value = content_tag("i", h(value)) if value
164 end
164 end
165 end
165 end
166
166
167 if !detail.value.blank?
167 if !detail.value.blank?
168 case detail.property
168 case detail.property
169 when 'attr', 'cf'
169 when 'attr', 'cf'
170 if !detail.old_value.blank?
170 if !detail.old_value.blank?
171 l(:text_journal_changed, :label => label, :old => old_value, :new => value)
171 l(:text_journal_changed, :label => label, :old => old_value, :new => value)
172 else
172 else
173 l(:text_journal_set_to, :label => label, :value => value)
173 l(:text_journal_set_to, :label => label, :value => value)
174 end
174 end
175 when 'attachment'
175 when 'attachment'
176 l(:text_journal_added, :label => label, :value => value)
176 l(:text_journal_added, :label => label, :value => value)
177 end
177 end
178 else
178 else
179 l(:text_journal_deleted, :label => label, :old => old_value)
179 l(:text_journal_deleted, :label => label, :old => old_value)
180 end
180 end
181 end
181 end
182
182
183 # Find the name of an associated record stored in the field attribute
183 # Find the name of an associated record stored in the field attribute
184 def find_name_by_reflection(field, id)
184 def find_name_by_reflection(field, id)
185 association = Issue.reflect_on_association(field.to_sym)
185 association = Issue.reflect_on_association(field.to_sym)
186 if association
186 if association
187 record = association.class_name.constantize.find_by_id(id)
187 record = association.class_name.constantize.find_by_id(id)
188 return record.name if record
188 return record.name if record
189 end
189 end
190 end
190 end
191
191
192 def issues_to_csv(issues, project = nil)
192 def issues_to_csv(issues, project = nil)
193 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
193 ic = Iconv.new(l(:general_csv_encoding), 'UTF-8')
194 decimal_separator = l(:general_csv_decimal_separator)
194 decimal_separator = l(:general_csv_decimal_separator)
195 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
195 export = FCSV.generate(:col_sep => l(:general_csv_separator)) do |csv|
196 # csv header fields
196 # csv header fields
197 headers = [ "#",
197 headers = [ "#",
198 l(:field_status),
198 l(:field_status),
199 l(:field_project),
199 l(:field_project),
200 l(:field_tracker),
200 l(:field_tracker),
201 l(:field_priority),
201 l(:field_priority),
202 l(:field_subject),
202 l(:field_subject),
203 l(:field_assigned_to),
203 l(:field_assigned_to),
204 l(:field_category),
204 l(:field_category),
205 l(:field_fixed_version),
205 l(:field_fixed_version),
206 l(:field_author),
206 l(:field_author),
207 l(:field_start_date),
207 l(:field_start_date),
208 l(:field_due_date),
208 l(:field_due_date),
209 l(:field_done_ratio),
209 l(:field_done_ratio),
210 l(:field_estimated_hours),
210 l(:field_estimated_hours),
211 l(:field_parent_issue),
211 l(:field_parent_issue),
212 l(:field_created_on),
212 l(:field_created_on),
213 l(:field_updated_on)
213 l(:field_updated_on)
214 ]
214 ]
215 # Export project custom fields if project is given
215 # Export project custom fields if project is given
216 # otherwise export custom fields marked as "For all projects"
216 # otherwise export custom fields marked as "For all projects"
217 custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
217 custom_fields = project.nil? ? IssueCustomField.for_all : project.all_issue_custom_fields
218 custom_fields.each {|f| headers << f.name}
218 custom_fields.each {|f| headers << f.name}
219 # Description in the last column
219 # Description in the last column
220 headers << l(:field_description)
220 headers << l(:field_description)
221 csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
221 csv << headers.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
222 # csv lines
222 # csv lines
223 issues.each do |issue|
223 issues.each do |issue|
224 fields = [issue.id,
224 fields = [issue.id,
225 issue.status.name,
225 issue.status.name,
226 issue.project.name,
226 issue.project.name,
227 issue.tracker.name,
227 issue.tracker.name,
228 issue.priority.name,
228 issue.priority.name,
229 issue.subject,
229 issue.subject,
230 issue.assigned_to,
230 issue.assigned_to,
231 issue.category,
231 issue.category,
232 issue.fixed_version,
232 issue.fixed_version,
233 issue.author.name,
233 issue.author.name,
234 format_date(issue.start_date),
234 format_date(issue.start_date),
235 format_date(issue.due_date),
235 format_date(issue.due_date),
236 issue.done_ratio,
236 issue.done_ratio,
237 issue.estimated_hours.to_s.gsub('.', decimal_separator),
237 issue.estimated_hours.to_s.gsub('.', decimal_separator),
238 issue.parent_id,
238 issue.parent_id,
239 format_time(issue.created_on),
239 format_time(issue.created_on),
240 format_time(issue.updated_on)
240 format_time(issue.updated_on)
241 ]
241 ]
242 custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
242 custom_fields.each {|f| fields << show_value(issue.custom_value_for(f)) }
243 fields << issue.description
243 fields << issue.description
244 csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
244 csv << fields.collect {|c| begin; ic.iconv(c.to_s); rescue; c.to_s; end }
245 end
245 end
246 end
246 end
247 export
247 export
248 end
248 end
249
250 def gantt_zoom_link(gantt, in_or_out)
251 img_attributes = {:style => 'height:1.4em; width:1.4em; margin-left: 3px;'} # em for accessibility
252
253 case in_or_out
254 when :in
255 if gantt.zoom < 4
256 link_to_remote(l(:text_zoom_in) + image_tag('zoom_in.png', img_attributes.merge(:alt => l(:text_zoom_in))),
257 {:url => gantt.params.merge(:zoom => (gantt.zoom+1)), :method => :get, :update => 'content'},
258 {:href => url_for(gantt.params.merge(:zoom => (gantt.zoom+1)))})
259 else
260 l(:text_zoom_in) +
261 image_tag('zoom_in_g.png', img_attributes.merge(:alt => l(:text_zoom_in)))
262 end
263
264 when :out
265 if gantt.zoom > 1
266 link_to_remote(l(:text_zoom_out) + image_tag('zoom_out.png', img_attributes.merge(:alt => l(:text_zoom_out))),
267 {:url => gantt.params.merge(:zoom => (gantt.zoom-1)), :method => :get, :update => 'content'},
268 {:href => url_for(gantt.params.merge(:zoom => (gantt.zoom-1)))})
269 else
270 l(:text_zoom_out) +
271 image_tag('zoom_out_g.png', img_attributes.merge(:alt => l(:text_zoom_out)))
272 end
273 end
274 end
275 end
249 end
General Comments 0
You need to be logged in to leave comments. Login now