[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