merged cont.
[opensuse:yast-rest-service.git] / webservice / app / helpers / view_helpers / html_helper.rb
1 #--
2 # Webyast Webclient framework
3 #
4 # Copyright (C) 2009, 2010 Novell, Inc. 
5 #   This library is free software; you can redistribute it and/or modify
6 # it only under the terms of version 2.1 of the GNU Lesser General Public
7 # License as published by the Free Software Foundation. 
8 #
9 #   This library is distributed in the hope that it will be useful, but WITHOUT
10 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11 # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 
12 # details. 
13 #
14 #   You should have received a copy of the GNU Lesser General Public
15 # License along with this library; if not, write to the Free Software 
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 #++
18
19
20 module ViewHelpers::HtmlHelper
21
22     def html_edit_link(id, action = :edit)
23         return link_to image_tag("/images/edit-icon.png", :alt => :edit), {:action => action, :id => id}, :onclick=>"$('#progress').show()"
24     end
25
26         # added additional argument to replace message string (see bnc#581153)
27     def html_delete_link(id, action = :delete, text = _('Are you sure?'))
28         return link_to image_tag("/images/delete.png", :alt => :delete), {:action => action, :id => id},
29         :confirm => text, :method => :delete
30     end
31
32     def html_create_table_content(items, properties, permissions = {}, proc_obj = nil)
33         ret = ''
34         columns = properties.size
35
36         items.each do |item|
37             line = ''
38             columns.times { |col|
39                 property = properties[col]
40
41                 if !property.nil? && item.respond_to?(property)
42                     cell = item.send(property)
43                 else
44                     if proc_obj.nil?
45                         cell = "ERROR: unknown method #{property}"
46                     else
47                         cell = proc_obj.call(item, col)
48                     end
49                 end
50
51                 line += "<td>#{h(cell)}</td>"
52             }
53
54             if permissions[:edit]
55                 line += "<td align=\"center\">#{html_edit_link(item.send(permissions[:id]))}</td>"
56             end
57
58             if permissions[:delete]
59                 line += "<td align=\"center\">#{html_delete_link(item.send(permissions[:id]))}</td>"
60             end
61
62             ret += "<tr>#{line}</tr>"
63         end
64
65         return ret
66     end
67
68     ##
69     # Create a simple HTML table
70     #
71     # Parameters:
72     # * labels - an array of strings - table headings
73     # * items - an array of objects - table content
74     # * properties - an array of strings - name of the method which will be called for the respective column.
75     #   The result will be displayed in the table.
76     # * permissions - a hash with permissions - used to display/hide Add, Edit, and Delete buttons.
77     #   The argument is optional, if missing no button will be displayed. Expected keys are :add, :edit, :delete.
78     #   If a key is missing or the value is false the relevant button is hidden.
79     # * optional block with two arguments: object and column number - this block is used
80     #   for computing table values for columns with property method set to nil. See the example.
81     #   Use the column block parameter to distinguish the columns if there are several columns with nil property.
82     #
83     # Examples:
84     #
85     # <tt>simple_table([_("First Name"), _("Surname")], @users, [:first_name, :surname], {:add => true, :edit => true, :delete => true, :id => :name})</tt>
86     #
87     # <tt>simple_table([_("Avg. Download Speed")], files, [nil]){|file, column| "#{file.size/file.download_time/1024} kB/s"}</tt>
88     #
89     def html_simple_table(labels, items, properties, permissions = {}, &block)
90         header = ''
91
92         labels.each { |l|
93             header += "<th class=\"first\">#{h(l)}</th>"
94         }
95
96         if permissions[:edit]
97             header += "<th class=\"first\" width=10%>#{h(label_edit)}</th>"
98         end
99
100         if permissions[:delete]
101             header += "<th class=\"first\" width=10%>#{h(label_delete)}</th>"
102         end
103
104         content = html_create_table_content(items, properties, permissions, block)
105
106         ret = "<table class=\"list\"><tr>#{header}</tr>#{content}</table>"
107
108         ret += "<br/>" + button_to(label_add, {:action => "new"}) if permissions[:add]
109
110         return ret
111     end
112
113     # clipboard icon for a predefined text
114     def clippy(text, bgcolor='#FFFFFF')
115       text.gsub! "\"","''" #replace quotes in text as it breaks output (bnc#596023)
116       text.gsub! "&","%28" #escape & which is special in FlashVars (bnc#596023)
117   html = <<-EOF
118     <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000"
119             width="110"
120             height="14"
121             id="clippy" >
122     <param name="movie" value="/flash/clippy.swf"/>
123     <param name="allowScriptAccess" value="always" />
124     <param name="quality" value="high" />
125     <param name="scale" value="noscale" />
126     <param NAME="FlashVars" value="text=#{text}">
127     <param name="bgcolor" value="#{bgcolor}">
128     <embed src="/flash/clippy.swf"
129            width="110"
130            height="14"
131            name="clippy"
132            quality="high"
133            allowScriptAccess="always"
134            type="application/x-shockwave-flash"
135            pluginspage="http://www.macromedia.com/go/getflashplayer"
136            FlashVars="text=#{text}"
137            bgcolor="#{bgcolor}"
138     />
139     </object>
140   EOF
141   end
142
143   # report an exception to the flash messages zone
144   # a flash error message will be appended to the
145   # element with id "flashes" with standard jquery
146   # ui styles. A link with more information that
147   # display a popup is also automatically created    
148   def report_error(error, message=nil)
149     # get the id of the error, or use a random id
150     error_id = error.nil? ? rand(10000) : error.object_id
151
152     err_message = error.try(:message)
153     err_message ||= _("Unknown error")
154
155     # get the backtrace, or create a message saying there is none
156     backtrace_text = error.try(:backtrace).try(:join, "\n")
157     backtrace_text = _("No information available") if backtrace_text.blank?
158
159     # the summary message
160     message ||= _("There was a problem retrieving information from the server.")
161
162     # build the html    
163     html =<<-EOF2
164       <div id="error-#{error_id}-content">
165         <div>
166           <p><strong>Error message:</strong>#{err_message}</p>
167           <p><span class="bug-icon"></span><a target="_blank" href="#{::ApplicationController.bug_url}">Report bug</a></p>
168           <p><a href="#" id="error-#{error_id}-show-backtrace-link">Show details</a>
169           #{clippy("message: #{err_message}\n backtrace: #{backtrace_text}")}</p></p>
170           <pre id="error-#{error_id}-backtrace" style="display: none">
171           #{backtrace_text}
172           </pre>
173         </div>
174       </div>
175
176       <div class="ui-state-error ui-corner-all" style="margin-top: 20px; padding: 0 .7em;" id="error-#{error_id}-summary">
177         <p><span class="ui-icon ui-icon-alert"/>#{message} (<a href="#" id="error-#{error_id}-details-link">more..</a>)</p>
178       </div>
179
180       <script type="text/javascript">
181         $(document).ready(
182           function() {
183             //$('#error-#{error_id}-summary').hide();
184
185             // hide the exception details
186             $('#error-#{error_id}-content').hide();
187
188             // put the error summary with the other flashes
189             // and not where the output should go
190             $('#flash-messages').prepend($('#error-#{error_id}-summary'));
191
192             //$('#error-#{error_id}-content').show();
193     
194            // define a dialog with the error details
195            $('#error-#{error_id}-content').dialog(
196            {
197              bgiframe: true,
198              autoOpen: false,
199              height: 300,
200              modal: true
201            });
202
203            // make the More link to open the dialog with details
204            $('#error-#{error_id}-details-link').click( function() {
205              $('#error-#{error_id}-content').dialog('open');
206            });
207
208            // make the Show details links show the backtrace
209            $('#error-#{error_id}-show-backtrace-link').click(function() {
210              $('#error-#{error_id}-backtrace').hide();
211              $('#error-#{error_id}-backtrace').show();
212              return false;
213            });
214          });
215      </script>
216 EOF2
217   end
218
219   def progress_bar(percent, width = '150px', height = '1.4em')
220     # display only 0-100% range
221     percent = 100 if percent > 100
222     percent = 0 if percent < 0
223
224     html = <<-EOF_PROGRESS
225     <div class="progress_bar">
226       <div class="progress_bar_percent" style="width: #{width}; line-height: #{height}">#{percent.to_i}%</div>
227       <div class="progress_bar_frame" style="width: #{width}; height: #{height};">
228         <div class="progress_bar_progress" style="width: #{percent.to_i}%; height: #{height};"/>
229       </div>
230     </div>
231 EOF_PROGRESS
232   end
233
234   # Encode an input string to a string which can be safely used as
235   # an HTML element id without escaping problematic symbols.
236   # The result contains only [a-zA-Z0-9_]* characters and can be used in jQuery
237   # selectors without escaping.
238   # Example:
239   #     my_id = safe_id id
240
241   #     <td id="my_table_item_<%= my_id -%>" ...
242   #     remote_function(:update => "#my_table_item_#{my_id}", ... )
243   #     $('#my_table_item_#{my_id}').hide()
244   def safe_id id
245     return nil if id.nil?
246
247     require 'base64'
248
249     # encode using Base64 encoding, remove the padding at the end
250     Base64.encode64(id.to_s).match /^([^=]*)=*$/
251
252     # make one line string and replace symbols used in Base64
253     # to get string containing only [-a-zA-Z0-9_]* characters
254     # see http://en.wikipedia.org/wiki/Base64
255     # (esp. "modified Base64 for URL" paragraph)
256     ret = $1
257     ret.gsub!("\n", '')
258     ret.gsub!('+', '-')
259     ret.gsub!('/', '_')
260     ret
261   end
262
263   # JavaScript String, makes a JS literal from a string value,
264   # typically from a translated string.
265   #
266   # Usage:
267   #
268   #   alert(<%= jss _("These are 'quotes'.") -%>);
269   #
270   # That works correctly if the text gets translated
271   # to 'Toto jsou "uvozovky".'
272   # (see also https://bugzilla.novell.com/show_bug.cgi?id=604224)
273   def jss(s)
274     "\"#{escape_javascript s}\""
275   end
276
277 end
278
279 # vim: ft=ruby