Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
C
coopwire-hypothesis
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
孙灵跃 Leon Sun
coopwire-hypothesis
Commits
1187d864
Commit
1187d864
authored
May 09, 2016
by
Robert Knight
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3247 from hypothesis/change-display-of-datetimes-on-annotations
Change display of datetimes on annotations
parents
2332e117
d78e2991
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
214 additions
and
60 deletions
+214
-60
time-test.js
h/static/scripts/test/time-test.js
+70
-21
time.js
h/static/scripts/time.js
+144
-39
No files found.
h/static/scripts/test/time-test.js
View file @
1187d864
...
@@ -9,19 +9,20 @@ var month = day * 30;
...
@@ -9,19 +9,20 @@ var month = day * 30;
var
year
=
day
*
365
;
var
year
=
day
*
365
;
var
FIXTURES_TO_FUZZY_STRING
=
[
var
FIXTURES_TO_FUZZY_STRING
=
[
[
10
,
'moments ago'
],
[
10
,
'Just now'
],
[
29
,
'moments ago'
],
[
29
,
'Just now'
],
[
49
,
'49 seconds ago'
],
[
49
,
'49 secs'
],
[
minute
+
5
,
'a minute ago'
],
[
minute
+
5
,
'1 min'
],
[
3
*
minute
+
5
,
'3 minutes ago'
],
[
3
*
minute
+
5
,
'3 mins'
],
[
4
*
hour
,
'4 hours ago'
],
[
hour
,
'1 hr'
],
[
27
*
hour
,
'a day ago'
],
[
4
*
hour
,
'4 hrs'
],
[
3
*
day
+
30
*
minute
,
'3 days ago'
],
[
27
*
hour
,
'1 Jan'
],
[
6
*
month
+
2
*
day
,
'6 months ago'
],
[
3
*
day
+
30
*
minute
,
'1 Jan'
],
[
1
*
year
,
'one year ago'
],
[
6
*
month
+
2
*
day
,
'1 Jan'
],
[
1
*
year
+
2
*
month
,
'one year ago'
],
[
1
*
year
,
'1 Jan 1970'
],
[
2
*
year
,
'2 years ago'
],
[
1
*
year
+
2
*
month
,
'1 Jan 1970'
],
[
8
*
year
,
'8 years ago'
]
[
2
*
year
,
'1 Jan 1970'
],
[
8
*
year
,
'1 Jan 1970'
]
];
];
var
FIXTURES_NEXT_FUZZY_UPDATE
=
[
var
FIXTURES_NEXT_FUZZY_UPDATE
=
[
...
@@ -31,10 +32,10 @@ var FIXTURES_NEXT_FUZZY_UPDATE = [
...
@@ -31,10 +32,10 @@ var FIXTURES_NEXT_FUZZY_UPDATE = [
[
minute
+
5
,
minute
],
[
minute
+
5
,
minute
],
[
3
*
minute
+
5
,
minute
],
[
3
*
minute
+
5
,
minute
],
[
4
*
hour
,
hour
],
[
4
*
hour
,
hour
],
[
27
*
hour
,
day
],
[
27
*
hour
,
null
],
[
3
*
day
+
30
*
minute
,
day
],
[
3
*
day
+
30
*
minute
,
null
],
[
6
*
month
+
2
*
day
,
24
*
day
],
// longer times are not supported
[
6
*
month
+
2
*
day
,
null
],
[
8
*
year
,
24
*
day
]
// by setTimout
[
8
*
year
,
null
]
];
];
describe
(
'time'
,
function
()
{
describe
(
'time'
,
function
()
{
...
@@ -50,18 +51,35 @@ describe('time', function () {
...
@@ -50,18 +51,35 @@ describe('time', function () {
});
});
describe
(
'.toFuzzyString'
,
function
()
{
describe
(
'.toFuzzyString'
,
function
()
{
function
mockIntl
()
{
return
{
DateTimeFormat
:
function
()
{
return
{
format
:
function
()
{
if
(
new
Date
().
getYear
()
===
70
)
{
return
'1 Jan'
;
}
else
{
return
'1 Jan 1970'
;
}
}
};
}
};
}
it
(
'Handles empty dates'
,
function
()
{
it
(
'Handles empty dates'
,
function
()
{
var
t
=
null
;
var
t
=
null
;
var
expect
=
''
;
var
expect
=
''
;
assert
.
equal
(
time
.
toFuzzyString
(
t
),
expect
);
assert
.
equal
(
time
.
toFuzzyString
(
t
,
mockIntl
()
),
expect
);
});
});
var
testFixture
=
function
(
f
)
{
var
testFixture
=
function
(
f
)
{
return
function
()
{
return
function
()
{
var
t
=
new
Date
();
var
t
=
new
Date
()
.
toISOString
()
;
var
expect
=
f
[
1
];
var
expect
=
f
[
1
];
sandbox
.
clock
.
tick
(
f
[
0
]
*
1000
);
sandbox
.
clock
.
tick
(
f
[
0
]
*
1000
);
assert
.
equal
(
time
.
toFuzzyString
(
t
),
expect
);
assert
.
equal
(
time
.
toFuzzyString
(
t
,
mockIntl
()
),
expect
);
};
};
};
};
...
@@ -70,6 +88,25 @@ describe('time', function () {
...
@@ -70,6 +88,25 @@ describe('time', function () {
it
(
'creates correct fuzzy string for fixture '
+
i
,
it
(
'creates correct fuzzy string for fixture '
+
i
,
testFixture
(
f
));
testFixture
(
f
));
}
}
it
(
'falls back to simple strings for >24hrs ago'
,
function
()
{
// If window.Intl is not available then the date formatting for dates
// more than one day ago falls back to a simple date string.
var
d
=
new
Date
().
toISOString
();
sandbox
.
clock
.
tick
(
day
*
2
*
1000
);
assert
.
equal
(
time
.
toFuzzyString
(
d
,
null
),
'Thu Jan 01 1970'
);
});
it
(
'falls back to simple strings for >1yr ago'
,
function
()
{
// If window.Intl is not available then the date formatting for dates
// more than one year ago falls back to a simple date string.
var
d
=
new
Date
().
toISOString
();
sandbox
.
clock
.
tick
(
year
*
2
*
1000
);
assert
.
equal
(
time
.
toFuzzyString
(
d
,
null
),
'Thu Jan 01 1970'
);
});
});
});
describe
(
'.decayingInterval'
,
function
()
{
describe
(
'.decayingInterval'
,
function
()
{
...
@@ -105,6 +142,18 @@ describe('time', function () {
...
@@ -105,6 +142,18 @@ describe('time', function () {
sandbox
.
clock
.
tick
(
minute
*
1000
);
sandbox
.
clock
.
tick
(
minute
*
1000
);
assert
.
notCalled
(
callback
);
assert
.
notCalled
(
callback
);
});
});
it
(
'does not set a timeout for dates > 24hrs ago'
,
function
()
{
var
date
=
new
Date
();
var
ONE_DAY
=
day
*
1000
;
sandbox
.
clock
.
tick
(
10
*
ONE_DAY
);
var
callback
=
sandbox
.
stub
();
time
.
decayingInterval
(
date
,
callback
);
sandbox
.
clock
.
tick
(
ONE_DAY
*
2
);
assert
.
notCalled
(
callback
);
});
});
});
describe
(
'.nextFuzzyUpdate'
,
function
()
{
describe
(
'.nextFuzzyUpdate'
,
function
()
{
...
@@ -116,7 +165,7 @@ describe('time', function () {
...
@@ -116,7 +165,7 @@ describe('time', function () {
var
testFixture
=
function
(
f
)
{
var
testFixture
=
function
(
f
)
{
return
function
()
{
return
function
()
{
var
t
=
new
Date
();
var
t
=
new
Date
()
.
toISOString
()
;
var
expect
=
f
[
1
];
var
expect
=
f
[
1
];
sandbox
.
clock
.
tick
(
f
[
0
]
*
1000
);
sandbox
.
clock
.
tick
(
f
[
0
]
*
1000
);
assert
.
equal
(
time
.
nextFuzzyUpdate
(
t
),
expect
);
assert
.
equal
(
time
.
nextFuzzyUpdate
(
t
),
expect
);
...
...
h/static/scripts/time.js
View file @
1187d864
...
@@ -2,39 +2,148 @@
...
@@ -2,39 +2,148 @@
var
minute
=
60
;
var
minute
=
60
;
var
hour
=
minute
*
60
;
var
hour
=
minute
*
60
;
var
day
=
hour
*
24
;
var
month
=
day
*
30
;
function
lessThanThirtySecondsAgo
(
date
,
now
)
{
var
year
=
day
*
365
;
return
((
now
-
date
)
<
30
*
1000
);
}
function
lessThanOneMinuteAgo
(
date
,
now
)
{
return
((
now
-
date
)
<
60
*
1000
);
}
function
lessThanOneHourAgo
(
date
,
now
)
{
return
((
now
-
date
)
<
(
60
*
60
*
1000
));
}
function
lessThanOneDayAgo
(
date
,
now
)
{
return
((
now
-
date
)
<
(
24
*
60
*
60
*
1000
));
}
function
thisYear
(
date
,
now
)
{
return
date
.
getFullYear
()
===
now
.
getFullYear
();
}
function
delta
(
date
,
now
)
{
return
Math
.
round
((
now
-
date
)
/
1000
);
}
function
nSec
(
date
,
now
)
{
return
'{} secs'
.
replace
(
'{}'
,
Math
.
floor
(
delta
(
date
,
now
)));
}
function
nMin
(
date
,
now
)
{
var
n
=
Math
.
floor
(
delta
(
date
,
now
)
/
minute
);
var
template
=
'{} min'
;
if
(
n
>
1
)
{
template
=
template
+
's'
;
}
return
template
.
replace
(
'{}'
,
n
);
}
function
nHr
(
date
,
now
)
{
var
n
=
Math
.
floor
(
delta
(
date
,
now
)
/
hour
);
var
template
=
'{} hr'
;
if
(
n
>
1
)
{
template
=
template
+
's'
;
}
return
template
.
replace
(
'{}'
,
n
);
}
// Cached DateTimeFormat instances,
// because instantiating a DateTimeFormat is expensive.
var
formatters
=
{};
/**
* Efficiently return `date` formatted with `options`.
*
* This is a wrapper for Intl.DateTimeFormat.format() that caches
* DateTimeFormat instances because they're expensive to create.
* Calling Date.toLocaleDateString() lots of times is also expensive in some
* browsers as it appears to create a new formatter for each call.
*
* @returns {string}
*
*/
function
format
(
date
,
options
,
Intl
)
{
// If the tests have passed in a mock Intl then use it, otherwise use the
// real one.
if
(
typeof
Intl
===
'undefined'
)
{
Intl
=
window
.
Intl
;
}
if
(
Intl
&&
Intl
.
DateTimeFormat
)
{
var
key
=
JSON
.
stringify
(
options
);
var
formatter
=
formatters
[
key
];
if
(
!
formatter
)
{
formatter
=
formatters
[
key
]
=
new
Intl
.
DateTimeFormat
(
undefined
,
options
);
}
return
formatter
.
format
(
date
);
}
else
{
// IE < 11, Safari <= 9.0.
return
date
.
toDateString
();
}
}
function
dayAndMonth
(
date
,
now
,
Intl
)
{
return
format
(
date
,
{
month
:
'short'
,
day
:
'numeric'
},
Intl
);
}
function
dayAndMonthAndYear
(
date
,
now
,
Intl
)
{
return
format
(
date
,
{
day
:
'numeric'
,
month
:
'short'
,
year
:
'numeric'
},
Intl
);
}
var
BREAKPOINTS
=
[
var
BREAKPOINTS
=
[
[
30
,
'moments ago'
,
1
],
{
[
minute
,
'{} seconds ago'
,
1
],
test
:
lessThanThirtySecondsAgo
,
[
2
*
minute
,
'a minute ago'
,
minute
],
format
:
function
()
{
return
'Just now'
;},
[
hour
,
'{} minutes ago'
,
minute
],
nextUpdate
:
1
[
2
*
hour
,
'an hour ago'
,
hour
],
},
[
day
,
'{} hours ago'
,
hour
],
{
[
2
*
day
,
'a day ago'
,
day
],
test
:
lessThanOneMinuteAgo
,
[
month
,
'{} days ago'
,
day
],
format
:
nSec
,
[
year
,
'{} months ago'
,
month
],
nextUpdate
:
1
[
2
*
year
,
'one year ago'
,
year
],
},
[
Infinity
,
'{} years ago'
,
year
]
{
test
:
lessThanOneHourAgo
,
format
:
nMin
,
nextUpdate
:
minute
},
{
test
:
lessThanOneDayAgo
,
format
:
nHr
,
nextUpdate
:
hour
},
{
test
:
thisYear
,
format
:
dayAndMonth
,
nextUpdate
:
null
},
{
test
:
function
()
{
return
true
;},
format
:
dayAndMonthAndYear
,
nextUpdate
:
null
}
];
];
function
getBreakpoint
(
date
)
{
function
getBreakpoint
(
date
,
now
)
{
var
delta
=
Math
.
round
((
new
Date
()
-
new
Date
(
date
))
/
1000
);
var
breakpoint
;
// Turn the given ISO 8601 string into a Date object.
date
=
new
Date
(
date
);
var
breakpoint
;
for
(
var
i
=
0
;
i
<
BREAKPOINTS
.
length
;
i
++
)
{
for
(
var
i
=
0
;
i
<
BREAKPOINTS
.
length
;
i
++
)
{
if
(
BREAKPOINTS
[
i
][
0
]
>
delta
)
{
breakpoint
=
BREAKPOINTS
[
i
];
breakpoint
=
BREAKPOINTS
[
i
];
break
;
if
(
breakpoint
.
test
(
date
,
now
))
{
return
breakpoint
;
}
}
}
}
return
{
delta
:
delta
,
breakpoint
:
breakpoint
,
};
}
}
function
nextFuzzyUpdate
(
date
)
{
function
nextFuzzyUpdate
(
date
)
{
...
@@ -42,13 +151,12 @@ function nextFuzzyUpdate(date) {
...
@@ -42,13 +151,12 @@ function nextFuzzyUpdate(date) {
return
null
;
return
null
;
}
}
var
breakpoint
=
getBreakpoint
(
date
).
breakpoint
;
var
secs
=
getBreakpoint
(
date
,
new
Date
()).
nextUpdate
;
if
(
!
breakpoint
)
{
if
(
secs
===
null
)
{
return
null
;
return
null
;
}
}
var
secs
=
breakpoint
[
2
];
// We don't want to refresh anything more often than 5 seconds
// We don't want to refresh anything more often than 5 seconds
secs
=
Math
.
max
(
secs
,
5
);
secs
=
Math
.
max
(
secs
,
5
);
...
@@ -73,6 +181,9 @@ function decayingInterval(date, callback) {
...
@@ -73,6 +181,9 @@ function decayingInterval(date, callback) {
var
timer
;
var
timer
;
var
update
=
function
()
{
var
update
=
function
()
{
var
fuzzyUpdate
=
nextFuzzyUpdate
(
date
);
var
fuzzyUpdate
=
nextFuzzyUpdate
(
date
);
if
(
fuzzyUpdate
===
null
)
{
return
;
}
var
nextUpdate
=
(
1000
*
fuzzyUpdate
)
+
500
;
var
nextUpdate
=
(
1000
*
fuzzyUpdate
)
+
500
;
timer
=
setTimeout
(
function
()
{
timer
=
setTimeout
(
function
()
{
callback
(
date
);
callback
(
date
);
...
@@ -92,19 +203,13 @@ function decayingInterval(date, callback) {
...
@@ -92,19 +203,13 @@ function decayingInterval(date, callback) {
* @param {number} date - The absolute timestamp to format.
* @param {number} date - The absolute timestamp to format.
* @return {string} A 'fuzzy' string describing the relative age of the date.
* @return {string} A 'fuzzy' string describing the relative age of the date.
*/
*/
function
toFuzzyString
(
date
)
{
function
toFuzzyString
(
date
,
Intl
)
{
if
(
!
date
)
{
if
(
!
date
)
{
return
''
;
return
''
;
}
}
var
breakpointInfo
=
getBreakpoint
(
date
);
var
now
=
new
Date
();
var
breakpoint
=
breakpointInfo
.
breakpoint
;
var
delta
=
breakpointInfo
.
delta
;
return
getBreakpoint
(
date
,
now
).
format
(
new
Date
(
date
),
now
,
Intl
);
if
(
!
breakpoint
)
{
return
''
;
}
var
template
=
breakpoint
[
1
];
var
resolution
=
breakpoint
[
2
];
return
template
.
replace
(
'{}'
,
String
(
Math
.
floor
(
delta
/
resolution
)));
}
}
module
.
exports
=
{
module
.
exports
=
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment