305 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Ruby
		
	
	
			
		
		
	
	
			305 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			Ruby
		
	
	
| # SPDX-License-Identifier: Apache-2.0
 | |
| # Copyright (C) 2021 OKTET Labs Ltd. All rights reserved.
 | |
| 
 | |
| #
 | |
| # General CGI helpers
 | |
| #
 | |
| 
 | |
| HEADER_FILE = "header.html"
 | |
| FOOTER_FILE = "footer.html"
 | |
| 
 | |
| CURRENT_MONTH = "- Current -"
 | |
| # Where to place it in the months list
 | |
| CURRENT_MONTH_NUMBER = 0
 | |
| 
 | |
| def cgi_debug_log(msg)
 | |
|     STDERR.puts "DEBUG: " + msg
 | |
| end
 | |
| 
 | |
| class MyCGI < CGI
 | |
| 
 | |
|     # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/23950?help-en
 | |
|     def MyCGI::pretty(string, shift = "  ")
 | |
|         i = 0; preserve = {}
 | |
|         lines = string.gsub(/\n*<pre.*<\/pre>\n*/inm) {
 | |
|             t = "%PRE#{i}"; i += 1
 | |
|             preserve[t] = $&
 | |
|             t
 | |
|         }
 | |
|         lines = lines.gsub(/\n*<textarea.*<\/textarea>\n*/inm) {
 | |
|             t = "%TEXTAREA#{i}"; i += 1
 | |
|             preserve[t] = $&
 | |
|             t
 | |
|         }
 | |
|         lines = lines.gsub(/(?!\A)<(?:.|\n)*?>/n,
 | |
|                            "\n\\0").gsub(/<(?:.|\n)*?>(?!\n)/n, "\\0\n")
 | |
|         end_pos = 0
 | |
|         while end_pos = lines.index(/^<\/(\w+)/n, end_pos)
 | |
|             element = $1.dup
 | |
|             start_pos = lines.rindex(/^\s*<#{element}/ni, end_pos)
 | |
|             lines[start_pos ... end_pos] = "__" +
 | |
|                 lines[start_pos ...  end_pos].
 | |
|                     gsub(/\n(?!\z)/n, "\n" + shift) +
 | |
|                 "__"
 | |
|         end
 | |
|         lines = lines.gsub(/^((?:#{Regexp::quote(shift)})*)__(?=<\/?\w)/n,
 | |
|                            '\1')
 | |
|         preserve.each { |t, s|
 | |
|             lines.sub!(/#{Regexp::quote(t)}/, s)
 | |
|         }
 | |
|         lines
 | |
|     end
 | |
| 
 | |
|     def MyCGI::list_select(list, param)
 | |
|         param = Array.new if not param
 | |
|         list.collect do |entry|
 | |
|             param.include?(entry[0]) ? entry.dup.push(true) : entry
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     def initialize(form_type, default_params, multiple_key, multiline_key, *args)
 | |
|         super(*args)
 | |
|         @form_type = form_type
 | |
|         @tree_params = default_params
 | |
|         @multiple_key = multiple_key
 | |
|         @multiline_key = multiline_key
 | |
|         self.params.each do |key, value|
 | |
|                 @tree_params = add_value(@tree_params, key, value, @multiple_key.include?(key))
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     def add_value(hash, key, value, multiple)
 | |
|         hash = Hash.new if not hash
 | |
|         if /^(.*?):(.*)$/ =~ key
 | |
|             hash[$1] = add_value(hash[$1], $2, value, @multiple_key.include?($1))
 | |
|         elsif @multiline_key.include?(key)
 | |
|             hash[key] = value.join
 | |
|         else
 | |
|             hash[key] = (multiple or value.length > 1) ? value : value[0]
 | |
|         end
 | |
|         hash
 | |
|     end
 | |
| 
 | |
|     def hiddens(value)
 | |
|         value.inject([]) do |res, item|
 | |
|             res + [Amrita.a(:name => item[0], :value => item[1])]
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     # Create array of pairs [name, value] from the parameters subtree
 | |
|     def tree_flatten(keys)
 | |
|         hash = @tree_params
 | |
|         keys.each do |key|
 | |
|             return [] if not hash[key]
 | |
|             hash = hash[key]
 | |
|         end
 | |
|         add_flatten(keys[0..-2], keys[-1], hash)
 | |
|     end
 | |
| 
 | |
|     def add_flatten(prefix, field, data)
 | |
|         names = field ? prefix + [field] : prefix
 | |
|         if data.is_a? Hash
 | |
|             data.inject([]) do |res, pair|
 | |
|                 res + add_flatten(names, pair[0], pair[1])
 | |
|             end
 | |
|         elsif data.is_a? Array
 | |
|             data.inject([]) do |res, value|
 | |
|                 res << [names.join(":"), value.to_s]
 | |
|             end
 | |
|         else
 | |
|             # single value
 | |
|             [[names.join(":"), data.to_s]]
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     def tree_hidden(keys)
 | |
|         hash = @tree_params
 | |
|         keys.each do |key|
 | |
|             return "" if not hash[key]
 | |
|             hash = hash[key]
 | |
|         end
 | |
|         add_hidden(keys[0..-2], keys[-1], hash)
 | |
|     end
 | |
| 
 | |
|     def MyCGI::list_options(data, selections = nil)
 | |
|         selection = ((selections.is_a? Array) ? selections[0] : selections).to_s
 | |
|         data.collect do |pair|
 | |
|             item = Amrita.a(:value => pair[0]){ pair[1] }
 | |
|             item << Amrita.a(:selected => "selected")[0] if
 | |
|                 pair[0].to_s == selection
 | |
|             item
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     def tree_hidden_e(keys)
 | |
|         hash = @tree_params
 | |
|         keys.each do |key|
 | |
|             return [] if not hash[key]
 | |
|             hash = hash[key]
 | |
|         end
 | |
|         add_hidden_e(keys[0..-2], keys[-1], hash)
 | |
|     end
 | |
| 
 | |
|     def add_hidden_e(prefix, field, value)
 | |
|         if value.is_a? Hash
 | |
|             value.inject([]) do |res, pair|
 | |
|                 res + add_hidden_e(prefix + [field], pair[0], pair[1])
 | |
|             end
 | |
|         else
 | |
|             value.inject([]) do |res, value1|
 | |
|                 res + [ Amrita.a(:name => (prefix + [field]).join(":"),
 | |
|                                :value => value1) ]
 | |
|             end
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     def add_hidden(prefix, field, value)
 | |
|         if value.is_a?Hash
 | |
|             value.inject("") do |res, pair|
 | |
|                 res + add_hidden(prefix + [field], pair[0], pair[1])
 | |
|             end
 | |
|         else
 | |
|             value.inject("") do |res, value1|
 | |
|                 res + hidden((prefix + [field]).join(":"), value1)
 | |
|             end
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     def MyCGI::hash2date(hash)
 | |
|         begin
 | |
|             value = %w(year month day).collect do |p|
 | |
|                     hash[p].is_a?(Array) ? hash[p][0] : hash[p]
 | |
|                     end
 | |
|             value[0] = case value[0]
 | |
|                        when '$' then 9999
 | |
|                        when '#' then Date.today.year
 | |
|                        else value[0].to_i
 | |
|                        end
 | |
|             value[1] = case value[1]
 | |
|                        when '$' then Date::MONTHNAMES.length - 1
 | |
|                        when CURRENT_MONTH then Date.today.month
 | |
|                        when CURRENT_MONTH_NUMBER.to_s then Date.today.month
 | |
|                        else value[1].to_i
 | |
|                        end
 | |
| 
 | |
|             if value[2] == '$'
 | |
|                 value[2] = 1
 | |
|                 (Date.new(*value) >> 1) - 1
 | |
|             elsif value[2] == '#'
 | |
|                 value[2] = Date.today.day
 | |
|                 Date.new(*value)
 | |
|             else
 | |
|                 value[2] = value[2].to_i
 | |
|                 Date.new(*value)
 | |
|             end
 | |
|         rescue ArgumentError
 | |
|             raise "Invalid date #{hash["year"]}-#{hash["month"]}-#{hash["day"]}"
 | |
|         end
 | |
|     end
 | |
|     def MyCGI::date2hash(date)
 | |
|         {
 | |
|             "year" => [date.year.to_s],
 | |
|             "month" => [date.mon.to_s],
 | |
|             "day" => [date.day.to_s]
 | |
|         }
 | |
|     end
 | |
| 
 | |
|     def MyCGI::select_date(prefix = "", value = nil, edit = false)
 | |
|         if value == nil
 | |
|             edit = true
 | |
|             value = MyCGI::date2hash(Date.today)
 | |
|         elsif value.is_a?Hash
 | |
|             # TODO: !!!!
 | |
|             value = { "year" => [value["year"]],
 | |
|                       "month" => [value["month"]],
 | |
|                       "day" => [value["day"]] } unless value["year"].is_a?Array
 | |
|             edit = true
 | |
|         else
 | |
|             value = MyCGI::date2hash(value)
 | |
|         end
 | |
|         if edit
 | |
|             template = Amrita::TemplateText.new(
 | |
|                 "<input class='form-control' id='day' size='2' type='text'>
 | |
|                  <select class='form-control' id='month'><option id='item'></select>
 | |
|                  <input class='form-control' id='year' size='4' type='text'>")
 | |
|             template.asxml = true
 | |
|             s = String.new
 | |
|             template.expand(s,
 | |
|                 {:day => Amrita.a(
 | |
|                     :name => prefix + ":day",
 | |
|                     :value => value["day"][0]),
 | |
|                  :month => Amrita.a(
 | |
|                      :name => prefix + ":month"){
 | |
|                      {:item => list_options(
 | |
|                           (0..(Date::MONTHNAMES.length - 1)).collect do |m|
 | |
|                               case m
 | |
|                               when CURRENT_MONTH_NUMBER then [m.to_s, CURRENT_MONTH]
 | |
|                               else [m.to_s, Date::MONTHNAMES[m]]
 | |
|                               end
 | |
|                           end, value["month"][0])
 | |
|                       }
 | |
|                       },
 | |
|                  :year => Amrita.a(
 | |
|                      :name => prefix + ":year",
 | |
|                      :value => value["year"][0])
 | |
|                  })
 | |
|             s
 | |
|         else
 | |
|             d = Date.new(value["year"][0].to_i, value["month"][0].to_i,
 | |
|                          value["day"][0].to_i)
 | |
|             sprintf("%s %s %s (%s)", value["day"][0],
 | |
|                     Date::MONTHNAMES[value["month"][0].to_i],
 | |
|                     value["year"][0],
 | |
|                     Date::ABBR_DAYNAMES[d.wday])
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     def MyCGI::select_date_e(prefix = "", value = nil, edit = false)
 | |
|         noescape{ select_date(prefix, value, edit) }
 | |
|     end
 | |
| 
 | |
|     # Assign values to the all-site common parts of the page
 | |
|     #
 | |
|     # @param data  Hash of data for amrita template of the page
 | |
|     def MyCGI::add_commons(data)
 | |
|         data[:header] = noescape{ File.open(HEADER_FILE) { |f| f.read }}
 | |
|         data[:footer] = noescape{ File.open(FOOTER_FILE) { |f| f.read }}
 | |
|     end
 | |
| 
 | |
|     def MyCGI::optional(data)
 | |
|         { :value => data }
 | |
|     end
 | |
| 
 | |
|     # Create string from the 'value' that can be used
 | |
|     # as a value of HTML DOM attribute 'id'
 | |
|     #
 | |
|     # @return String of proposed attribute value
 | |
|     def MyCGI::element_id(value)
 | |
|         id = value.to_s
 | |
|         if id.empty? or id !~ /[A-Za-z].*/
 | |
|             "s" + id
 | |
|         else
 | |
|             id
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     def MyCGI.dump(value)
 | |
|         case value.class.to_s
 | |
|         when "Hash" then
 | |
|             "{" + value.collect do |key, x|
 | |
|                 "#{key} => #{dump(x)}"
 | |
|             end.join(", ") + "}"
 | |
|         when "String" then
 | |
|             "\"#{value}\""
 | |
|         when "Array" then
 | |
|             "[#{value.collect {|x| dump(x)}.join(",")}]"
 | |
|         else
 | |
|             "#{value.class}(#{value.to_s})"
 | |
|         end
 | |
|     end
 | |
| 
 | |
|     attr_accessor :form_type, :tree_params, :multiple_key
 | |
|     private :add_value
 | |
| end
 | |
| 
 |