Last active
December 20, 2015 00:09
-
-
Save marshall007/6039852 to your computer and use it in GitHub Desktop.
AngularJS "Time Ago" filter.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
timeAgo = angular.module 'app' | |
# Filter: time | |
# Date.parse() is inconsistent across browsers | |
# this is a shim for parsing ISO-8601 date strings | |
timeAgo.filter 'time', -> | |
(time) -> | |
return if not time | |
return time if angular.isDate time | |
return new Date time if angular.isNumber time | |
time = time.replace /\.\d+/, '' | |
time = time.replace(/-/, '/').replace /-/, '/' | |
time = time.replace(/T/, ' ').replace /Z/, ' UTC' | |
time = time.replace /([\+\-]\d\d)\:?(\d\d)/, ' $1$2' | |
time = new Date time * 1000 or time | |
# Filter: timeAgo | |
# Allows you to override any of the default templates | |
timeAgo.constant 'timeAgoTemplates', {} | |
timeAgo.filter 'timeAgo', [ | |
'timeFilter', 'timeAgoTemplates' | |
(normalize, config) -> | |
templates = | |
default: 'Never' | |
prefix: '' | |
suffix: 'ago' | |
seconds: 'less than a minute' | |
minute: 'a minute' | |
minutes: '%d minutes' | |
hour: 'an hour' | |
hours: '%d hours' | |
day: 'a day' | |
days: '%d days' | |
month: 'a month' | |
months: '%d months' | |
year: 'a year' | |
years: '%d years' | |
angular.extend templates, config | |
template = (t, n) -> | |
templates[t]?.replace /%d/i, Math.abs Math.round n | |
build = -> # (prefix, value, suffix) -> | |
args = Array.prototype.slice.call arguments, 0 | |
return args.map (a) -> | |
a.trim() | |
.join(' ').trim() | |
(time, none, prefix) -> | |
none = none or templates.default | |
prefix = prefix or templates.prefix | |
time = normalize time | |
return none if not time | |
now = new Date | |
seconds = ((now.getTime() - time) * .001) >> 0 | |
minutes = seconds / 60 | |
hours = minutes / 60 | |
days = hours / 24 | |
years = days / 365 | |
return build prefix, ( | |
seconds < 45 and template('seconds', seconds) or | |
seconds < 90 and template('minute', 1) or | |
minutes < 45 and template('minutes', minutes) or | |
minutes < 90 and template('hour', 1) or | |
hours < 24 and template('hours', hours) or | |
hours < 42 and template('day', 1) or | |
days < 30 and template('days', days) or | |
days < 45 and template('month', 1) or | |
days < 365 and template('months', days / 30) or | |
years < 1.5 and template('year', 1) or | |
template 'years', years | |
), templates.suffix | |
] | |
# Directive: <time-ago> | |
timeAgo.directive 'timeAgo', [ | |
'$interval', 'timeFilter', | |
($interval, normalize) -> | |
restrict: 'E' | |
replace: true | |
scope: | |
default: '@' | |
prefix: '@' | |
time: '=' | |
template: """ | |
<time datetime="{{ time }}" | |
title="{{ time | date:'short' }}"> | |
{{ time | timeAgo:default:prefix }} | |
</time> | |
""" | |
link: (scope) -> | |
clear = null | |
scope.$watch 'time', (value) -> | |
$interval.cancel clear if clear | |
hours = (Date.now() - normalize value) / 3600000 | |
# update every 30 seconds if less than an hour has passed | |
if hours < 1 | |
clear = $interval angular.noop, 30000 | |
] |
awesome, modified it a bit to create an auto updating directive
<timeago time="post.created_on"></timeago>
angular.module('app').directive 'timeago', ->
templates =
seconds: 'a few seconds ago'
minute: 'a minute ago'
minutes: '%d minutes ago'
hour: 'an hour ago'
hours: '%d hours ago'
day: 'a day ago'
days: '%d days ago'
month: 'a month ago'
months: '%d months ago'
year: 'a year ago'
years: '%d years ago'
# replace %d with a value
template = (name, value) ->
templates[name]?.replace /%d/i, Math.abs(Math.round(value))
# generate time ago string
getTimeAgo = (time) ->
if not time then return 'Never'
time = time.replace /\.\d+/, ''
time = time.replace(/-/, '/').replace /-/, '/'
time = time.replace(/T/, ' ').replace /Z/, ' UTC'
time = time.replace /([\+\-]\d\d)\:?(\d\d)/, ' $1$2'
time = new Date time * 1000 || time
now = new Date
seconds = ((now.getTime() - time) * .001) >> 0
minutes = seconds / 60
hours = minutes / 60
days = hours / 24
years = days / 365
if seconds < 30 then return template 'seconds', seconds
if seconds < 90 then return template 'minute', 1
if minutes < 45 then return template 'minutes', minutes
if minutes < 90 then return template 'hour', 1
if hours < 24 then return template 'hours', hours
if hours < 42 then return template 'day', 1
if days < 30 then return template 'days', days
if days < 45 then return template 'month', 1
if days < 365 then return template 'months', days/30
if years < 1.5 then return template 'year', 1
return template 'years', years
restrict: 'E'
replace: true
template: '<time datetime="{{time}}" title="{{time|date:\'medium\'}}">{{timeago}}</time>'
scope:
time: "="
controller: ['$scope','$interval', ($scope, $interval)->
$scope.timeago = getTimeAgo($scope.time)
$interval(->
$scope.timeago = getTimeAgo($scope.time)
, 5000)
]
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Inspired by https://coderwall.com/p/uub3pw