Skip to content

Commit

Permalink
dashboard: make timeago dynamic using jquery + timeago
Browse files Browse the repository at this point in the history
  • Loading branch information
pommi committed Dec 13, 2014
1 parent 5c7fccf commit 6c39bf0
Show file tree
Hide file tree
Showing 3 changed files with 227 additions and 1 deletion.
5 changes: 4 additions & 1 deletion inc/html.inc.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ function html_start() {
}

echo <<<EOT
<script type="text/javascript" src="//code.jquery.com/jquery-2.1.1.min.js"></script>

This comment has been minimized.

Copy link
@Lekensteyn

Lekensteyn Dec 13, 2014

Contributor

Hmm, this is the first external dependency, slowing down loading and breaking internal (offline) monitoring. What about using VanillaJS or including the jquery dependency in-tree? Maybe even allow disabling this option as it is not the end of the world when the time is not updated.

This comment has been minimized.

Copy link
@pommi

pommi Dec 14, 2014

Author Owner

Agreed on external dependency (acef029).

VanillaJS, no, but I understand where you're coming from. I also was against including jquery because it would be overkill, but it's just way more easy to include 3rd party open source javascript, depending on jquery, than writing all javascript yourself. jquery adds another 83K, that is a lot. But a small graph is also already ~30K and a large one ~60K, or an RRD file ~432K (load.rrd). And when you configure your webserver correctly the jquery file is downloaded once to your browser and cached for x time.

This comment has been minimized.

Copy link
@Lekensteyn

Lekensteyn Dec 14, 2014

Contributor

Related: #15

My main concern was the external (non-local) dependency, but that is fixed now. Thanks!

<script type="text/javascript" src="{$html_weburl}js/jquery.timeago.js"></script>
</head>
<body>
Expand Down Expand Up @@ -291,7 +293,8 @@ function host_summary($cat, $hosts) {
elseif ($time > 60)
$class .= ' warn';

printf('<td class="%s">%d seconds ago</td>',$class, $time);
printf('<td class="%s"><time class="timeago" datetime="%s">%d seconds ago</time></td>',
$class, date('c', $rrd_info['last_update']), $time);
}

print "</tr>\n";
Expand Down
9 changes: 9 additions & 0 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,13 @@
host_summary('uncategorized', $uhosts);
}

echo <<<EOT
<script>
jQuery(document).ready(function() {
jQuery("time.timeago").timeago();
});
</script>
EOT;

html_end();
214 changes: 214 additions & 0 deletions js/jquery.timeago.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
/**
* Timeago is a jQuery plugin that makes it easy to support automatically
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
*
* @name timeago
* @version 1.4.1
* @requires jQuery v1.2.3+
* @author Ryan McGeary
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
*
* For usage and examples, visit:
* http://timeago.yarp.com/
*
* Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
*/

(function (factory) {
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], factory);
} else {
// Browser globals
factory(jQuery);
}
}(function ($) {
$.timeago = function(timestamp) {
if (timestamp instanceof Date) {
return inWords(timestamp);
} else if (typeof timestamp === "string") {
return inWords($.timeago.parse(timestamp));
} else if (typeof timestamp === "number") {
return inWords(new Date(timestamp));
} else {
return inWords($.timeago.datetime(timestamp));
}
};
var $t = $.timeago;

$.extend($.timeago, {
settings: {
refreshMillis: 60000,
allowPast: true,
allowFuture: false,
localeTitle: false,
cutoff: 0,
strings: {
prefixAgo: null,
prefixFromNow: null,
suffixAgo: "ago",
suffixFromNow: "from now",
inPast: 'any moment now',
seconds: "less than a minute",
minute: "about a minute",
minutes: "%d minutes",
hour: "about an hour",
hours: "about %d hours",
day: "a day",
days: "%d days",
month: "about a month",
months: "%d months",
year: "about a year",
years: "%d years",
wordSeparator: " ",
numbers: []
}
},

inWords: function(distanceMillis) {
if(!this.settings.allowPast && ! this.settings.allowFuture) {
throw 'timeago allowPast and allowFuture settings can not both be set to false.';
}

var $l = this.settings.strings;
var prefix = $l.prefixAgo;
var suffix = $l.suffixAgo;
if (this.settings.allowFuture) {
if (distanceMillis < 0) {
prefix = $l.prefixFromNow;
suffix = $l.suffixFromNow;
}
}

if(!this.settings.allowPast && distanceMillis >= 0) {
return this.settings.strings.inPast;
}

var seconds = Math.abs(distanceMillis) / 1000;
var minutes = seconds / 60;
var hours = minutes / 60;
var days = hours / 24;
var years = days / 365;

function substitute(stringOrFunction, number) {
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
var value = ($l.numbers && $l.numbers[number]) || number;
return string.replace(/%d/i, value);
}

var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
seconds < 90 && substitute($l.minute, 1) ||
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
minutes < 90 && substitute($l.hour, 1) ||
hours < 24 && substitute($l.hours, Math.round(hours)) ||
hours < 42 && substitute($l.day, 1) ||
days < 30 && substitute($l.days, Math.round(days)) ||
days < 45 && substitute($l.month, 1) ||
days < 365 && substitute($l.months, Math.round(days / 30)) ||
years < 1.5 && substitute($l.year, 1) ||
substitute($l.years, Math.round(years));

var separator = $l.wordSeparator || "";
if ($l.wordSeparator === undefined) { separator = " "; }
return $.trim([prefix, words, suffix].join(separator));
},

parse: function(iso8601) {
var s = $.trim(iso8601);
s = s.replace(/\.\d+/,""); // remove milliseconds
s = s.replace(/-/,"/").replace(/-/,"/");
s = s.replace(/T/," ").replace(/Z/," UTC");
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
return new Date(s);
},
datetime: function(elem) {
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
return $t.parse(iso8601);
},
isTime: function(elem) {
// jQuery's `is()` doesn't play well with HTML5 in IE
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
}
});

// functions that can be called via $(el).timeago('action')
// init is default when no action is given
// functions are called with context of a single element
var functions = {
init: function(){
var refresh_el = $.proxy(refresh, this);
refresh_el();
var $s = $t.settings;
if ($s.refreshMillis > 0) {
this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
}
},
update: function(time){
var parsedTime = $t.parse(time);
$(this).data('timeago', { datetime: parsedTime });
if($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleString());
refresh.apply(this);
},
updateFromDOM: function(){
$(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
refresh.apply(this);
},
dispose: function () {
if (this._timeagoInterval) {
window.clearInterval(this._timeagoInterval);
this._timeagoInterval = null;
}
}
};

$.fn.timeago = function(action, options) {
var fn = action ? functions[action] : functions.init;
if(!fn){
throw new Error("Unknown function name '"+ action +"' for timeago");
}
// each over objects here and call the requested function
this.each(function(){
fn.call(this, options);
});
return this;
};

function refresh() {
var data = prepareData(this);
var $s = $t.settings;

if (!isNaN(data.datetime)) {
if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
$(this).text(inWords(data.datetime));
}
}
return this;
}

function prepareData(element) {
element = $(element);
if (!element.data("timeago")) {
element.data("timeago", { datetime: $t.datetime(element) });
var text = $.trim(element.text());
if ($t.settings.localeTitle) {
element.attr("title", element.data('timeago').datetime.toLocaleString());
} else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
element.attr("title", text);
}
}
return element.data("timeago");
}

function inWords(date) {
return $t.inWords(distance(date));
}

function distance(date) {
return (new Date().getTime() - date.getTime());
}

// fix for IE6 suckage
document.createElement("abbr");
document.createElement("time");
}));

0 comments on commit 6c39bf0

Please sign in to comment.