local_time 0.3.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/MIT-LICENSE +1 -1
- data/README.md +63 -13
- data/app/assets/javascripts/local_time.js.coffee +48 -13
- data/app/helpers/local_time_helper.rb +30 -8
- data/test/helpers/local_time_helper_test.rb +29 -1
- data/test/javascripts/{index.js.coffee → local_time/index.js.coffee} +11 -6
- data/test/javascripts/{unit → local_time}/local_time_test.js.coffee +1 -1
- data/test/javascripts/{unit → local_time}/page_events_test.js.coffee +0 -5
- data/test/javascripts/local_time/public_api_test.js.coffee +11 -0
- data/test/javascripts/local_time/relative_date_test.js.coffee +65 -0
- data/test/javascripts/{unit → local_time}/strftime_test.js.coffee +10 -2
- data/test/javascripts/{unit → local_time}/time_ago_test.js.coffee +0 -0
- data/test/javascripts/{config.ru → runner/config.ru} +2 -3
- data/test/javascripts/{index.html → runner/index.html} +2 -2
- data/test/javascripts/vendor/moment.js +6 -0
- data/test/javascripts/vendor/qunit.css +244 -0
- data/test/javascripts/vendor/qunit.js +2212 -0
- data/test/javascripts/vendor/run-qunit.coffee +50 -0
- data/test/javascripts/vendor/sinon-timers.js +385 -0
- metadata +32 -20
- data/test/javascripts/unit/public_api_test.js.coffee +0 -21
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d42dfef630d09374cd897d5a842566191ff07cd
|
4
|
+
data.tar.gz: 671f048d37ba09ade8df1e01dd8c4bb36f5ccfab
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6209af737d470ff029db6233ca5f30e6840e8e74c40db30aca1a8ad9a592dbd705ea2159ff16eb37118946dee8d6f6db1fbfd69d6f129d30b9aab1c3f3a93b18
|
7
|
+
data.tar.gz: 26786c11ec81af062927263f55e5f4103532dbdc871d535e0e272a5c95b8a94f6e8979d165154330c3bc2cc0b93ac202f4202546f04258012e75b82d4c1d8ce1
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -1,11 +1,16 @@
|
|
1
|
-
Local Time is a Rails engine with helpers and JavaScript for displaying times and dates to users in their local time. The helpers render a `<time>` element
|
1
|
+
Local Time is a Rails engine with helpers and JavaScript for displaying times and dates to users in their local time. The helpers render a `<time>` element and the JavaScript swoops in to convert and format. The helper output is ideal for caching since it's always in UTC time.
|
2
2
|
|
3
3
|
---
|
4
4
|
|
5
5
|
####Example
|
6
6
|
|
7
|
+
```ruby
|
8
|
+
> comment.created_at
|
9
|
+
"Wed, 27 Nov 2013 18:43:22 EST -0500"
|
10
|
+
```
|
11
|
+
|
7
12
|
```erb
|
8
|
-
<%= local_time(comment.created_at)
|
13
|
+
<%= local_time(comment.created_at) %>
|
9
14
|
```
|
10
15
|
|
11
16
|
Renders:
|
@@ -22,6 +27,7 @@ When the DOM loads, the content is immediately replaced with a local, formatted
|
|
22
27
|
<time data-format="%B %e, %Y %l:%M%P"
|
23
28
|
data-local="time"
|
24
29
|
datetime="2013-11-27T23:43:22Z"
|
30
|
+
title="November 27, 2013 6:43pm EDT"
|
25
31
|
data-localized="true">November 27, 2013 6:43pm</time>
|
26
32
|
```
|
27
33
|
|
@@ -30,21 +36,36 @@ When the DOM loads, the content is immediately replaced with a local, formatted
|
|
30
36
|
#### Time and date helpers
|
31
37
|
|
32
38
|
```erb
|
33
|
-
|
34
|
-
|
39
|
+
<%= local_time(time) %>
|
40
|
+
```
|
41
|
+
|
42
|
+
Format with a strftime string (default format shown here)
|
43
|
+
|
44
|
+
```erb
|
45
|
+
<%= local_time(time, '%B %e, %Y %l:%M%P') %>
|
46
|
+
```
|
47
|
+
|
48
|
+
Alias for `local_time` with a month-formatted default
|
49
|
+
|
50
|
+
```erb
|
51
|
+
<%= local_date(time, '%B %e, %Y') %>
|
52
|
+
```
|
53
|
+
|
54
|
+
To set attributes on the time tag, pass a hash as the second argument with a `:format` key and your attributes.
|
35
55
|
|
36
|
-
|
37
|
-
<%=
|
56
|
+
```erb
|
57
|
+
<%= local_time(time, format: '%B %e, %Y %l:%M%P', class: 'my-time') %>
|
38
58
|
```
|
39
59
|
|
40
60
|
To use a strftime format already defined in your app, pass a symbol as the format.
|
61
|
+
|
41
62
|
```erb
|
42
|
-
<%= local_time(date,
|
63
|
+
<%= local_time(date, :long) %>
|
43
64
|
```
|
44
65
|
|
45
66
|
`I18n.t("time.formats.#{format}")`, `I18n.t("date.formats.#{format}")`, `Time::DATE_FORMATS[format]`, and `Date::DATE_FORMATS[format]` will be scanned (in that order) for your format.
|
46
67
|
|
47
|
-
Note: The included strftime JavaScript implementation is not 100% complete. It supports the following directives: `%a %A %b %B %c %d %e %H %I %l %m %M %p %P %S %w %y %Y`
|
68
|
+
Note: The included strftime JavaScript implementation is not 100% complete. It supports the following directives: `%a %A %b %B %c %d %e %H %I %l %m %M %p %P %S %w %y %Y %Z`
|
48
69
|
|
49
70
|
#### Time ago helper
|
50
71
|
|
@@ -52,7 +73,9 @@ Note: The included strftime JavaScript implementation is not 100% complete. It s
|
|
52
73
|
<%= local_time_ago(time) %>
|
53
74
|
```
|
54
75
|
|
55
|
-
Displays the relative amount of time passed. With age, the descriptions transition from
|
76
|
+
Displays the relative amount of time passed. With age, the descriptions transition from {quantity of seconds, minutes, or hours} to {date + time} to {date}. The `<time>` elements are updated every 60 seconds.
|
77
|
+
|
78
|
+
Examples (in quotes):
|
56
79
|
|
57
80
|
* Recent: "a second ago", "32 seconds ago", "an hour ago", "14 hours ago"
|
58
81
|
* Yesterday: "yesterday at 5:22pm"
|
@@ -60,6 +83,22 @@ Displays the relative amount of time passed. With age, the descriptions transiti
|
|
60
83
|
* This year: "on Nov 17"
|
61
84
|
* Last year: "on Jan 31, 2012"
|
62
85
|
|
86
|
+
#### Relative time helper
|
87
|
+
|
88
|
+
Preset time and date formats that vary with age. The available types are `date`, `time-ago`, `time-or-date`, and `weekday`. Like the `local_time` helper, `:type` can be passed a string or in an options hash.
|
89
|
+
|
90
|
+
```erb
|
91
|
+
<%= local_relative_time(time, 'weekday') %>
|
92
|
+
<%= local_relative_time(time, type: 'time-or-date') %>
|
93
|
+
```
|
94
|
+
|
95
|
+
**Available `:type` options**
|
96
|
+
|
97
|
+
* `date` Inlcudes the year unless it's current. "Apr 11" or "Apr 11, 2013"
|
98
|
+
* `time-ago` See above. `local_time_ago` calls `local_relative_time` with this `:type` option.
|
99
|
+
* `time-or-date` Displays the time if it's todday. Displays time otherwise. "3:26pm" or "Apr 11"
|
100
|
+
* `weekday` Displays "Today", "Yesterday", or the weekday (e.g. Wednesday) if the time is within a week of today.
|
101
|
+
|
63
102
|
#### Installation
|
64
103
|
|
65
104
|
1. Add `gem 'local_time'` to your Gemfile.
|
@@ -72,18 +111,29 @@ The included JavaScript does not depend on any frameworks or libraries, and list
|
|
72
111
|
|
73
112
|
#### JavaScript API
|
74
113
|
|
75
|
-
`
|
114
|
+
`relativeDate`, `relativeTimeAgo`, `relativeTimeOrDate`, `relativeWeekday`, `run`, and `strftime` methods are available on the global `LocalTime` object.
|
76
115
|
|
77
116
|
```js
|
78
|
-
> LocalTime.strftime(new Date, "%B %e, %Y %l:%M%P")
|
79
|
-
"February 9, 2014 12:55pm"
|
80
|
-
|
81
117
|
> LocalTime.relativeTimeAgo(new Date(new Date - 60 * 1000 * 5))
|
82
118
|
"5 minutes ago"
|
119
|
+
|
120
|
+
// Process <time> tags. Equivalent to dispatching a "time:elapse" Event.
|
121
|
+
> LocalTime.run()
|
122
|
+
|
123
|
+
> LocalTime.strftime(new Date, "%B %e, %Y %l:%M%P")
|
124
|
+
"February 9, 2014 12:55pm"
|
83
125
|
```
|
84
126
|
|
85
127
|
#### Version History
|
86
128
|
|
129
|
+
**1.0.0** (April 12, 2014)
|
130
|
+
|
131
|
+
* Added `local_relative_time` helper with several built in types
|
132
|
+
* Allow `:format` (and `:type`) option as a bare string or value in hash
|
133
|
+
* Added `relativeDate`, `relativeTimeOrDate`, `relativeWeekday` and `run` to the API
|
134
|
+
* Dropped ineffective `popstate` event listener
|
135
|
+
* Now in use at [Basecamp](https://basecamp.com/)
|
136
|
+
|
87
137
|
**0.3.0** (February 9, 2014)
|
88
138
|
|
89
139
|
* Allow :format option lookup in I18n or DATE_FORMATS hashes [Paul Dobbins]
|
@@ -30,7 +30,7 @@ strftime = (time, formatString) ->
|
|
30
30
|
minute = time.getMinutes()
|
31
31
|
second = time.getSeconds()
|
32
32
|
|
33
|
-
formatString.replace /%([%
|
33
|
+
formatString.replace /%([%aAbBcdeHIlmMpPSwyYZ])/g, ([match, modifier]) ->
|
34
34
|
switch modifier
|
35
35
|
when '%' then '%'
|
36
36
|
when 'a' then weekdays[day].slice 0, 3
|
@@ -51,6 +51,7 @@ strftime = (time, formatString) ->
|
|
51
51
|
when 'w' then day
|
52
52
|
when 'y' then pad year % 100
|
53
53
|
when 'Y' then year
|
54
|
+
when 'Z' then time.toString().match(/\((\w+)\)$/)?[1] ? ''
|
54
55
|
|
55
56
|
|
56
57
|
class CalendarDate
|
@@ -67,6 +68,16 @@ class CalendarDate
|
|
67
68
|
@year = @date.getUTCFullYear()
|
68
69
|
@month = @date.getUTCMonth() + 1
|
69
70
|
@day = @date.getUTCDate()
|
71
|
+
@value = @date.getTime()
|
72
|
+
|
73
|
+
equals: (calendarDate) ->
|
74
|
+
calendarDate?.value is @value
|
75
|
+
|
76
|
+
is: (calendarDate) ->
|
77
|
+
@equals calendarDate
|
78
|
+
|
79
|
+
isToday: ->
|
80
|
+
@is @constructor.today()
|
70
81
|
|
71
82
|
occursOnSameYearAs: (date) ->
|
72
83
|
@year is date?.year
|
@@ -82,7 +93,7 @@ class CalendarDate
|
|
82
93
|
@constructor.today().daysSince @
|
83
94
|
|
84
95
|
|
85
|
-
class
|
96
|
+
class RelativeTime
|
86
97
|
constructor: (@date) ->
|
87
98
|
@calendarDate = CalendarDate.fromDate @date
|
88
99
|
|
@@ -100,6 +111,12 @@ class RelativeTimeAgo
|
|
100
111
|
else
|
101
112
|
"on #{@formatDate()}"
|
102
113
|
|
114
|
+
toTimeOrDateString: ->
|
115
|
+
if @calendarDate.isToday()
|
116
|
+
@formatTime()
|
117
|
+
else
|
118
|
+
@formatDate()
|
119
|
+
|
103
120
|
timeElapsed: ->
|
104
121
|
ms = new Date().getTime() - @date.getTime()
|
105
122
|
sec = Math.round ms / 1000
|
@@ -143,8 +160,19 @@ class RelativeTimeAgo
|
|
143
160
|
formatTime: ->
|
144
161
|
strftime @date, '%l:%M%P'
|
145
162
|
|
163
|
+
relativeDate = (date) ->
|
164
|
+
new RelativeTime(date).formatDate()
|
165
|
+
|
146
166
|
relativeTimeAgo = (date) ->
|
147
|
-
new
|
167
|
+
new RelativeTime(date).toString()
|
168
|
+
|
169
|
+
relativeTimeOrDate = (date) ->
|
170
|
+
new RelativeTime(date).toTimeOrDateString()
|
171
|
+
|
172
|
+
relativeWeekday = (date) ->
|
173
|
+
if day = new RelativeTime(date).relativeWeekday()
|
174
|
+
day.charAt(0).toUpperCase() + day.substring(1)
|
175
|
+
|
148
176
|
|
149
177
|
domLoaded = false
|
150
178
|
|
@@ -156,10 +184,6 @@ update = (callback) ->
|
|
156
184
|
if Turbolinks?.supported
|
157
185
|
document.addEventListener "page:update", callback
|
158
186
|
else
|
159
|
-
setTimeout ->
|
160
|
-
window.addEventListener "popstate", callback
|
161
|
-
, 1
|
162
|
-
|
163
187
|
jQuery?(document).on "ajaxSuccess", (event, xhr) ->
|
164
188
|
callback() if jQuery.trim xhr.responseText
|
165
189
|
|
@@ -180,19 +204,30 @@ document.addEventListener "DOMContentLoaded", ->
|
|
180
204
|
time = new Date Date.parse datetime
|
181
205
|
return if isNaN time
|
182
206
|
|
207
|
+
unless element.hasAttribute("title")
|
208
|
+
element.setAttribute "title", strftime(time, "%B %e, %Y at %l:%M%P %Z")
|
209
|
+
|
183
210
|
element[textProperty] =
|
184
211
|
switch local
|
212
|
+
when "date"
|
213
|
+
element.setAttribute "data-localized", true
|
214
|
+
relativeDate time
|
185
215
|
when "time"
|
186
216
|
element.setAttribute "data-localized", true
|
187
217
|
strftime time, format
|
188
218
|
when "time-ago"
|
189
219
|
relativeTimeAgo time
|
220
|
+
when "time-or-date"
|
221
|
+
relativeTimeOrDate time
|
222
|
+
when "weekday"
|
223
|
+
relativeWeekday(time) ? ""
|
224
|
+
|
225
|
+
run = ->
|
226
|
+
event = document.createEvent "Events"
|
227
|
+
event.initEvent "time:elapse", true, true
|
228
|
+
document.dispatchEvent event
|
190
229
|
|
191
|
-
|
192
|
-
event = document.createEvent "Events"
|
193
|
-
event.initEvent "time:elapse", true, true
|
194
|
-
document.dispatchEvent event
|
195
|
-
, 60 * 1000
|
230
|
+
setInterval run, 60 * 1000
|
196
231
|
|
197
232
|
# Public API
|
198
|
-
@LocalTime = {
|
233
|
+
@LocalTime = {relativeDate, relativeTimeAgo, relativeTimeOrDate, relativeWeekday, run, strftime}
|
@@ -1,9 +1,11 @@
|
|
1
1
|
module LocalTimeHelper
|
2
2
|
DEFAULT_FORMAT = '%B %e, %Y %l:%M%P'
|
3
3
|
|
4
|
-
def local_time(time, options =
|
5
|
-
time
|
6
|
-
|
4
|
+
def local_time(time, options = nil)
|
5
|
+
time = utc_time(time)
|
6
|
+
|
7
|
+
options, format = extract_options_and_value(options, :format)
|
8
|
+
format = find_time_format(format)
|
7
9
|
|
8
10
|
options[:data] ||= {}
|
9
11
|
options[:data].merge! local: :time, format: format
|
@@ -11,20 +13,28 @@ module LocalTimeHelper
|
|
11
13
|
time_tag time, time.strftime(format), options
|
12
14
|
end
|
13
15
|
|
14
|
-
def local_date(time, options =
|
15
|
-
options
|
16
|
+
def local_date(time, options = nil)
|
17
|
+
options, format = extract_options_and_value(options, :format)
|
18
|
+
options[:format] = format || '%B %e, %Y'
|
16
19
|
local_time time, options
|
17
20
|
end
|
18
21
|
|
19
|
-
def
|
22
|
+
def local_relative_time(time, options = nil)
|
20
23
|
time = utc_time(time)
|
24
|
+
options, type = extract_options_and_value(options, :type)
|
21
25
|
|
22
26
|
options[:data] ||= {}
|
23
|
-
options[:data].merge! local:
|
27
|
+
options[:data].merge! local: type
|
24
28
|
|
25
29
|
time_tag time, time.strftime(DEFAULT_FORMAT), options
|
26
30
|
end
|
27
31
|
|
32
|
+
def local_time_ago(time, options = nil)
|
33
|
+
options, type = extract_options_and_value(options, :type)
|
34
|
+
options[:type] = 'time-ago'
|
35
|
+
local_relative_time time, options
|
36
|
+
end
|
37
|
+
|
28
38
|
def utc_time(time_or_date)
|
29
39
|
if time_or_date.respond_to?(:in_time_zone)
|
30
40
|
time_or_date.in_time_zone.utc
|
@@ -34,7 +44,7 @@ module LocalTimeHelper
|
|
34
44
|
end
|
35
45
|
|
36
46
|
private
|
37
|
-
def
|
47
|
+
def find_time_format(format)
|
38
48
|
if format.is_a?(Symbol)
|
39
49
|
if (i18n_format = I18n.t("time.formats.#{format}", default: [:"date.formats.#{format}", ''])).present?
|
40
50
|
i18n_format
|
@@ -47,4 +57,16 @@ module LocalTimeHelper
|
|
47
57
|
format.presence || DEFAULT_FORMAT
|
48
58
|
end
|
49
59
|
end
|
60
|
+
|
61
|
+
def extract_options_and_value(options, value_key = nil)
|
62
|
+
case options
|
63
|
+
when Hash
|
64
|
+
value = options.delete(value_key)
|
65
|
+
[ options, value ]
|
66
|
+
when NilClass
|
67
|
+
[ {} ]
|
68
|
+
else
|
69
|
+
[ {}, options ]
|
70
|
+
end
|
71
|
+
end
|
50
72
|
end
|
@@ -1,11 +1,19 @@
|
|
1
1
|
require_relative '../../app/helpers/local_time_helper'
|
2
2
|
require 'active_support/all'
|
3
3
|
require 'action_view'
|
4
|
+
|
4
5
|
require 'minitest/autorun'
|
6
|
+
begin
|
7
|
+
# 2.0.0
|
8
|
+
class TestCase < MiniTest::Test; end
|
9
|
+
rescue NameError
|
10
|
+
# 1.9.3
|
11
|
+
class TestCase < MiniTest::Unit::TestCase; end
|
12
|
+
end
|
5
13
|
|
6
14
|
I18n.enforce_available_locales = false
|
7
15
|
|
8
|
-
class LocalTimeHelperTest <
|
16
|
+
class LocalTimeHelperTest < TestCase
|
9
17
|
include ActionView::Helpers::DateHelper, ActionView::Helpers::TagHelper
|
10
18
|
include LocalTimeHelper
|
11
19
|
|
@@ -51,6 +59,11 @@ class LocalTimeHelperTest < MiniTest::Unit::TestCase
|
|
51
59
|
assert_equal expected, local_time(@time, format: '%b %e')
|
52
60
|
end
|
53
61
|
|
62
|
+
def test_local_time_with_format_as_string
|
63
|
+
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
64
|
+
assert_equal expected, local_time(@time, '%b %e')
|
65
|
+
end
|
66
|
+
|
54
67
|
def test_local_time_with_i18n_format
|
55
68
|
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
56
69
|
assert_equal expected, local_time(@time, format: :simple_time)
|
@@ -88,6 +101,11 @@ class LocalTimeHelperTest < MiniTest::Unit::TestCase
|
|
88
101
|
assert_equal expected, local_date(@time.to_date, format: '%b %e')
|
89
102
|
end
|
90
103
|
|
104
|
+
def test_local_date_with_format_as_string
|
105
|
+
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
106
|
+
assert_equal expected, local_date(@time.to_date, '%b %e')
|
107
|
+
end
|
108
|
+
|
91
109
|
def test_local_date_with_i18n_format
|
92
110
|
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
93
111
|
assert_equal expected, local_date(@time.to_date, format: :simple_date)
|
@@ -112,4 +130,14 @@ class LocalTimeHelperTest < MiniTest::Unit::TestCase
|
|
112
130
|
expected = %Q(<time class="date-time" data-local="time-ago" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
|
113
131
|
assert_equal expected, local_time_ago(@time, class: "date-time")
|
114
132
|
end
|
133
|
+
|
134
|
+
def test_relative_time
|
135
|
+
expected = %Q(<time data-local="time-or-date" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
|
136
|
+
assert_equal expected, local_relative_time(@time, type: "time-or-date")
|
137
|
+
end
|
138
|
+
|
139
|
+
def test_local_time_ago_with_type_as_string
|
140
|
+
expected = %Q(<time data-local="time-or-date" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
|
141
|
+
assert_equal expected, local_relative_time(@time, "time-or-date")
|
142
|
+
end
|
115
143
|
end
|
@@ -1,13 +1,18 @@
|
|
1
|
-
#= require qunit
|
2
|
-
#= require moment
|
3
|
-
#= require sinon-timers
|
1
|
+
#= require vendor/qunit
|
2
|
+
#= require vendor/moment
|
3
|
+
#= require vendor/sinon-timers
|
4
4
|
#= require local_time
|
5
|
-
|
5
|
+
|
6
6
|
#= require_self
|
7
|
+
#= require_directory .
|
8
|
+
|
9
|
+
@addTimeEl = ({format, type, datetime} = {}) ->
|
10
|
+
format ?= "%Y"
|
11
|
+
type ?= "time"
|
12
|
+
datetime ?= "2013-11-12T12:13:00Z"
|
7
13
|
|
8
|
-
@addTimeEl = (format = "%Y", datetime = "2013-11-12T12:13:00Z") ->
|
9
14
|
el = document.createElement "time"
|
10
|
-
el.setAttribute "data-local",
|
15
|
+
el.setAttribute "data-local", type
|
11
16
|
el.setAttribute "data-format", format
|
12
17
|
el.setAttribute "datetime", datetime
|
13
18
|
document.body.appendChild el
|
@@ -10,11 +10,6 @@ test "document time:elapse", ->
|
|
10
10
|
triggerEvent "time:elapse"
|
11
11
|
ok getText el
|
12
12
|
|
13
|
-
test "window popstate", ->
|
14
|
-
el = addTimeEl()
|
15
|
-
triggerEvent "popstate", window
|
16
|
-
ok getText el
|
17
|
-
|
18
13
|
test "document page:update with Turbolinks on", ->
|
19
14
|
el = addTimeEl()
|
20
15
|
triggerEvent "page:update"
|