prefer tDateToString/tTimeToString over strftime
refs CNVS-19516 the {{strftime}} handlebars helper requires use of a hard-coded format string that's locale-unaware. tDateToString and tTimeToString take localization keys so that you get a format string appropriate to the locale. the remaining calls to {{strftime}} are for fixed-format machine-oriented strings, where they shouldn't be localized. this is an appropriate use, but really the only time {{strftime}} should be used. additionally, for all but the calendar agenda view, these should have been using fudged values ({{strftime}}, {{tTimeToString}} and {{tDateToString}} all expect fudged dates as input). fix that, too, while we're in here. finally, while adding specs, found that Date.parse doesn't like milliseconds, which meant dates weren't actually happening in the assignment-related specs; fixed that by switching to tz.parse. Since the values being parsed were explicitly UTC, this doesn't change the parsing semantics (e.g. fudged vs. not) test-plan: - set Norwegian as your locale [edit assignment dialog] - create an assignment with multiple due dates - go back to the assignment list, and choose the edit dialog from the cog menu - the tool-tip on the "Due" field should include the multiple dates formatted as "<day> <month>" rather than "<month> <day>" - also check same field for timezone consistency when profile timezone does not match browser timezone [assignment page] - for the same assignment, click through to the assignment's page - the due dates should display as "<day> <month>" rather than "<month> <day>" - also check same field for timezone consistency when profile timezone does not match browser timezone [availability column in assignment list] - for the same assignment - make one due date have an unlock at in the past and lock at in the future - make another due date have an unlock at in the future - view the assignment list - the tool-tip on "Multiple Dates" next to "Available" should have "<day> <month>" instead of "<month> <day>" for both the "Available until" (first section) value and the "Not available until" (second section) value - also check same field for timezone consistency when profile timezone does not match browser timezone [calendar agenda view] - go to the calendar agenda view - the due date times for future assignments should have 24-hour formatting, not 12-hour - the event dates for future non-assignment events should also have 24-hour formatting - also check same fields for timezone consistency when profile timezone does not match browser timezone [feature flags] - go to the feature flags pane in course settings - the "Estimated Release" for "New Quiz Statistics Page" should format "<day> <month> <year>", not "<month> <day>, <year>" Change-Id: I0226cc14adcd39eceaa0e5f4bf66e0eefdc0bbf3 Reviewed-on: https://gerrit.instructure.com/51448 Reviewed-by: Cody Cutrer <cody@instructure.com> Reviewed-by: Jeremy Stanley <jeremy@instructure.com> Reviewed-by: Jonathan Featherstone <jfeatherstone@instructure.com> Reviewed-by: John Corrigan <jcorrigan@instructure.com> Tested-by: Jenkins QA-Review: August Thornton <august@instructure.com> Product-Review: Jacob Fugal <jacob@instructure.com>
This commit is contained in:
parent
0805dd3143
commit
43f8be381e
|
@ -3,7 +3,8 @@ define [
|
|||
'underscore'
|
||||
'jquery'
|
||||
'i18n!assignments'
|
||||
], (Backbone, _, $, I18n) ->
|
||||
'timezone'
|
||||
], (Backbone, _, $, I18n, tz) ->
|
||||
|
||||
class DateGroup extends Backbone.Model
|
||||
|
||||
|
@ -15,19 +16,19 @@ define [
|
|||
|
||||
dueAt: ->
|
||||
dueAt = @get("due_at")
|
||||
if dueAt then Date.parse(dueAt) else null
|
||||
if dueAt then tz.parse(dueAt) else null
|
||||
|
||||
unlockAt: ->
|
||||
unlockAt = @get("unlock_at")
|
||||
if unlockAt then Date.parse(unlockAt) else null
|
||||
if unlockAt then tz.parse(unlockAt) else null
|
||||
|
||||
lockAt: ->
|
||||
lockAt = @get("lock_at")
|
||||
if lockAt then Date.parse(lockAt) else null
|
||||
if lockAt then tz.parse(lockAt) else null
|
||||
|
||||
now: ->
|
||||
now = @get("now")
|
||||
if now then Date.parse(now) else new Date()
|
||||
if now then tz.parse(now) else new Date()
|
||||
|
||||
|
||||
# no lock/unlock dates
|
||||
|
@ -61,4 +62,4 @@ define [
|
|||
available: @available()
|
||||
pending: @pending()
|
||||
open: @open()
|
||||
closed: @closed()
|
||||
closed: @closed()
|
||||
|
|
|
@ -57,7 +57,7 @@
|
|||
{{#each allDates}}
|
||||
<div class="clearfix">
|
||||
<dt>{{dueFor}}</dt>
|
||||
<dd>{{#if dueAt}} {{strftime dueAt "%b %-d"}} {{else}} - {{/if}}</dd>
|
||||
<dd>{{#if dueAt}} {{tDateToString (fudge dueAt) 'short'}} {{else}} - {{/if}}</dd>
|
||||
</div>
|
||||
{{/each}}
|
||||
</dl>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<dd>
|
||||
{{#if dueAt}}
|
||||
<span {{contextSensitiveDatetimeTitle dueAt}}>
|
||||
{{strftime dueAt "%b %-d"}}
|
||||
{{tDateToString (fudge dueAt) 'short'}}
|
||||
</span>
|
||||
{{else}}
|
||||
-
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
{{#if pending}}
|
||||
<span class="status-description">{{#t "not_available_until"}}Not available until{{/t}}</span>
|
||||
<span {{ contextSensitiveDatetimeTitle unlockAt }}>
|
||||
{{strftime unlockAt "%b %-d"}}
|
||||
{{tDateToString (fudge unlockAt) 'short'}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
{{#if open}}
|
||||
<span class="status-description">{{#t "available_until"}}Available until{{/t}}</span>
|
||||
<span {{ contextSensitiveDatetimeTitle lockAt }}>
|
||||
{{strftime lockAt "%b %-d"}}
|
||||
{{tDateToString (fudge lockAt) 'short'}}
|
||||
</span>
|
||||
{{/if}}
|
||||
|
||||
|
|
|
@ -23,11 +23,11 @@
|
|||
<div class="ig-details">
|
||||
{{#if assignment}}
|
||||
<b>{{#t "due"}}Due{{/t}}</b><span class="screenreader-only">,</span>
|
||||
{{strftime originalStart "%l:%M%P"}}
|
||||
{{tTimeToString originalStart "tiny"}}
|
||||
{{else}}
|
||||
{{#unless all_day}}
|
||||
<span class="screenreader-only">{{#t "starts_at"}}Starts at{{/t}},</span>
|
||||
{{strftime originalStart "%l:%M%P"}}
|
||||
{{tTimeToString originalStart "tiny"}}
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
{{#if releaseOn}}
|
||||
{{#t "estimated_release"}}Estimated Release:{{/t}}
|
||||
<span class="feature-release-date">
|
||||
{{strftime releaseOn "%B %-d, %Y"}}
|
||||
{{tDateToString (fudge releaseOn) "medium"}}
|
||||
</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
|
|
@ -3,11 +3,14 @@ define [
|
|||
'underscore'
|
||||
'timezone'
|
||||
'vendor/timezone/America/Denver'
|
||||
'vendor/timezone/America/Juneau'
|
||||
'vendor/timezone/fr_FR'
|
||||
'compiled/views/calendar/AgendaView'
|
||||
'compiled/calendar/EventDataSource'
|
||||
'helpers/ajax_mocks/api/v1/calendarEvents'
|
||||
'helpers/ajax_mocks/api/v1/calendarAssignments'
|
||||
], ($, _, tz, denver, AgendaView, EventDataSource, eventResponse, assignmentResponse) ->
|
||||
'helpers/I18nStubber'
|
||||
], ($, _, tz, denver, juneau, french, AgendaView, EventDataSource, eventResponse, assignmentResponse, I18nStubber) ->
|
||||
loadEventPage = (server, includeNext = false) ->
|
||||
sendCustomEvents(server, eventResponse, assignmentResponse, includeNext)
|
||||
|
||||
|
@ -28,11 +31,13 @@ define [
|
|||
@server = sinon.fakeServer.create()
|
||||
@snapshot = tz.snapshot()
|
||||
tz.changeZone(denver, 'America/Denver')
|
||||
I18nStubber.pushFrame()
|
||||
|
||||
teardown: ->
|
||||
@container.remove()
|
||||
@server.restore()
|
||||
tz.restore(@snapshot)
|
||||
I18nStubber.popFrame()
|
||||
|
||||
test 'should render results', ->
|
||||
view = new AgendaView(el: @container, dataSource: @dataSource)
|
||||
|
@ -57,6 +62,11 @@ define [
|
|||
ok @container.find('.agenda-load-btn').length
|
||||
|
||||
test 'toJSON should properly serialize results', ->
|
||||
I18nStubber.stub 'en',
|
||||
'date.formats.short_with_weekday': '%a, %b %-d'
|
||||
'date.abbr_day_names.1': 'Mon'
|
||||
'date.abbr_month_names.10': 'Oct'
|
||||
|
||||
view = new AgendaView(el: @container, dataSource: @dataSource)
|
||||
view.fetch(@contextCodes, @startDate)
|
||||
loadEventPage(@server)
|
||||
|
@ -101,3 +111,53 @@ define [
|
|||
sendCustomEvents(@server, JSON.stringify(events), JSON.stringify([]), false, 2)
|
||||
|
||||
ok @container.find('.ig-row').length == 60, 'finds 60 ig-rows'
|
||||
|
||||
test 'renders non-assignment events with locale-appropriate format string', ->
|
||||
tz.changeLocale(french, 'fr_FR')
|
||||
I18nStubber.setLocale 'fr_FR'
|
||||
I18nStubber.stub 'fr_FR', 'time.formats.tiny': '%k:%M'
|
||||
|
||||
view = new AgendaView(el: @container, dataSource: @dataSource)
|
||||
view.fetch(@contextCodes, @startDate)
|
||||
loadEventPage(@server)
|
||||
|
||||
# this event has a start_at of 2013-10-08T20:30:00Z, or 1pm MDT
|
||||
ok @container.find('.ig-details').slice(2, 3).text().match(/13:00/), 'formats according to locale'
|
||||
|
||||
test 'renders assignment events with locale-appropriate format string', ->
|
||||
tz.changeLocale(french, 'fr_FR')
|
||||
I18nStubber.setLocale 'fr_FR'
|
||||
I18nStubber.stub 'fr_FR', 'time.formats.tiny': '%k:%M'
|
||||
|
||||
view = new AgendaView(el: @container, dataSource: @dataSource)
|
||||
view.fetch(@contextCodes, @startDate)
|
||||
loadEventPage(@server)
|
||||
|
||||
# this event has a start_at of 2013-10-13T05:59:59Z, or 11:59pm MDT
|
||||
ok @container.find('.ig-details').slice(12, 13).text().match(/23:59/), 'formats according to locale'
|
||||
|
||||
test 'renders non-assignment events in appropriate timezone', ->
|
||||
tz.changeZone(juneau, 'America/Juneau')
|
||||
I18nStubber.stub 'en',
|
||||
'time.formats.tiny': '%l:%M%P'
|
||||
'date': {}
|
||||
|
||||
view = new AgendaView(el: @container, dataSource: @dataSource)
|
||||
view.fetch(@contextCodes, @startDate)
|
||||
loadEventPage(@server)
|
||||
|
||||
# this event has a start_at of 2013-10-08T20:30:00Z, or 11:00am AKDT
|
||||
ok @container.find('.ig-details').slice(2, 3).text().match(/11:00am/), 'formats in correct timezone'
|
||||
|
||||
test 'renders assignment events in appropriate timezone', ->
|
||||
tz.changeZone(juneau, 'America/Juneau')
|
||||
I18nStubber.stub 'en',
|
||||
'time.formats.tiny': '%l:%M%P'
|
||||
'date': {}
|
||||
|
||||
view = new AgendaView(el: @container, dataSource: @dataSource)
|
||||
view.fetch(@contextCodes, @startDate)
|
||||
loadEventPage(@server)
|
||||
|
||||
# this event has a start_at of 2013-10-13T05:59:59Z, or 9:59pm AKDT
|
||||
ok @container.find('.ig-details').slice(12, 13).text().match(/9:59pm/), 'formats in correct timezone'
|
||||
|
|
|
@ -4,9 +4,13 @@ define [
|
|||
'compiled/models/Submission'
|
||||
'compiled/views/assignments/AssignmentListItemView'
|
||||
'jquery'
|
||||
'timezone'
|
||||
'vendor/timezone/America/Juneau'
|
||||
'vendor/timezone/fr_FR'
|
||||
'helpers/I18nStubber'
|
||||
'helpers/fakeENV'
|
||||
'helpers/jquery.simulate'
|
||||
], (Backbone, Assignment, Submission, AssignmentListItemView, $, fakeENV) ->
|
||||
], (Backbone, Assignment, Submission, AssignmentListItemView, $, tz, juneau, french, I18nStubber, fakeENV) ->
|
||||
screenreaderText = null
|
||||
nonScreenreaderText = null
|
||||
|
||||
|
@ -144,9 +148,15 @@ define [
|
|||
setup: ->
|
||||
genSetup.call @
|
||||
|
||||
@snapshot = tz.snapshot()
|
||||
I18nStubber.pushFrame()
|
||||
|
||||
teardown: ->
|
||||
genTeardown.call @
|
||||
|
||||
tz.restore(@snapshot)
|
||||
I18nStubber.popFrame()
|
||||
|
||||
test "initializes child views if can manage", ->
|
||||
view = createView(@model, canManage: true)
|
||||
ok view.publishIconView
|
||||
|
@ -310,6 +320,57 @@ define [
|
|||
equal spy.callCount, 0
|
||||
AssignmentListItemView.prototype.updateScore.restore()
|
||||
|
||||
test "renders lockAt/unlockAt with locale-appropriate format string", ->
|
||||
tz.changeLocale(french, 'fr_FR')
|
||||
I18nStubber.setLocale 'fr_FR'
|
||||
I18nStubber.stub 'fr_FR',
|
||||
'date.formats.short': '%-d %b'
|
||||
'date.abbr_month_names.8': 'août'
|
||||
model = new AssignmentCollection([buildAssignment
|
||||
id: 1
|
||||
all_dates: [
|
||||
{ lock_at: "2113-08-28T04:00:00Z", title: "Summer Session" }
|
||||
{ unlock_at: "2113-08-28T04:00:00Z", title: "Winter Session" }]]).at(0)
|
||||
|
||||
view = createView(model, canManage: true)
|
||||
$dds = view.dateAvailableColumnView.$("#vdd_tooltip_#{@model.id}_lock div")
|
||||
equal $("span", $dds.first()).last().text().trim(), '28 août'
|
||||
equal $("span", $dds.last()).last().text().trim(), '28 août'
|
||||
|
||||
test "renders lockAt/unlockAt in appropriate time zone", ->
|
||||
tz.changeZone(juneau, 'America/Juneau')
|
||||
I18nStubber.stub 'en',
|
||||
'date.formats.short': '%b %-d'
|
||||
'date.abbr_month_names.8': 'Aug'
|
||||
|
||||
model = new AssignmentCollection([buildAssignment
|
||||
id: 1
|
||||
all_dates: [
|
||||
{ lock_at: "2113-08-28T04:00:00Z", title: "Summer Session" }
|
||||
{ unlock_at: "2113-08-28T04:00:00Z", title: "Winter Session" }]]).at(0)
|
||||
|
||||
view = createView(model, canManage: true)
|
||||
$dds = view.dateAvailableColumnView.$("#vdd_tooltip_#{@model.id}_lock div")
|
||||
equal $("span", $dds.first()).last().text().trim(), 'Aug 27'
|
||||
equal $("span", $dds.last()).last().text().trim(), 'Aug 27'
|
||||
|
||||
test "renders due date column with locale-appropriate format string", ->
|
||||
tz.changeLocale(french, 'fr_FR')
|
||||
I18nStubber.setLocale 'fr_FR'
|
||||
I18nStubber.stub 'fr_FR',
|
||||
'date.formats.short': '%-d %b'
|
||||
'date.abbr_month_names.8': 'août'
|
||||
view = createView(@model, canManage: true)
|
||||
equal view.dateDueColumnView.$("#vdd_tooltip_#{@model.id}_due div dd").first().text().trim(), '29 août'
|
||||
|
||||
test "renders due date column in appropriate time zone", ->
|
||||
tz.changeZone(juneau, 'America/Juneau')
|
||||
I18nStubber.stub 'en',
|
||||
'date.formats.short': '%b %-d'
|
||||
'date.abbr_month_names.8': 'Aug'
|
||||
view = createView(@model, canManage: true)
|
||||
equal view.dateDueColumnView.$("#vdd_tooltip_#{@model.id}_due div dd").first().text().trim(), 'Aug 28'
|
||||
|
||||
module 'AssignmentListItemViewSpec—alternate grading type: percent',
|
||||
setup: ->
|
||||
genSetup.call @, assignment_grade_percent()
|
||||
|
|
|
@ -6,9 +6,13 @@ define [
|
|||
'compiled/views/assignments/CreateAssignmentView'
|
||||
'compiled/views/DialogFormView'
|
||||
'jquery'
|
||||
'timezone'
|
||||
'vendor/timezone/America/Juneau'
|
||||
'vendor/timezone/fr_FR'
|
||||
'helpers/I18nStubber'
|
||||
'helpers/jquery.simulate'
|
||||
'compiled/behaviors/tooltip'
|
||||
], (Backbone, AssignmentGroupCollection, AssignmentGroup, Assignment, CreateAssignmentView, DialogFormView, $) ->
|
||||
], (Backbone, AssignmentGroupCollection, AssignmentGroup, Assignment, CreateAssignmentView, DialogFormView, $, tz, juneau, french, I18nStubber) ->
|
||||
|
||||
fixtures = $('#fixtures')
|
||||
|
||||
|
@ -113,12 +117,18 @@ define [
|
|||
@assignment4 = assignment4()
|
||||
@group = assignmentGroup()
|
||||
|
||||
@snapshot = tz.snapshot()
|
||||
I18nStubber.pushFrame()
|
||||
|
||||
teardown: ->
|
||||
ENV.VALID_DATE_RANGE = {
|
||||
start_at: {date: null, date_context: null}
|
||||
end_at: {date: null, date_context: null}
|
||||
}
|
||||
|
||||
tz.restore(@snapshot)
|
||||
I18nStubber.popFrame()
|
||||
|
||||
test "initialize generates a new assignment for creation", ->
|
||||
view = createView(@group)
|
||||
equal view.model.get("assignment_group_id"), @group.get("id")
|
||||
|
@ -297,3 +307,19 @@ define [
|
|||
ok errors["due_at"]
|
||||
equal errors['due_at'][0]['message'], 'Due date cannot be before unlock date'
|
||||
|
||||
test "renders due dates with locale-appropriate format string", ->
|
||||
tz.changeLocale(french, 'fr_FR')
|
||||
I18nStubber.setLocale 'fr_FR'
|
||||
I18nStubber.stub 'fr_FR',
|
||||
'date.formats.short': '%-d %b'
|
||||
'date.abbr_month_names.8': 'août'
|
||||
view = createView(@assignment1)
|
||||
equal view.$("#vdd_tooltip_assign_1 div dd").first().text().trim(), '28 août'
|
||||
|
||||
test "renders due dates in appropriate time zone", ->
|
||||
tz.changeZone(juneau, 'America/Juneau')
|
||||
I18nStubber.stub 'en',
|
||||
'date.formats.short': '%b %-d'
|
||||
'date.abbr_month_names.8': 'Aug'
|
||||
view = createView(@assignment1)
|
||||
equal view.$("#vdd_tooltip_assign_1 div dd").first().text().trim(), 'Aug 27'
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
define [
|
||||
'compiled/views/feature_flags/FeatureFlagView'
|
||||
'compiled/models/FeatureFlag'
|
||||
'jquery'
|
||||
'timezone'
|
||||
'vendor/timezone/America/Juneau'
|
||||
'vendor/timezone/fr_FR'
|
||||
'helpers/I18nStubber'
|
||||
'helpers/fakeENV'
|
||||
], (FeatureFlagView, FeatureFlag, $, tz, juneau, french, I18nStubber, fakeENV) ->
|
||||
|
||||
module "FeatureFlagView",
|
||||
setup: ->
|
||||
@container = $('<div />', id: 'feature-flags').appendTo('#fixtures')
|
||||
@snapshot = tz.snapshot()
|
||||
I18nStubber.pushFrame()
|
||||
fakeENV.setup()
|
||||
|
||||
teardown: ->
|
||||
@container.remove()
|
||||
tz.restore(@snapshot)
|
||||
I18nStubber.popFrame()
|
||||
fakeENV.teardown()
|
||||
|
||||
test 'should format release date with locale-appropriate format string', ->
|
||||
releaseDate = tz.parse('2100-07-04T00:00:00Z')
|
||||
|
||||
tz.changeLocale(french, 'fr_FR')
|
||||
I18nStubber.setLocale 'fr_FR'
|
||||
I18nStubber.stub 'fr_FR',
|
||||
'date.formats.medium': '%-d %b %Y'
|
||||
'date.abbr_month_names.7': 'juil.'
|
||||
|
||||
flag = new FeatureFlag
|
||||
releaseOn: releaseDate
|
||||
feature_flag:
|
||||
transitions: {}
|
||||
view = new FeatureFlagView el: @container, model: flag
|
||||
view.render()
|
||||
|
||||
equal view.$('.feature-release-date').text().trim(), '4 juil. 2100'
|
||||
|
||||
test 'should format release date in locale-appropriate format string', ->
|
||||
releaseDate = tz.parse('2100-07-04T00:00:00Z')
|
||||
|
||||
tz.changeZone(juneau, 'America/Juneau')
|
||||
I18nStubber.stub 'en',
|
||||
'date.formats.medium': '%b %-d, %Y'
|
||||
'date.abbr_month_names.7': 'Jul'
|
||||
|
||||
flag = new FeatureFlag
|
||||
releaseOn: releaseDate
|
||||
feature_flag:
|
||||
transitions: {}
|
||||
view = new FeatureFlagView el: @container, model: flag
|
||||
view.render()
|
||||
|
||||
equal view.$('.feature-release-date').text().trim(), 'Jul 3, 2100'
|
Loading…
Reference in New Issue