]> git.draconx.ca Git - homepage.git/blobdiff - layouts/listing.erb
Improve clicky table generation.
[homepage.git] / layouts / listing.erb
diff --git a/layouts/listing.erb b/layouts/listing.erb
new file mode 100644 (file)
index 0000000..02017a0
--- /dev/null
@@ -0,0 +1,150 @@
+<%
+# Nick's web site: Generate directory listing.
+#
+# Copyright © 2021 Nick Bowler
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>
+
+mydir = rep_uri
+
+files = {}
+@items.find_all(@item[:pattern]).each do |item|
+  t = item[:updated_at]
+
+  item.reps.each do |rep|
+    next if rep == @rep
+
+    p = rep_uri(rep)
+    d, f = File.split(p)
+    next unless "#{d}/" == mydir
+
+    if p =~ %r{/$}
+      displaysize = Dir.children(File.dirname(rep.raw_path)).length - 1
+      size = displaysize - 1000000
+      type = :DIR
+    else
+      size = File.size(rep.raw_path)
+      displaysize = human_filesize(size)
+      type = nil
+    end
+
+    files[f] = {
+      sorttime: if t then t.to_f else 0.0 end,
+      displaytime: if t then t.getutc.strftime "%Y-%m-%d %H:%M UTC" end,
+      displaysize: displaysize,
+      size: size,
+      type: type,
+    }
+  end
+end
+
+if @items["#{File.dirname(mydir)}/index.lst"]
+  files[".."] = { type: :UP }
+end
+
+def render_entry(files, key)
+  f = files[key]
+  return <<~EOF
+    <td>#{if f[:type]
+      "<img alt='#{f[:type]}' width='16' height='16' src='#{case f[:type]
+            when :DIR; "/images/folder.svg"
+            when :UP;  "/images/return.svg"
+            else raise "no icon for filetype #{f[:type]}"
+            end}' />"
+    end}</td>
+    <td><a href='#{key}'>#{
+      if key == ".." then "[Parent Directory]" else key end
+    }</a></td>
+    <td>#{f[:displaytime]}</td>
+    <td>#{f[:displaysize]}</td>
+  EOF
+end
+%>
+<table class='filelist' clicky='name'>
+  <thead>
+    <tr>
+      <th />
+      <th clicky='name'>Name</th>
+      <th clicky='date'>Last Modified</th>
+      <th clicky='size'>Size</th>
+    </tr>
+  </thead>
+  <tbody>
+<%=
+    parentrow = if files[".."] then "#{render_entry(files, "..")}" end
+    files.delete("..")
+    if parentrow then "<tr>#{parentrow}</tr>" end
+%>
+<%
+by_name = files.keys.sort{ |a, b| strverscmp(a, b) }
+by_name.each do |key|
+  entry = render_entry(files, key)
+%>
+    <tr><%= entry %></tr>
+<% end %>
+  </tbody>
+
+  <tbody>
+<%
+def meta_cmp(files, key, a, b)
+  av, bv = files[a][key], files[b][key]
+  return av <=> bv if av != bv
+  return strverscmp(a, b)
+end
+
+by_date = files.keys.sort { |a, b| meta_cmp(files, :sorttime, a, b) }
+by_size = files.keys.sort { |a, b| meta_cmp(files, :size, a, b) }
+
+listnames = [ "namerev", "datefwd", "daterev", "sizefwd", "sizerev" ]
+lists = [ by_name.reverse, by_date, by_date.reverse, by_size, by_size.reverse ]
+if parentrow
+%>
+  <tr class='<%= listnames.join(" ") %>'><%= parentrow %></tr>
+<%
+end
+evenmap = (0..(lists.length-1)).map { false }
+even = false
+
+while not (elems = lists.map(&:first)).compact.empty?
+  matches = (0..(lists.length-1)).to_a.keep_if { |x| evenmap[x] == even }
+  if !matches.empty?
+    elems = elems.values_at(*matches).compact
+    mode = elems.group_by{|a| a}.max{|a, b| a[1].length <=> b[1].length}[0]
+    matches = []
+
+    lists.each_index do |i|
+      if evenmap[i] == even and lists[i].first.eql? mode
+        lists[i].shift
+        evenmap[i] ^= true
+        evenmap[i] = nil if lists[i].empty?
+
+        matches << i
+      end
+    end
+%>
+    <tr class='<%= listnames.values_at(*matches).join(" ") %>'>
+      <%= render_entry(files, mode) %>
+    </tr>
+<%
+  else
+%>
+    <tr><td /></tr>
+<%
+  end
+
+  even ^= true
+end
+%>
+  </tbody>
+</table>