github.com/wtsi-ssg/wrstat@v1.1.4-0.20221008232152-3030622a8cf8/server/static/tree/js/jquery.timeago.js (about)

     1  /**
     2   * Timeago is a jQuery plugin that makes it easy to support automatically
     3   * updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
     4   *
     5   * @name timeago
     6   * @version 1.6.7
     7   * @requires jQuery >=1.5.0 <4.0
     8   * @author Ryan McGeary
     9   * @license MIT License - http://www.opensource.org/licenses/mit-license.php
    10   *
    11   * For usage and examples, visit:
    12   * http://timeago.yarp.com/
    13   *
    14   * Copyright (c) 2008-2019, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
    15   */
    16  
    17  (function (factory) {
    18    if (typeof define === 'function' && define.amd) {
    19      // AMD. Register as an anonymous module.
    20      define(['jquery'], factory);
    21    } else if (typeof module === 'object' && typeof module.exports === 'object') {
    22      factory(require('jquery'));
    23    } else {
    24      // Browser globals
    25      factory(jQuery);
    26    }
    27  }(function ($) {
    28    $.timeago = function (timestamp) {
    29      if (timestamp instanceof Date) {
    30        return inWords(timestamp);
    31      } else if (typeof timestamp === "string") {
    32        return inWords($.timeago.parse(timestamp));
    33      } else if (typeof timestamp === "number") {
    34        return inWords(new Date(timestamp));
    35      } else {
    36        return inWords($.timeago.datetime(timestamp));
    37      }
    38    };
    39    var $t = $.timeago;
    40  
    41    $.extend($.timeago, {
    42      settings: {
    43        refreshMillis: 60000,
    44        allowPast: true,
    45        allowFuture: false,
    46        localeTitle: false,
    47        cutoff: 0,
    48        autoDispose: true,
    49        strings: {
    50          prefixAgo: null,
    51          prefixFromNow: null,
    52          suffixAgo: "ago",
    53          suffixFromNow: "from now",
    54          inPast: "any moment now",
    55          seconds: "< a minute",
    56          minute: "~ a minute",
    57          minutes: "%d minutes",
    58          hour: "~ an hour",
    59          hours: "~ %d hours",
    60          day: "a day",
    61          days: "%d days",
    62          month: "~ a month",
    63          months: "%d months",
    64          year: "~ a year",
    65          years: "%d years",
    66          wordSeparator: " ",
    67          numbers: []
    68        }
    69      },
    70  
    71      inWords: function (distanceMillis) {
    72        if (!this.settings.allowPast && !this.settings.allowFuture) {
    73          throw 'timeago allowPast and allowFuture settings can not both be set to false.';
    74        }
    75  
    76        var $l = this.settings.strings;
    77        var prefix = $l.prefixAgo;
    78        var suffix = $l.suffixAgo;
    79        if (this.settings.allowFuture) {
    80          if (distanceMillis < 0) {
    81            prefix = $l.prefixFromNow;
    82            suffix = $l.suffixFromNow;
    83          }
    84        }
    85  
    86        if (!this.settings.allowPast && distanceMillis >= 0) {
    87          return this.settings.strings.inPast;
    88        }
    89  
    90        var seconds = Math.abs(distanceMillis) / 1000;
    91        var minutes = seconds / 60;
    92        var hours = minutes / 60;
    93        var days = hours / 24;
    94        var years = days / 365;
    95  
    96        function substitute(stringOrFunction, number) {
    97          var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
    98          var value = ($l.numbers && $l.numbers[number]) || number;
    99          return string.replace(/%d/i, value);
   100        }
   101  
   102        var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
   103          seconds < 90 && substitute($l.minute, 1) ||
   104          minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
   105          minutes < 90 && substitute($l.hour, 1) ||
   106          hours < 24 && substitute($l.hours, Math.round(hours)) ||
   107          hours < 42 && substitute($l.day, 1) ||
   108          days < 30 && substitute($l.days, Math.round(days)) ||
   109          days < 45 && substitute($l.month, 1) ||
   110          days < 365 && substitute($l.months, Math.round(days / 30)) ||
   111          years < 1.5 && substitute($l.year, 1) ||
   112          substitute($l.years, Math.round(years));
   113  
   114        var separator = $l.wordSeparator || "";
   115        if ($l.wordSeparator === undefined) { separator = " "; }
   116        return $.trim([prefix, words, suffix].join(separator));
   117      },
   118  
   119      parse: function (iso8601) {
   120        var s = $.trim(iso8601);
   121        s = s.replace(/\.\d+/, ""); // remove milliseconds
   122        s = s.replace(/-/, "/").replace(/-/, "/");
   123        s = s.replace(/T/, " ").replace(/Z/, " UTC");
   124        s = s.replace(/([\+\-]\d\d)\:?(\d\d)/, " $1$2"); // -04:00 -> -0400
   125        s = s.replace(/([\+\-]\d\d)$/, " $100"); // +09 -> +0900
   126        return new Date(s);
   127      },
   128      datetime: function (elem) {
   129        var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
   130        return $t.parse(iso8601);
   131      },
   132      isTime: function (elem) {
   133        // jQuery's `is()` doesn't play well with HTML5 in IE
   134        return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
   135      }
   136    });
   137  
   138    // functions that can be called via $(el).timeago('action')
   139    // init is default when no action is given
   140    // functions are called with context of a single element
   141    var functions = {
   142      init: function () {
   143        functions.dispose.call(this);
   144        var refresh_el = $.proxy(refresh, this);
   145        refresh_el();
   146        var $s = $t.settings;
   147        if ($s.refreshMillis > 0) {
   148          this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
   149        }
   150      },
   151      update: function (timestamp) {
   152        var date = (timestamp instanceof Date) ? timestamp : $t.parse(timestamp);
   153        $(this).data('timeago', { datetime: date });
   154        if ($t.settings.localeTitle) {
   155          $(this).attr("title", date.toLocaleString());
   156        }
   157        refresh.apply(this);
   158      },
   159      updateFromDOM: function () {
   160        $(this).data('timeago', { datetime: $t.parse($t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title")) });
   161        refresh.apply(this);
   162      },
   163      dispose: function () {
   164        if (this._timeagoInterval) {
   165          window.clearInterval(this._timeagoInterval);
   166          this._timeagoInterval = null;
   167        }
   168      }
   169    };
   170  
   171    $.fn.timeago = function (action, options) {
   172      var fn = action ? functions[action] : functions.init;
   173      if (!fn) {
   174        throw new Error("Unknown function name '" + action + "' for timeago");
   175      }
   176      // each over objects here and call the requested function
   177      this.each(function () {
   178        fn.call(this, options);
   179      });
   180      return this;
   181    };
   182  
   183    function refresh() {
   184      var $s = $t.settings;
   185  
   186      //check if it's still visible
   187      if ($s.autoDispose && !$.contains(document.documentElement, this)) {
   188        //stop if it has been removed
   189        $(this).timeago("dispose");
   190        return this;
   191      }
   192  
   193      var data = prepareData(this);
   194  
   195      if (!isNaN(data.datetime)) {
   196        if ($s.cutoff === 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
   197          $(this).text(inWords(data.datetime));
   198        } else {
   199          if ($(this).attr('title').length > 0) {
   200            $(this).text($(this).attr('title'));
   201          }
   202        }
   203      }
   204      return this;
   205    }
   206  
   207    function prepareData(element) {
   208      element = $(element);
   209      if (!element.data("timeago")) {
   210        element.data("timeago", { datetime: $t.datetime(element) });
   211        var text = $.trim(element.text());
   212        if ($t.settings.localeTitle) {
   213          element.attr("title", element.data('timeago').datetime.toLocaleString());
   214        } else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
   215          element.attr("title", text);
   216        }
   217      }
   218      return element.data("timeago");
   219    }
   220  
   221    function inWords(date) {
   222      return $t.inWords(distance(date));
   223    }
   224  
   225    function distance(date) {
   226      return (new Date().getTime() - date.getTime());
   227    }
   228  
   229    // fix for IE6 suckage
   230    document.createElement("abbr");
   231    document.createElement("time");
   232  }));