[PATCH] cgit.css: add dynamic age update
John Keeping
john at keeping.me.uk
Sun Jun 24 13:52:53 CEST 2018
Subject should be "cgit.js: " not cgit.css!
On Sun, Jun 24, 2018 at 03:59:51PM +0800, Andy Green wrote:
> This patch updates the emitted "ages" dynamically on the client side.
>
> After updating on completion of the document load, it sets a timer
> to update according to the smallest age it found. If there are any
> ages listed in minutes, then it will update again in 10s (this can
> never happen more than twelve times on a given page then). When the
> most recent age is in hours, it updates every 5m. If days, then
> every 30m and so on.
>
> This keeps the cost of the dynamic updates at worst once per 10s
> and trending towards being trivially cheap after a couple of minutes.
> The updates are done entirely on the client side without contact
> with the server.
>
> To make this work reliably, since parsing datetimes is unreliable in
> browser js, the unix time is added as an attribute to all age spans.
>
> To make that reliable cross-platform, the unix time is treated as a
> uint64_t when it is formatted for printing.
>
> The rules for display conversion of the age is aligned with the
> existing server-side rules in ui-shared.h.
>
> If the client or server-side time are not synchronized by ntpd etc,
> ages shown on the client will not relate to the original ages computed
> at the server. The client updates the ages immediately when the
> DOM has finished loading, so in the case the times at the server and
> client are not aligned, this patch changes what the user sees on the
> page to reflect patch age compared to client time.
>
> If the server and client clocks are aligned, this patch makes no
> difference to what is seen on the page.
>
> Signed-off-by: Andy Green <andy at warmcat.com>
If we're going to start depending on JS, should we take the robust
approach to this and never generate relative times on the server? Or do
so only for <noscript>?
I'd really like to here other people's opinions on this.
Personally, I'm slightly negative because while I do regularly use some
sites that take this approach (including having long-lived tabs open on
pages like this), I always end up refreshing the page anyway when I go
back to the tab, because new content doesn't load without doing so.
So I'm not sure what this tells me except "it's been at least N
{seconds,minutes,hours,days} since you last refreshed this page". And
the first thing I'm going to do is hit refresh anyway.
> ---
> cgit.h | 1 +
> cgit.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ui-shared.c | 2 +-
> 3 files changed, 60 insertions(+), 1 deletion(-)
>
> diff --git a/cgit.h b/cgit.h
> index 2579ce4..9b21919 100644
> --- a/cgit.h
> +++ b/cgit.h
> @@ -24,6 +24,7 @@
> #include <utf8.h>
> #include <notes.h>
> #include <graph.h>
> +#include <inttypes.h>
>
> /* Add isgraph(x) to Git's sane ctype support (see git-compat-util.h) */
> #undef isgraph
> diff --git a/cgit.js b/cgit.js
> index e2c3799..e13faf2 100644
> --- a/cgit.js
> +++ b/cgit.js
> @@ -145,6 +145,61 @@ function cgit_line_range_click(e) {
> cgit_copy_clipboard(cp);
> }
>
> +/* this follows the logic and suffixes used in ui-shared.c */
> +
> +var cgit_age_classes = [ "age-mins", "age-hours", "age-days", "age-weeks", "age-months", "age-years" ];
> +var cgit_age_suffix = [ "min.", "hours", "days", "weeks", "months", "years", "years" ];
> +var cgit_age_next = [ 60, 3600, 24 * 3600, 7 * 24 * 3600, 30 * 24 * 3600, 365 * 24 * 3600, 365 * 24 * 3600 ];
> +var cgit_age_limit = [ 7200, 24 * 7200, 7 * 24 * 7200, 30 * 24 * 7200, 365 * 25 * 7200, 365 * 25 * 7200 ];
> +var cgit_update_next = [ 10, 5 * 60, 1800, 24 * 3600, 24 * 3600, 24 * 3600, 24 * 3600 ];
> +
> +function cgit_render_age(e, age)
> +{
> + var t, n;
> +
> + for (n = 0; n < cgit_age_classes.length; n++)
> + if (age < cgit_age_limit[n])
> + break;
> +
> + t = Math.round(age / cgit_age_next[n]) + " " + cgit_age_suffix[n];
> +
> + if (e.textContent != t) {
> + e.textContent = t;
> + if (n == cgit_age_classes.length)
> + n--;
> + if (e.className != cgit_age_classes[n])
> + e.className = cgit_age_classes[n];
> + }
> +}
> +
> +function cgit_aging()
> +{
> + var n, next = 24 * 3600,
> + now_ut = Math.round((new Date().getTime() / 1000));
> +
> + for (n = 0; n < cgit_age_classes.length; n++) {
> + var m, elems = document.getElementsByClassName(cgit_age_classes[n]);
> +
> + if (elems.length && cgit_update_next[n] < next)
> + next = cgit_update_next[n];
> +
> + for (m = 0; m < elems.length; m++) {
> + var age = now_ut - elems[m].getAttribute("ut");
> +
> + cgit_render_age(elems[m], age);
> + }
> + }
> +
> + /*
> + * We only need to come back when the age might have changed.
> + * Eg, if everything is counted in hours already, once per
> + * 5 minutes is accurate enough.
> + */
> +
> + window.setTimeout(cgit_aging, next * 1000);
> +}
> +
> +
> /* line range highlight */
>
> document.addEventListener("DOMContentLoaded", function() {
> @@ -152,6 +207,9 @@ document.addEventListener("DOMContentLoaded", function() {
> var e = document.getElementById("linenumber_td");
> if (e)
> e.addEventListener("click", cgit_line_range_click, true);
> +
> + cgit_aging();
> +
> }, false);
> window.addEventListener("hashchange", function() {
> cgit_line_range_highlight();
> diff --git a/ui-shared.c b/ui-shared.c
> index 836c590..8567c06 100644
> --- a/ui-shared.c
> +++ b/ui-shared.c
> @@ -670,7 +670,7 @@ const struct date_mode *cgit_date_mode(enum date_mode_type type)
> static void print_rel_date(time_t t, int tz, double value,
> const char *class, const char *suffix)
> {
> - htmlf("<span class='%s' title='", class);
> + htmlf("<span class='%s' ut='%" PRIu64 "' title='", class, (uint64_t)t);
> html_attr(show_date(t, tz, cgit_date_mode(DATE_ISO8601)));
> htmlf("'>%.0f %s</span>", value, suffix);
> }
>
> _______________________________________________
> CGit mailing list
> CGit at lists.zx2c4.com
> https://lists.zx2c4.com/mailman/listinfo/cgit
More information about the CGit
mailing list