local_time 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +72 -0
- data/app/assets/javascripts/local_time.js.coffee +195 -0
- data/app/helpers/local_time_helper.rb +29 -0
- data/lib/local_time.rb +4 -0
- data/test/helpers/local_time_helper_test.rb +68 -0
- data/test/javascripts/config.ru +20 -0
- data/test/javascripts/index.html +20 -0
- data/test/javascripts/index.js.coffee +21 -0
- data/test/javascripts/unit/local_time_test.js.coffee +36 -0
- data/test/javascripts/unit/page_events_test.js.coffee +30 -0
- data/test/javascripts/unit/strftime_test.js.coffee +40 -0
- data/test/javascripts/unit/time_ago_test.js.coffee +49 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d0bfe22e485d89d3b8b8ef64db29d82d4d4f518c
|
4
|
+
data.tar.gz: 7d662d650e07542e16b13b98315ce589992bf397
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 840814649a2e4c03f7b8b9592ff696c7d5b7516a088a270fe2bdb4fb96e1a29221d455c31bbc31fdaa2a2dc0a38fe3718144c4c2dfe8ced9cbbc1d7ee76f425b
|
7
|
+
data.tar.gz: 2ed6f4bd924c469c23fd1134a53e4818ac1f5de1fd9cf9060859726bb47429176a8e5421f07c48d18303502c288ea38ccf74fff70ce55134f2e6b8fc110d23a4
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2013 Javan Makhmali
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,72 @@
|
|
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 in UTC and the JavaScript swoops in to convert and format. Because the `<time>` element is only rendered in one timezone, it is ideal for caching.
|
2
|
+
|
3
|
+
---
|
4
|
+
|
5
|
+
####Example
|
6
|
+
|
7
|
+
Assuming the time zone is EST and `Time.now` is `2013-11-27 18:43:22 -0500`:
|
8
|
+
|
9
|
+
```erb
|
10
|
+
<%= local_time(Time.now) # index.html.erb %>
|
11
|
+
```
|
12
|
+
|
13
|
+
Renders in UTC time:
|
14
|
+
|
15
|
+
```html
|
16
|
+
<time data-format="%B %e, %Y %l:%M%P"
|
17
|
+
data-local="time"
|
18
|
+
datetime="2013-11-27T23:43:22Z">November 27, 2013 11:43pm</time>
|
19
|
+
```
|
20
|
+
|
21
|
+
Then immediately converts to local time and strftime formats with JavaScript:
|
22
|
+
|
23
|
+
```html
|
24
|
+
<time data-format="%B %e, %Y %l:%M%P"
|
25
|
+
data-local="time"
|
26
|
+
datetime="2013-11-27T23:43:22Z"
|
27
|
+
data-localized="true">November 27, 2013 6:43pm</time>
|
28
|
+
```
|
29
|
+
|
30
|
+
*(Line breaks added for readability)*
|
31
|
+
|
32
|
+
#### Time and date helpers
|
33
|
+
|
34
|
+
```erb
|
35
|
+
Pass a time and an optional strftime format (default format shown here)
|
36
|
+
<%= local_time(time, format: '%B %e, %Y %l:%M%P') %>
|
37
|
+
|
38
|
+
Alias for local_time with a month-formatted default
|
39
|
+
<%= local_date(time, format: '%B %e, %Y') %>
|
40
|
+
```
|
41
|
+
|
42
|
+
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`
|
43
|
+
|
44
|
+
#### Time ago helper
|
45
|
+
|
46
|
+
```erb
|
47
|
+
<%= local_time_ago(time) %>
|
48
|
+
```
|
49
|
+
|
50
|
+
Displays the relative amount of time passed. With age, the descriptions transition from specific quantities to general dates. The `<time>` elements are updated every 60 seconds. Examples (in quotes):
|
51
|
+
|
52
|
+
* Recent: "a second ago", "32 seconds ago", "an hour ago", "14 hours ago"
|
53
|
+
* Yesterday: "yesterday at 5:22pm"
|
54
|
+
* This week: "Tuesday at 12:48am"
|
55
|
+
* This year: "on Nov 17"
|
56
|
+
* Last year: "on Jan 31, 2012"
|
57
|
+
|
58
|
+
#### Installation
|
59
|
+
|
60
|
+
1. Add `gem 'local_time'` to your Gemfile.
|
61
|
+
2. Run `bundle install`.
|
62
|
+
3. Add `//= require local_time` to your JavaScript manifest file (usually found at app/assets/javascripts/application.js).
|
63
|
+
|
64
|
+
#### JavaScript events and library compatibility
|
65
|
+
|
66
|
+
The included JavaScript does not depend on any frameworks or libraries, and listens for a `DOMContentLoaded` event to run initially. It also listens on `document` for `page:update` if you're using Turbolinks and `ajaxSuccess` if you're using jQuery. This should catch most cases where new `<time>` elements have been added to the DOM and process them automatically. If you're adding new elements in another context, trigger `time:elapse` to process them.
|
67
|
+
|
68
|
+
#### Version History
|
69
|
+
|
70
|
+
**0.1.0** (November 29, 2013)
|
71
|
+
|
72
|
+
* Initial release.
|
@@ -0,0 +1,195 @@
|
|
1
|
+
browserIsCompatible = ->
|
2
|
+
document.querySelectorAll and document.addEventListener
|
3
|
+
|
4
|
+
return unless browserIsCompatible()
|
5
|
+
|
6
|
+
# Older browsers do not support ISO8601 (JSON) timestamps in Date.parse
|
7
|
+
if isNaN Date.parse "2011-01-01T12:00:00-05:00"
|
8
|
+
parse = Date.parse
|
9
|
+
iso8601 = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(Z|[-+]?[\d:]+)$/
|
10
|
+
|
11
|
+
Date.parse = (dateString) ->
|
12
|
+
dateString = dateString.toString()
|
13
|
+
if matches = dateString.match iso8601
|
14
|
+
[_, year, month, day, hour, minute, second, zone] = matches
|
15
|
+
offset = zone.replace(":", "") if zone isnt "Z"
|
16
|
+
dateString = "#{year}/#{month}/#{day} #{hour}:#{minute}:#{second} GMT#{[offset]}"
|
17
|
+
parse dateString
|
18
|
+
|
19
|
+
weekdays = "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split " "
|
20
|
+
months = "January February March April May June July August September October November December".split " "
|
21
|
+
|
22
|
+
pad = (num) -> ('0' + num).slice -2
|
23
|
+
|
24
|
+
strftime = (time, formatString) ->
|
25
|
+
day = time.getDay()
|
26
|
+
date = time.getDate()
|
27
|
+
month = time.getMonth()
|
28
|
+
year = time.getFullYear()
|
29
|
+
hour = time.getHours()
|
30
|
+
minute = time.getMinutes()
|
31
|
+
second = time.getSeconds()
|
32
|
+
|
33
|
+
formatString.replace /%([%aAbBcdeHIlmMpPSwyY])/g, ([match, modifier]) ->
|
34
|
+
switch modifier
|
35
|
+
when '%' then '%'
|
36
|
+
when 'a' then weekdays[day].slice 0, 3
|
37
|
+
when 'A' then weekdays[day]
|
38
|
+
when 'b' then months[month].slice 0, 3
|
39
|
+
when 'B' then months[month]
|
40
|
+
when 'c' then time.toString()
|
41
|
+
when 'd' then pad date
|
42
|
+
when 'e' then date
|
43
|
+
when 'H' then pad hour
|
44
|
+
when 'I' then pad strftime time, '%l'
|
45
|
+
when 'l' then (if hour is 0 or hour is 12 then 12 else (hour + 12) % 12)
|
46
|
+
when 'm' then pad month + 1
|
47
|
+
when 'M' then pad minute
|
48
|
+
when 'p' then (if hour > 11 then 'PM' else 'AM')
|
49
|
+
when 'P' then (if hour > 11 then 'pm' else 'am')
|
50
|
+
when 'S' then pad second
|
51
|
+
when 'w' then day
|
52
|
+
when 'y' then pad year % 100
|
53
|
+
when 'Y' then year
|
54
|
+
|
55
|
+
|
56
|
+
class CalendarDate
|
57
|
+
@fromDate: (date) ->
|
58
|
+
new this date.getFullYear(), date.getMonth() + 1, date.getDate()
|
59
|
+
|
60
|
+
@today: ->
|
61
|
+
@fromDate new Date
|
62
|
+
|
63
|
+
constructor: (year, month, day) ->
|
64
|
+
@date = new Date Date.UTC year, month - 1
|
65
|
+
@date.setUTCDate day
|
66
|
+
|
67
|
+
@year = @date.getUTCFullYear()
|
68
|
+
@month = @date.getUTCMonth() + 1
|
69
|
+
@day = @date.getUTCDate()
|
70
|
+
|
71
|
+
occursOnSameYearAs: (date) ->
|
72
|
+
@year is date?.year
|
73
|
+
|
74
|
+
occursThisYear: ->
|
75
|
+
@occursOnSameYearAs @constructor.today()
|
76
|
+
|
77
|
+
daysSince: (date) ->
|
78
|
+
if date
|
79
|
+
(@date - date.date) / (1000 * 60 * 60 * 24)
|
80
|
+
|
81
|
+
daysPassed: ->
|
82
|
+
@constructor.today().daysSince @
|
83
|
+
|
84
|
+
|
85
|
+
class RelativeTimeAgo
|
86
|
+
@generate: (date) ->
|
87
|
+
new this(date).toString()
|
88
|
+
|
89
|
+
constructor: (@date) ->
|
90
|
+
@calendarDate = CalendarDate.fromDate @date
|
91
|
+
|
92
|
+
toString: ->
|
93
|
+
# Today: "Saved 5 hours ago"
|
94
|
+
if ago = @timeElapsed()
|
95
|
+
"#{ago} ago"
|
96
|
+
|
97
|
+
# Yesterday: "Saved yesterday at 8:15am"
|
98
|
+
# This week: "Saved Thursday at 8:15am"
|
99
|
+
else if day = @relativeWeekday()
|
100
|
+
"#{day} at #{@formatTime()}"
|
101
|
+
|
102
|
+
# Older: "Saved on Dec 15"
|
103
|
+
else
|
104
|
+
"on #{@formatDate()}"
|
105
|
+
|
106
|
+
timeElapsed: ->
|
107
|
+
ms = new Date().getTime() - @date.getTime()
|
108
|
+
sec = Math.round ms / 1000
|
109
|
+
min = Math.round sec / 60
|
110
|
+
hr = Math.round min / 60
|
111
|
+
|
112
|
+
if ms < 0
|
113
|
+
null
|
114
|
+
else if sec < 10
|
115
|
+
"a second"
|
116
|
+
else if sec < 45
|
117
|
+
"#{sec} seconds"
|
118
|
+
else if sec < 90
|
119
|
+
"a minute"
|
120
|
+
else if min < 45
|
121
|
+
"#{min} minutes"
|
122
|
+
else if min < 90
|
123
|
+
"an hour"
|
124
|
+
else if hr < 24
|
125
|
+
"#{hr} hours"
|
126
|
+
else
|
127
|
+
null
|
128
|
+
|
129
|
+
relativeWeekday: ->
|
130
|
+
daysPassed = @calendarDate.daysPassed()
|
131
|
+
|
132
|
+
if daysPassed > 6
|
133
|
+
null
|
134
|
+
else if daysPassed is 0
|
135
|
+
"today"
|
136
|
+
else if daysPassed is 1
|
137
|
+
"yesterday"
|
138
|
+
else
|
139
|
+
strftime @date, "%A"
|
140
|
+
|
141
|
+
formatDate: ->
|
142
|
+
format = "%b %e"
|
143
|
+
format += ", %Y" unless @calendarDate.occursThisYear()
|
144
|
+
strftime @date, format
|
145
|
+
|
146
|
+
formatTime: ->
|
147
|
+
strftime @date, '%l:%M%P'
|
148
|
+
|
149
|
+
|
150
|
+
domLoaded = false
|
151
|
+
|
152
|
+
update = (callback) ->
|
153
|
+
callback() if domLoaded
|
154
|
+
|
155
|
+
document.addEventListener "time:elapse", callback
|
156
|
+
|
157
|
+
if Turbolinks?.supported
|
158
|
+
document.addEventListener "page:update", callback
|
159
|
+
else
|
160
|
+
setTimeout ->
|
161
|
+
window.addEventListener "popstate", callback
|
162
|
+
, 1
|
163
|
+
|
164
|
+
jQuery?(document).on "ajaxSuccess", (event, xhr) ->
|
165
|
+
callback() if jQuery.trim xhr.responseText
|
166
|
+
|
167
|
+
process = (selector, callback) ->
|
168
|
+
update ->
|
169
|
+
for element in document.querySelectorAll selector
|
170
|
+
callback element
|
171
|
+
|
172
|
+
document.addEventListener "DOMContentLoaded", ->
|
173
|
+
domLoaded = true
|
174
|
+
|
175
|
+
process "time[data-local]:not([data-localized])", (element) ->
|
176
|
+
datetime = element.getAttribute "datetime"
|
177
|
+
format = element.getAttribute "data-format"
|
178
|
+
local = element.getAttribute "data-local"
|
179
|
+
|
180
|
+
time = new Date Date.parse datetime
|
181
|
+
return if isNaN time
|
182
|
+
|
183
|
+
element.innerText =
|
184
|
+
switch local
|
185
|
+
when "time"
|
186
|
+
element.setAttribute "data-localized", true
|
187
|
+
strftime time, format
|
188
|
+
when "time-ago"
|
189
|
+
RelativeTimeAgo.generate time
|
190
|
+
|
191
|
+
setInterval ->
|
192
|
+
event = document.createEvent "Events"
|
193
|
+
event.initEvent "time:elapse", true, true
|
194
|
+
document.dispatchEvent event
|
195
|
+
, 60 * 1000
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module LocalTimeHelper
|
2
|
+
def local_time(time, options = {})
|
3
|
+
time = utc_time(time)
|
4
|
+
format = options.delete(:format).presence || '%B %e, %Y %l:%M%P'
|
5
|
+
|
6
|
+
options[:data] ||= {}
|
7
|
+
options[:data].merge! local: :time, format: format
|
8
|
+
|
9
|
+
time_tag time, time.strftime(format), options
|
10
|
+
end
|
11
|
+
|
12
|
+
def local_date(time, options = {})
|
13
|
+
options.reverse_merge! format: '%B %e, %Y'
|
14
|
+
local_time time, options
|
15
|
+
end
|
16
|
+
|
17
|
+
def local_time_ago(time)
|
18
|
+
time = utc_time(time)
|
19
|
+
time_tag time, time.strftime('%B %e, %Y %l:%M%P'), data: { local: 'time-ago' }
|
20
|
+
end
|
21
|
+
|
22
|
+
def utc_time(time_or_date)
|
23
|
+
if time_or_date.respond_to?(:in_time_zone)
|
24
|
+
time_or_date.in_time_zone.utc
|
25
|
+
else
|
26
|
+
time_or_date.to_time.utc
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/local_time.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
require_relative '../../app/helpers/local_time_helper'
|
2
|
+
require 'active_support/all'
|
3
|
+
require 'action_view'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
|
7
|
+
class LocalTimeHelperTest < Minitest::Test
|
8
|
+
include ActionView::Helpers::DateHelper, ActionView::Helpers::TagHelper
|
9
|
+
include LocalTimeHelper
|
10
|
+
|
11
|
+
def setup
|
12
|
+
@original_zone = Time.zone
|
13
|
+
Time.zone = ActiveSupport::TimeZone["Central Time (US & Canada)"]
|
14
|
+
|
15
|
+
@date = "2013-11-21"
|
16
|
+
@time = Time.zone.parse(@date)
|
17
|
+
@time_utc = "2013-11-21 06:00:00 UTC"
|
18
|
+
@time_js = "2013-11-21T06:00:00Z"
|
19
|
+
end
|
20
|
+
|
21
|
+
def teardown
|
22
|
+
Time.zone = @original_zone
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_utc_time_with_a_date
|
26
|
+
date = Date.parse(@date)
|
27
|
+
assert_equal @time_utc, utc_time(date).to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_utc_time_with_a_local_time
|
31
|
+
assert_equal @time_utc, utc_time(@time).to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_utc_time_with_a_utc_time
|
35
|
+
assert_equal @time_utc, utc_time(@time.utc).to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_local_time
|
39
|
+
expected = %Q(<time data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
|
40
|
+
assert_equal expected, local_time(@time)
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_local_time_with_format
|
44
|
+
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
45
|
+
assert_equal expected, local_time(@time, format: '%b %e')
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_local_time_with_options
|
49
|
+
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}" style="display:none">Nov 21</time>)
|
50
|
+
assert_equal expected, local_time(@time, format: '%b %e', style: 'display:none')
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_local_date
|
54
|
+
expected = %Q(<time data-format="%B %e, %Y" data-local="time" datetime="#{@time_js}">November 21, 2013</time>)
|
55
|
+
assert_equal expected, local_date(@time)
|
56
|
+
assert_equal expected, local_date(@time.to_date)
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_local_date_with_format
|
60
|
+
expected = %Q(<time data-format="%b %e" data-local="time" datetime="#{@time_js}">Nov 21</time>)
|
61
|
+
assert_equal expected, local_date(@time, format: '%b %e')
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_local_time_ago
|
65
|
+
expected = %Q(<time data-local="time-ago" datetime="#{@time_js}">November 21, 2013 6:00am</time>)
|
66
|
+
assert_equal expected, local_time_ago(@time)
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'sprockets'
|
2
|
+
require 'coffee-rails'
|
3
|
+
|
4
|
+
Root = File.expand_path("../../..", __FILE__)
|
5
|
+
|
6
|
+
Assets = Sprockets::Environment.new(Root) do |env|
|
7
|
+
env.append_path "app/assets/javascripts"
|
8
|
+
env.append_path "test/javascripts"
|
9
|
+
env.append_path "vendor"
|
10
|
+
end
|
11
|
+
|
12
|
+
map "/css" do
|
13
|
+
run Assets
|
14
|
+
end
|
15
|
+
|
16
|
+
map "/js" do
|
17
|
+
run Assets
|
18
|
+
end
|
19
|
+
|
20
|
+
map("/") { run Rack::File.new("#{Root}/test/javascripts/index.html") }
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<link rel="stylesheet" href="/css/qunit.css">
|
6
|
+
<script type="text/javascript" src="/js/index.js"></script>
|
7
|
+
</head>
|
8
|
+
<body>
|
9
|
+
<div id="qunit"></div>
|
10
|
+
<div id="qunit-fixture"></div>
|
11
|
+
|
12
|
+
<time id="one" data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="2013-11-12T12:13:00Z"></time>
|
13
|
+
<time id="two" data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="2013-01-02T02:04:00Z"></time>
|
14
|
+
<time id="past" data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="1805-05-15T01:01:00Z"></time>
|
15
|
+
<time id="future" data-format="%B %e, %Y %l:%M%P" data-local="time" datetime="3333-02-14T23:55:00Z"></time>
|
16
|
+
|
17
|
+
<time id="date" data-format="%B %e, %Y" data-local="time" datetime="2013-11-12T12:13:00Z"></time>
|
18
|
+
|
19
|
+
<time id="ago"></time>
|
20
|
+
</html>
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#= require qunit
|
2
|
+
#= require moment
|
3
|
+
#= require local_time
|
4
|
+
#= require_directory ./unit
|
5
|
+
#= require_self
|
6
|
+
|
7
|
+
@addTimeEl = (format = "%Y", datetime = "2013-11-12T12:13:00Z") ->
|
8
|
+
el = document.createElement "time"
|
9
|
+
el.setAttribute "data-local", "time"
|
10
|
+
el.setAttribute "data-format", format
|
11
|
+
el.setAttribute "datetime", datetime
|
12
|
+
document.body.appendChild el
|
13
|
+
el
|
14
|
+
|
15
|
+
@triggerEvent = (name, el = document) ->
|
16
|
+
event = document.createEvent "Events"
|
17
|
+
event.initEvent name, true, true
|
18
|
+
el.dispatchEvent event
|
19
|
+
|
20
|
+
@run = ->
|
21
|
+
triggerEvent "time:elapse"
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module "localized"
|
2
|
+
|
3
|
+
for id in ["one", "two", "past", "future"]
|
4
|
+
test id, ->
|
5
|
+
assertLocalized id
|
6
|
+
|
7
|
+
test "date", ->
|
8
|
+
assertLocalized "date", "date"
|
9
|
+
|
10
|
+
test "unparseable time", ->
|
11
|
+
el = addTimeEl "%Y", ":("
|
12
|
+
el.innerText = "2013"
|
13
|
+
run()
|
14
|
+
equal el.innerText, "2013"
|
15
|
+
|
16
|
+
|
17
|
+
assertLocalized = (id, type = "time") ->
|
18
|
+
switch type
|
19
|
+
when "time"
|
20
|
+
momentFormat = "MMMM D, YYYY h:mma"
|
21
|
+
compare = "toString"
|
22
|
+
when "date"
|
23
|
+
momentFormat = "MMMM D, YYYY"
|
24
|
+
compare = "dayOfYear"
|
25
|
+
|
26
|
+
el = document.getElementById id
|
27
|
+
|
28
|
+
ok datetime = el.getAttribute "datetime"
|
29
|
+
ok local = el.innerText
|
30
|
+
|
31
|
+
datetimeParsed = moment datetime
|
32
|
+
localParsed = moment local, momentFormat
|
33
|
+
|
34
|
+
ok datetimeParsed.isValid()
|
35
|
+
ok localParsed.isValid()
|
36
|
+
equal datetimeParsed[compare](), localParsed[compare]()
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module "page events"
|
2
|
+
|
3
|
+
test "document DOMContentLoaded", ->
|
4
|
+
el = addTimeEl()
|
5
|
+
triggerEvent "DOMContentLoaded"
|
6
|
+
ok el.innerText
|
7
|
+
|
8
|
+
test "document time:elapse", ->
|
9
|
+
el = addTimeEl()
|
10
|
+
triggerEvent "time:elapse"
|
11
|
+
ok el.innerText
|
12
|
+
|
13
|
+
test "window popstate", ->
|
14
|
+
el = addTimeEl()
|
15
|
+
triggerEvent "popstate", window
|
16
|
+
ok el.innerText
|
17
|
+
|
18
|
+
test "document page:update with Turbolinks on", ->
|
19
|
+
el = addTimeEl()
|
20
|
+
triggerEvent "page:update"
|
21
|
+
ok not el.innerText
|
22
|
+
|
23
|
+
original = window.Turbolinks
|
24
|
+
window.Turbolinks = { supported: true }
|
25
|
+
|
26
|
+
triggerEvent "DOMContentLoaded"
|
27
|
+
triggerEvent "page:update"
|
28
|
+
ok el.innerText
|
29
|
+
|
30
|
+
window.Turbolinks = original
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module "strftime"
|
2
|
+
|
3
|
+
momentMap =
|
4
|
+
"%a": "ddd"
|
5
|
+
"%A": "dddd"
|
6
|
+
"%b": "MMM"
|
7
|
+
"%B": "MMMM"
|
8
|
+
"%c": "toString()"
|
9
|
+
"%d": "DD"
|
10
|
+
"%e": "D"
|
11
|
+
"%H": "HH"
|
12
|
+
"%I": "hh"
|
13
|
+
"%l": "h"
|
14
|
+
"%m": "MM"
|
15
|
+
"%M": "mm"
|
16
|
+
"%p": "A"
|
17
|
+
"%P": "a"
|
18
|
+
"%S": "ss"
|
19
|
+
"%w": "e"
|
20
|
+
"%y": "YY"
|
21
|
+
"%Y": "YYYY"
|
22
|
+
|
23
|
+
for day in [0..30] by 6
|
24
|
+
do (day) ->
|
25
|
+
for hour in [0..24] by 6
|
26
|
+
do (hour) ->
|
27
|
+
for format, momentFormat of momentMap
|
28
|
+
do (format, momentFormat) ->
|
29
|
+
|
30
|
+
test "#{format} (+#{day} days, #{hour} hours)", ->
|
31
|
+
now = moment().add("days", day).add("hours", hour)
|
32
|
+
el = addTimeEl format, now.toISOString()
|
33
|
+
run()
|
34
|
+
|
35
|
+
equal el.innerText,
|
36
|
+
if func = momentFormat.match(/(\w+)\(\)/)?[1]
|
37
|
+
now.toDate()[func]()
|
38
|
+
else
|
39
|
+
now.format momentFormat
|
40
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module "time ago"
|
2
|
+
|
3
|
+
test "a second ago", ->
|
4
|
+
assertTimeAgo "a second ago", "seconds", 9
|
5
|
+
|
6
|
+
test "seconds ago", ->
|
7
|
+
assertTimeAgo "44 seconds ago", "seconds", 44
|
8
|
+
|
9
|
+
test "a minute ago", ->
|
10
|
+
assertTimeAgo "a minute ago", "seconds", 89
|
11
|
+
|
12
|
+
test "minutes ago", ->
|
13
|
+
assertTimeAgo "44 minutes ago", "minutes", 44
|
14
|
+
|
15
|
+
test "an hour ago", ->
|
16
|
+
assertTimeAgo "an hour ago", "minutes", 89
|
17
|
+
|
18
|
+
test "hours ago", ->
|
19
|
+
assertTimeAgo "23 hours ago", "hours", 23
|
20
|
+
|
21
|
+
test "yesterday", ->
|
22
|
+
time = moment().subtract("days", 1).format "h:mma"
|
23
|
+
assertTimeAgo "yesterday at #{time}", "days", 1
|
24
|
+
|
25
|
+
test "last week", ->
|
26
|
+
ago = moment().subtract "days", 5
|
27
|
+
day = ago.format "dddd"
|
28
|
+
time = ago.format "h:mma"
|
29
|
+
|
30
|
+
assertTimeAgo "#{day} at #{time}", "days", 5
|
31
|
+
|
32
|
+
test "this year", ->
|
33
|
+
# This will fail on the first 7 days of the year.
|
34
|
+
# Not sure how to test without somehow stubbing Date.
|
35
|
+
if moment().dayOfYear() > 7
|
36
|
+
date = moment().subtract("days", 7).format "MMM D"
|
37
|
+
assertTimeAgo "on #{date}", "days", 7
|
38
|
+
|
39
|
+
test "last year", ->
|
40
|
+
date = moment().subtract("days", 366).format "MMM D, YYYY"
|
41
|
+
assertTimeAgo "on #{date}", "days", 366
|
42
|
+
|
43
|
+
|
44
|
+
assertTimeAgo = (string, unit, amount) ->
|
45
|
+
el = document.getElementById "ago"
|
46
|
+
el.setAttribute "data-local", "time-ago"
|
47
|
+
el.setAttribute "datetime", moment().subtract(unit, amount).utc().toISOString()
|
48
|
+
run()
|
49
|
+
equal el.innerText, string
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: local_time
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Javan Makhmali
|
8
|
+
- Sam Stephenson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-11-29 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: coffee-rails
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
description:
|
29
|
+
email: javan@37signals.com
|
30
|
+
executables: []
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- app/assets/javascripts/local_time.js.coffee
|
35
|
+
- app/helpers/local_time_helper.rb
|
36
|
+
- lib/local_time.rb
|
37
|
+
- MIT-LICENSE
|
38
|
+
- README.md
|
39
|
+
- test/helpers/local_time_helper_test.rb
|
40
|
+
- test/javascripts/config.ru
|
41
|
+
- test/javascripts/index.html
|
42
|
+
- test/javascripts/index.js.coffee
|
43
|
+
- test/javascripts/unit/local_time_test.js.coffee
|
44
|
+
- test/javascripts/unit/page_events_test.js.coffee
|
45
|
+
- test/javascripts/unit/strftime_test.js.coffee
|
46
|
+
- test/javascripts/unit/time_ago_test.js.coffee
|
47
|
+
homepage:
|
48
|
+
licenses:
|
49
|
+
- MIT
|
50
|
+
metadata: {}
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options: []
|
53
|
+
require_paths:
|
54
|
+
- lib
|
55
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - '>='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: '0'
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - '>='
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
version: '0'
|
65
|
+
requirements: []
|
66
|
+
rubyforge_project:
|
67
|
+
rubygems_version: 2.1.11
|
68
|
+
signing_key:
|
69
|
+
specification_version: 4
|
70
|
+
summary: Rails engine for displaying local times using JavaScript
|
71
|
+
test_files:
|
72
|
+
- test/helpers/local_time_helper_test.rb
|
73
|
+
- test/javascripts/config.ru
|
74
|
+
- test/javascripts/index.html
|
75
|
+
- test/javascripts/index.js.coffee
|
76
|
+
- test/javascripts/unit/local_time_test.js.coffee
|
77
|
+
- test/javascripts/unit/page_events_test.js.coffee
|
78
|
+
- test/javascripts/unit/strftime_test.js.coffee
|
79
|
+
- test/javascripts/unit/time_ago_test.js.coffee
|