2 # Nick's web site: Generate directory listing.
4 # Copyright © 2021 Nick Bowler
6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation, either version 3 of the License, or
9 # (at your option) any later version.
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <https://www.gnu.org/licenses/>
22 @items.find_all(@item[:pattern]).each do |item|
25 item.reps.each do |rep|
30 next unless "#{d}/" == mydir
33 displaysize = Dir.children(File.dirname(rep.raw_path)).length - 1
34 size = displaysize - 1000000
37 size = File.size(rep.raw_path)
38 displaysize = human_filesize(size)
43 sorttime: if t then t.to_f else 0.0 end,
44 displaytime: if t then t.getutc.strftime "%Y-%m-%d %H:%M\u00a0UTC" end,
45 displaysize: displaysize,
52 if @items["#{File.dirname(mydir)}/index.lst"]
53 files[".."] = { type: :UP }
56 def render_entry(files, key)
60 "<img alt='#{f[:type]}' width='16' height='16' src='#{case f[:type]
61 when :DIR; "/icons/folder.svg"
62 when :UP; "/icons/return.svg"
63 else raise "no icon for filetype #{f[:type]}"
66 <td><a href='#{key}'>#{
67 if key == ".." then "[Parent Directory]" else key end
69 <td>#{f[:displaytime]}</td>
70 <td>#{f[:displaysize]}</td>
74 <table class='filelist' clicky='name'>
78 <th clicky='name'>Name</th>
79 <th clicky='date'>Last Modified</th>
80 <th clicky='size'>Size</th>
85 parentrow = if files[".."] then "#{render_entry(files, "..")}" end
87 if parentrow then "<tr>#{parentrow}</tr>" end
90 by_name = files.keys.sort{ |a, b| strverscmp(a, b) }
92 entry = render_entry(files, key)
100 def meta_cmp(files, key, a, b)
101 av, bv = files[a][key], files[b][key]
102 return av <=> bv if av != bv
103 return strverscmp(a, b)
106 by_date = files.keys.sort { |a, b| meta_cmp(files, :sorttime, a, b) }
107 by_size = files.keys.sort { |a, b| meta_cmp(files, :size, a, b) }
109 listnames = [ "namerev", "datefwd", "daterev", "sizefwd", "sizerev" ]
110 lists = [ by_name.reverse, by_date, by_date.reverse, by_size, by_size.reverse ]
113 <tr class='<%= listnames.join(" ") %>'><%= parentrow %></tr>
116 evenmap = (0..(lists.length-1)).map { false }
119 while not (elems = lists.map(&:first)).compact.empty?
120 matches = (0..(lists.length-1)).to_a.keep_if { |x| evenmap[x] == even }
122 elems = elems.values_at(*matches).compact
123 mode = elems.group_by{|a| a}.max{|a, b| a[1].length <=> b[1].length}[0]
126 lists.each_index do |i|
127 if evenmap[i] == even and lists[i].first.eql? mode
130 evenmap[i] = nil if lists[i].empty?
136 <tr class='<%= listnames.values_at(*matches).join(" ") %>'>
137 <%= render_entry(files, mode) %>