commit ff291d6c72608cbd385874f6cf66ba2662ed2b75
parent f6c99b65e4ee7c0dd648f7582ef848e5e3a13524
Author: Michael Skec
Date: Sat, 11 Nov 2023 18:27:07 +1100
Implement client-side commit age
Now shows age/idle time of commits/repositories using some ugly
JavaScript. Looks alright for now.
Diffstat:
M | stagit-index.c | | | 64 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---- |
M | stagit.c | | | 84 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ |
2 files changed, 132 insertions(+), 16 deletions(-)
diff --git a/stagit-index.c b/stagit-index.c
@@ -90,7 +90,12 @@ printtimeshort(FILE *fp, const git_time *intime)
if (!(intm = gmtime(&t)))
return;
//strftime(out, sizeof(out), "%Y-%m-%d %H:%M", intm);
- strftime(out, sizeof(out), "%Y-%m-%d", intm);
+ //strftime(out, sizeof(out), "%Y-%m-%d", intm);
+
+ /* ISO-8601 UTC time which we convert to the local time on the page using a
+ * little bit of JavaScript. */
+ strftime(out, sizeof(out), "%Y-%m-%dT%H:%M:%S.000Z", intm);
+
fputs(out, fp);
}
@@ -105,6 +110,7 @@ writeheader(FILE *fp)
xmlencode(fp, title, strlen(title));
fprintf(fp, "</title>\n<link rel=\"icon\" type=\"image/png\" href=\"%sfavicon.png\" />\n", relpath);
fprintf(fp, "<link rel=\"stylesheet\" type=\"text/css\" href=\"%sstyle.css\" />\n", relpath);
+
fputs("</head>\n<body>\n", fp);
#if LOGO
fprintf(fp, "<table>\n<tr><td><img src=\"%slogo.png\" alt=\"\" width=\"32\" height=\"32\" /></td>\n"
@@ -118,14 +124,64 @@ writeheader(FILE *fp)
"</td></tr>\n</table>\n<hr/>\n<div id=\"content\">\n"
"<table id=\"index\"><thead>\n"
"<tr><td><b>Name</b></td><td><b>Description</b></td><td><b>Owner</b></td>"
- "<td><b>Latest commit</b></td></tr>"
+ "<td><b class=\"date-idle\">Latest commit</b></td></tr>"
"</thead><tbody>\n", fp);
}
void
writefooter(FILE *fp)
{
- fputs("</tbody>\n</table>\n</div>\n</body>\n</html>\n", fp);
+ //fputs("</tbody>\n</table>\n</div>\n</body>\n</html>\n", fp);
+ fputs("</tbody>\n</table>\n</div>\n", fp);
+
+ /* Some client-side JS that converts our UTC date strings to a more logical 'age' string. */
+ fputs(
+ "<script type=\"text/javascript\">"
+ "/* Set date-idle titles */"
+ "var date_idles = document.getElementsByClassName(\"date-idle\");"
+ "for (var i = 0; i < date_idles.length; ++i)"
+ "{"
+ "date_idles[i].innerHTML = \"Idle\";"
+ "}"
+ ""
+ "/* Convert UTC dates to age strings */"
+ "var now = Date.now();"
+ "var utctimes = document.getElementsByClassName(\"age\");"
+ "for (var i = 0; i < utctimes.length; ++i)"
+ "{"
+ "var t = new Date(utctimes[i].innerHTML);"
+ "var secs = Math.abs(now - t) / 1000;"
+ "if (secs < 2 * 60 * 60) /* last two hours -- print minutes */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / 60).toString() + \" min.\";"
+ "continue;"
+ "}"
+ "if (secs < 2 * 60 * 60 * 24) /* last two days -- print hours */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60)).toString() + \" hours\";"
+ "continue;"
+ "}"
+ "if (secs < 2 * 60 * 60 * 24 * 7) /* last two weeks -- print days */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24)).toString() + \" days\";"
+ "continue;"
+ "}"
+ "if (secs < 2 * 60 * 60 * 24 * 30) /* last two months -- print weeks */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 7)).toString() + \" weeks\";"
+ "continue;"
+ "}"
+ "if (secs < 2 * 60 * 60 * 24 * 365) /* last two years -- print months */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 30)).toString() + \" months\";"
+ "continue;"
+ "}"
+ "/* print years */"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 365)).toString() + \" years\";"
+ "}"
+ "</script>", fp);
+
+ fputs("</body>\n</html>\n", fp);
}
int
@@ -170,7 +226,7 @@ writelog(FILE *fp)
xmlencode(fp, description, strlen(description));
fputs("</td><td>", fp);
xmlencode(fp, owner, strlen(owner));
- fputs("</td><td>", fp);
+ fputs("</td><td class=\"age\">", fp);
if (author)
printtimeshort(fp, &(author->when));
fputs("</td></tr>", fp);
diff --git a/stagit.c b/stagit.c
@@ -5,6 +5,7 @@
#include <errno.h>
#include <libgen.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -494,7 +495,12 @@ printtimeshort(FILE *fp, const git_time *intime)
t = (time_t)intime->time;
if (!(intm = gmtime(&t)))
return;
- strftime(out, sizeof(out), "%Y-%m-%d %H:%M", intm);
+ //strftime(out, sizeof(out), "%Y-%m-%d %H:%M", intm);
+
+ /* ISO-8601 UTC time which we convert to the local time on the page using a
+ * little bit of JavaScript. */
+ strftime(out, sizeof(out), "%Y-%m-%dT%H:%M:%S.000Z", intm);
+
fputs(out, fp);
}
@@ -578,9 +584,63 @@ writeheader(FILE *fp, const char *title)
}
void
-writefooter(FILE *fp)
+writefooter(FILE *fp, bool age_js)
{
- fputs("</div>\n</body>\n</html>\n", fp);
+ //fputs("</div>\n</body>\n</html>\n", fp);
+
+ fputs("</div>\n", fp);
+
+ if (age_js)
+ {
+ /* Some client-side JS that converts our UTC date strings to a more logical 'age' string. */
+ fputs(
+ "<script type=\"text/javascript\">"
+ "/* Set date-age titles */"
+ "var date_ages = document.getElementsByClassName(\"date-age\");"
+ "for (var i = 0; i < date_ages.length; ++i)"
+ "{"
+ "date_ages[i].innerHTML = \"Age\";"
+ "}"
+ ""
+ "/* Convert UTC dates to age strings */"
+ "var now = Date.now();"
+ "var utctimes = document.getElementsByClassName(\"age\");"
+ "for (var i = 0; i < utctimes.length; ++i)"
+ "{"
+ "var t = new Date(utctimes[i].innerHTML);"
+ "var secs = Math.abs(now - t) / 1000;"
+ "if (secs < 2 * 60 * 60) /* last two hours -- print minutes */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / 60).toString() + \" min.\";"
+ "continue;"
+ "}"
+ "if (secs < 2 * 60 * 60 * 24) /* last two days -- print hours */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60)).toString() + \" hours\";"
+ "continue;"
+ "}"
+ "if (secs < 2 * 60 * 60 * 24 * 7) /* last two weeks -- print days */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24)).toString() + \" days\";"
+ "continue;"
+ "}"
+ "if (secs < 2 * 60 * 60 * 24 * 30) /* last two months -- print weeks */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 7)).toString() + \" weeks\";"
+ "continue;"
+ "}"
+ "if (secs < 2 * 60 * 60 * 24 * 365) /* last two years -- print months */"
+ "{"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 30)).toString() + \" months\";"
+ "continue;"
+ "}"
+ "/* print years */"
+ "utctimes[i].innerHTML = Math.round(secs / (60 * 60 * 24 * 365)).toString() + \" years\";"
+ "}"
+ "</script>", fp);
+ }
+
+ fputs("</body>\n</html>\n", fp);
}
size_t
@@ -830,7 +890,7 @@ printshowfile(FILE *fp, struct commitinfo *ci)
void
writelogline(FILE *fp, struct commitinfo *ci)
{
- fputs("<tr><td>", fp);
+ fputs("<tr><td class=\"age\">", fp);
if (ci->author)
printtimeshort(fp, &(ci->author->when));
fputs("</td><td>", fp);
@@ -908,7 +968,7 @@ writelog(FILE *fp, const git_oid *oid)
fputs("<pre>", fpfile);
printshowfile(fpfile, ci);
fputs("</pre>\n", fpfile);
- writefooter(fpfile);
+ writefooter(fpfile, false);
checkfileerror(fpfile, path, 'w');
fclose(fpfile);
}
@@ -1072,7 +1132,7 @@ writeblob(git_object *obj, const char *fpath, const char *filename, size_t files
else
lc = writeblobhtml(fp, (git_blob *)obj);
- writefooter(fp);
+ writefooter(fp, false);
checkfileerror(fp, fpath, 'w');
fclose(fp);
@@ -1242,7 +1302,7 @@ writerefs(FILE *fp)
if (++count == 1) {
fprintf(fp, "<h2>%s</h2><table id=\"%s\">"
"<thead>\n<tr><td><b>Name</b></td>"
- "<td><b>Latest commit</b></td>"
+ "<td><b class=\"date-age\">Latest commit</b></td>"
"<td><b>Author</b></td>\n</tr>\n"
"</thead><tbody>\n",
titles[j], ids[j]);
@@ -1253,7 +1313,7 @@ writerefs(FILE *fp)
fputs("<tr><td>", fp);
xmlencode(fp, s, strlen(s));
- fputs("</td><td>", fp);
+ fputs("</td><td class=\"age\">", fp);
if (ci->author)
printtimeshort(fp, &(ci->author->when));
fputs("</td><td>", fp);
@@ -1418,7 +1478,7 @@ main(int argc, char *argv[])
relpath = "";
mkdir("commit", S_IRWXU | S_IRWXG | S_IRWXO);
writeheader(fp, NULL);
- fputs("<table id=\"log\"><thead>\n<tr><td><b>Date</b></td>"
+ fputs("<table id=\"log\"><thead>\n<tr><td><b class=\"date-age\">Latest commit</b></td>"
"<td><b>Commit message</b></td>"
"<td><b>Author</b></td><td class=\"num\" align=\"right\"><b>Files</b></td>"
"<td class=\"num\" align=\"right\"><b>+</b></td>"
@@ -1465,7 +1525,7 @@ main(int argc, char *argv[])
}
fputs("</tbody></table>", fp);
- writefooter(fp);
+ writefooter(fp, true);
checkfileerror(fp, "log.html", 'w');
fclose(fp);
@@ -1474,7 +1534,7 @@ main(int argc, char *argv[])
writeheader(fp, NULL);
if (head)
writefiles(fp, head);
- writefooter(fp);
+ writefooter(fp, false);
checkfileerror(fp, "files.html", 'w');
fclose(fp);
@@ -1482,7 +1542,7 @@ main(int argc, char *argv[])
fp = efopen("refs.html", "w");
writeheader(fp, NULL);
writerefs(fp);
- writefooter(fp);
+ writefooter(fp, true);
checkfileerror(fp, "refs.html", 'w');
fclose(fp);