implemented Cash positions
[smr.git] / gui / app / helpers / application_helper.rb
blobb5fc52944c9ca7a6736917375bf8ae2af7612813
2 # This file is part of SMR.
4 # SMR is free software: you can redistribute it and/or modify it under the
5 # terms of the GNU General Public License as published by the Free Software
6 # Foundation, either version 3 of the License, or (at your option) any later
7 # version.
9 # SMR is distributed in the hope that it will be useful, but WITHOUT ANY
10 # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 # A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License along with
14 # SMR.  If not, see <http://www.gnu.org/licenses/>.
17 require 'percentage'
20 # Collection of helper methods for use in all views.
21 module ApplicationHelper
23     ##
24     # Date the user is currently browsing, as +Time+.
25     def smr_browse_date
26         if session[:smr_browse_date].nil? then Time.new
27         else Time.at(session[:smr_browse_date]) end
28     end
30     ##
31     # Place the users us browsing as +String+.
32     def smr_browse_position
33         controller.class.to_s.sub('Controller', '')
34     end
36     ##
37     # Returns change from +val1+ to +val2+ in percent, as smr_humanize()d String.
38     def percentage_change(val1, val2)
39         return nil if val1.zero? or val2.blank?
40         smr_humanize(Percentage.change(val1, val2))
41     end
43     ##
44     # Returns percentage of +val+ from +base+, as smr_humanize()d String.
45     def percentage_of(base, val)
46         if base.zero? then return nil end
47         smr_humanize(BigDecimal(val.to_s).as_percentage_of(base))
48     end
50     ##
51     # humanize a number in ways useful in SMR
52     #
53     # Options:
54     # - :scientific notation, ie 1000 => 1.0e3
55     # - :shortword as spoken but short form, ie 1000 = 1 Kilo => 1k
56     def smr_humanize(n, options={ :scientific=>false, :shortword=>false, :date_with_time=>false })
57         unit = String.new
58         format = '%s'
59         skip_rounding=false
61         # handle 'inappropriate' data quickly
62         return '-' if n == 0.0 or n == false
63         return '' if n == ''
64         return n if n.is_a?(String)
66         # decide whether to round
67         skip_rounding = true if n.is_a?(Fixnum) and n.abs < 1000
68         skip_rounding = true if (n.nil? or n == false)
70         if n.is_a?(Percentage)
71             unit = '%'
72             format = if n.to_f < 10 then '%.1f' else '%i' end
73             skip_rounding = true           
74         end
76         if n.is_a?(Time)
77             dateformat = if options[:date_with_time] then '%Y-%m-%d %H:%S' else '%Y-%m-%d' end
78             format = '%s'+n.strftime(dateformat)
79             n = nil 
80             skip_rounding = true
81         end
83         if options[:shortword]
84             skip_rounding = true
85             n = number_to_human(
86                 n,
87                 :units=>{
88                     :unit=>'', :thousand=>'k', :million=>'m', :billion=>'b',
89                     :trillion=>'t', :quadrillion=>'q'
90                 }
91             )
92         end
94         # do generic rounding if necessary
95         unless skip_rounding
96             case n.abs
97                 when 0..1 then format = '%.4f'
98                 when 1..9 then format = '%.3f'
99                 when 10..99 then format = '%.2f'
100                 when 100..1000 then format = '%.1f'
101             else
102                 format = if options[:scientific] then '%.3e' else '%i' end
103             end
104         end
106         # return a String
107         (format + '%s') % [n, unit]
108     end
110     ##
111     # Turns Time into human speakable String
112     def smr_human_date(time)
113         time.strftime("%A, %B %d %Y")
114     end
116     ##
117     # Returns menu to browse SMR functionality in HTML format, see
118     # @smr_menu_items and smr_menu_addsubitem().
119     # TODO: supports one sublevel only, do we ever need more?
120     def smr_menu
121         content_tag(:ul, nil, :id=>'smr_menu') {
122           @smr_menu_items.reduce('') { |ctag, top|
123             if top.second.is_a?(Hash) then
124                 # sub level
125                 ctag << content_tag(:li) do
126                     link_to(top.first, top.second.delete('_toplink')) + 
127                     content_tag(:ul, nil) do
128                         top.second.reduce('') { |c, sub|
129                             c << content_tag(:li, link_to(sub.first, sub.second))
130                         }.html_safe
131                     end
132                 end
133             else
134                 # top level
135                 ctag << content_tag(:li, link_to(top.first, top.second))
136             end
137           }.html_safe
138         }
139     end
141     ##
142     # Provide link back to original object from Smr::BlogItem. Returns nil if
143     # there is no reference on that item.
144     #
145     # NOTE:
146     # - works only for +type=Comment+ right now and if the Comment is not
147     #   older than 7 days (the later is intentional as we want to store THE
148     #   TRUTH and not alternate it afterwards)
149     def smr_link_back(smr_blogitem, name)
150         raise 'smr_blogitem must be Smr::BlogItem' unless smr_blogitem.is_a?(Smr::BlogItem)
152         if smr_blogitem.type == 'Comment' and smr_blogitem.refid and smr_blogitem.date>7.days.ago then
153             link_to name, :controller=>:blog, :action=>:new, :id=>smr_blogitem.refid
154         else
155             nil
156         end
157     end
159     ##
160     # Create HTML container with page links.
161     #
162     # It will be positioned at +current_page+ with a maximum of +num_pages+
163     # and each link will direct to +basepath/?page=N+.
164     def smr_paginate(current_page, num_pages, basepath)
165             JustPaginate.page_navigation(current_page, num_pages) do |p|
166             '%s/?page=%i' % [basepath, p]
167         end.html_safe
168     end
170     ##
171     # Profit/Loss status number :n as text for humans to read or CSS class
172     # name.
173     def smr_profitloss_status(n, css=false)
174         if n.is_a?(FalseClass) or n == 0
175             s='Unvalued'
176         elsif n.between?(-150, 200)
177             s='Even'
178         elsif n > 0.0
179             s='Profit'
180         elsif n < 0.0
181             s='Loss'
182         end
184         if css then s.downcase else s end
185     end