# web/lib/utils.rb # ------------------------------------------------------------------------------ # patch some convenience methods into base classes class Fixnum # convert to string with thin space as thousand separator def to_s_with_ts self.to_s.gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1 ") end end class String def titlecase self[0,1].upcase + self[1,self.size].downcase end end class Numeric def to_bytes if self >= 1024*1024 unit = 'MB' value = self / (1024*1024) elsif self >= 1024 unit = 'kB' value = self / 1024 else unit = 'B' end value.to_i.to_s + ' ' + unit end end class Float def round_to(n=0) (self * (10.0 ** n)).round * (10.0 ** (-n)) end end # ------------------------------------------------------------------------------ def title @title = [] if @title.nil? @title = [@title] unless @title.is_a?(Array) @title << TaginfoConfig.get('instance.name', 'OpenStreetMap Taginfo') @title.join(' | ') end def section(id) @section = id.to_s @section_title = (@section =~ /^(keys|tags)$/) ? t.osm[@section] : t.taginfo[@section] end def json_opts(format) if format == 'json_pretty' return { :indent => ' ', :space => ' ', :object_nl => "\n" } else return {} end end # ------------------------------------------------------------------------------ # Escape tag key or value for XAPI according to # http://wiki.openstreetmap.org/wiki/XAPI#Escaping def xapi_escape(text) text.gsub(/([|\[\]*\/=()\\])/, '\\\\\1') end def xapi_url(element, key, value=nil) predicate = xapi_escape(key) + '=' if value.nil? predicate += '*' else predicate += xapi_escape(value) end TaginfoConfig.get('xapi.url_prefix', 'http://www.informationfreeway.org/api/0.6/') + "#{ element }[#{ Rack::Utils::escape(predicate) }]" end def xapi_link(element, key, value=nil) '' + external_link('xapi_button', 'XAPI', xapi_url(element, key, value), true) + '' end def josm_link(element, key, value=nil) '' + external_link('josm_button', 'JOSM', 'http://localhost:8111/import?url=' + Rack::Utils::escape(xapi_url(element, key, value)), true) + '' end def quote_double(text) text.gsub(/["\\]/, "\\\\\\0") end def turbo_link(count, filter, key, value=nil) if count <= TaginfoConfig.get('turbo.max_auto', 100) key = quote_double(key) if value.nil? value = '*' else value = '"' + quote_double(value) + '"' end if filter != 'all' filter_condition = ' and type:' + filter.chop end url = TaginfoConfig.get('turbo.url_prefix', 'http://overpass-turbo.eu/?') + 'w=' + Rack::Utils::escape('"' + key + '"=' + value + filter_condition.to_s + ' ' + TaginfoConfig.get('turbo.wizard_area', 'global')) + '&R' else template = 'key'; parameters = { :key => key } unless value.nil? parameters[:value] = value; template += '-value' end if filter != 'all' template += '-type' parameters[:type] = filter.chop end parameters[:template] = template url = TaginfoConfig.get('turbo.url_prefix', 'http://overpass-turbo.eu/?') + Rack::Utils::build_query(parameters) end return '' + external_link('turbo_button', ' overpass turbo', url, true) + '' end def level0_link() return '' + external_link('level0_button', 'Level0 Editor', '#', true) + '' end def external_link(id, title, link, new_window=false) target = new_window ? 'target="_blank" ' : '' %Q{#{title}} end def wiki_link(title) prefix = '//wiki.openstreetmap.org/wiki/' external_link('wikilink_' + title.gsub(%r{[^A-Za-z0-9]}, '_'), title, prefix + title) end # ------------------------------------------------------------------------------ def tagcloud_size(tag) x = tag['scale1'].to_f / 20 + tag['pos'] / 4 (x * 40 + 12).to_i end def get_filter f = params[:filter].to_s == '' ? 'all' : params[:filter] if f !~ /^(all|nodes|ways|relations)$/ raise ArgumentError, "unknown filter" end f end def get_total(type) key = { 'all' => 'objects', 'nodes' => 'nodes_with_tags', 'ways' => 'ways', 'relations' => 'relations' }[type] return @db.stats(key) end # ------------------------------------------------------------------------------ # Escape % and _ special characters with @. # The @ was chosen because it is not a special character in SQL, in Regexes, # and isn't seen often in OSM tags. You must use "ESCAPE '@'" clause with LIKE! def like_escape(param) param.to_s.gsub(/[_%@]/, '@\0') end def like_prefix(param) like_escape(param) + '%' end def like_contains(param) '%' + like_escape(param) + '%' end # ------------------------------------------------------------------------------ # Like the 'get' method but will add a redirect for the same path with trailing / added def get!(path, &block) get path, &block get path + '/' do redirect path end end # Like the 'get' method but specific for API calls, includes documentation for API calls def api(version, path, doc=nil, &block) API.new(version, path, doc) unless doc.nil? get("/api/#{version}/#{path}", &block) end # ------------------------------------------------------------------------------ # Used in wiki api calls def get_wiki_result(res) return JSON.generate(res.map{ |row| { :lang => row['lang'], :language => ::Language[row['lang']].native_name, :language_en => ::Language[row['lang']].english_name, :title => row['title'], :description => row['description'] || '', :image => { :title => row['image'], :width => row['width'].to_i, :height => row['height'].to_i, :mime => row['mime'], :image_url => row['image_url'], :thumb_url_prefix => row['thumb_url_prefix'], :thumb_url_suffix => row['thumb_url_suffix'] }, :on_node => row['on_node'].to_i == 1, :on_way => row['on_way'].to_i == 1, :on_area => row['on_area'].to_i == 1, :on_relation => row['on_relation'].to_i == 1, :tags_implies => row['tags_implies' ].split(','), :tags_combination => row['tags_combination'].split(','), :tags_linked => row['tags_linked' ].split(',') } }, json_opts(params[:format])) end # Used in josm api calls def get_josm_style_rules_result(total, res) return JSON.generate({ :page => @ap.page, :rp => @ap.results_per_page, :total => total, :url => request.url, :data => res.map{ |row| { :key => row['k'], :value => row['v'], :value_bool => row['b'], :rule => row['rule'], :area_color => row['area_color'] ? row['area_color'].sub(/^.*#/, '#') : '', :line_color => row['line_color'] ? row['line_color'].sub(/^.*#/, '#') : '', :line_width => row['line_width'] ? row['line_width'].to_i : 0, :icon => row['icon_source'] && row['icon_source'] != 'misc/deprecated.png' && row['icon_source'] != 'misc/no_icon.png' ? row['icon_source'] : '' } } }, json_opts(params[:format])) end def paging_results(array) return [ [ :total, :INT, 'Total number of results.' ], [ :page, :INT, 'Result page number (first has page number 1).' ], [ :rp, :INT, 'Results per page.' ], [ :url, :STRING, 'URL of the request.' ], [ :data, :ARRAY_OF_HASHES, 'Array with results.', array ] ]; end def no_paging_results(array) return [ [ :total, :INT, 'Total number of results.' ], [ :url, :STRING, 'URL of the request.' ], [ :data, :ARRAY_OF_HASHES, 'Array with results.', array ] ]; end MAX_IMAGE_WIDTH = 300 def build_image_url(row) w = row['width'].to_i h = row['height'].to_i if w <= MAX_IMAGE_WIDTH return row['image_url'] end if w > 0 && h > 0 return "#{row['thumb_url_prefix']}#{ h <= w ? MAX_IMAGE_WIDTH : (MAX_IMAGE_WIDTH * w / h).to_i }#{ row['thumb_url_suffix'] }" end return nil end