local_time 0.3.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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"
|