Commit f020d1c5 by Oleg Marshev

Show date and time on Schedules and Details in UTC (TNL-85).

parent 89e89d2a
define(["backbone", "underscore", "gettext"], function(Backbone, _, gettext) { define(["backbone", "underscore", "gettext", "date"], function(Backbone, _, gettext, date) {
var CourseDetails = Backbone.Model.extend({ var CourseDetails = Backbone.Model.extend({
defaults: { defaults: {
...@@ -21,16 +21,16 @@ var CourseDetails = Backbone.Model.extend({ ...@@ -21,16 +21,16 @@ var CourseDetails = Backbone.Model.extend({
// When init'g from html script, ensure you pass {parse: true} as an option (2nd arg to reset) // When init'g from html script, ensure you pass {parse: true} as an option (2nd arg to reset)
parse: function(attributes) { parse: function(attributes) {
if (attributes['start_date']) { if (attributes['start_date']) {
attributes.start_date = new Date(attributes.start_date); attributes.start_date = date.parse(attributes.start_date);
} }
if (attributes['end_date']) { if (attributes['end_date']) {
attributes.end_date = new Date(attributes.end_date); attributes.end_date = date.parse(attributes.end_date);
} }
if (attributes['enrollment_start']) { if (attributes['enrollment_start']) {
attributes.enrollment_start = new Date(attributes.enrollment_start); attributes.enrollment_start = date.parse(attributes.enrollment_start);
} }
if (attributes['enrollment_end']) { if (attributes['enrollment_end']) {
attributes.enrollment_end = new Date(attributes.enrollment_end); attributes.enrollment_end = date.parse(attributes.enrollment_end);
} }
return attributes; return attributes;
}, },
......
define(["js/views/validation", "codemirror", "underscore", "jquery", "jquery.ui", "tzAbbr", "js/models/uploads", define(["js/views/validation", "codemirror", "underscore", "jquery", "jquery.ui", "js/utils/date_utils", "js/models/uploads",
"js/views/uploads", "js/utils/change_on_enter", "jquery.timepicker", "date"], "js/views/uploads", "js/utils/change_on_enter", "jquery.timepicker", "date"],
function(ValidatingView, CodeMirror, _, $, ui, tzAbbr, FileUploadModel, FileUploadDialog, TriggerChangeEventOnEnter) { function(ValidatingView, CodeMirror, _, $, ui, DateUtils, FileUploadModel, FileUploadDialog, TriggerChangeEventOnEnter) {
var DetailsView = ValidatingView.extend({ var DetailsView = ValidatingView.extend({
// Model class is CMS.Models.Settings.CourseDetails // Model class is CMS.Models.Settings.CourseDetails
...@@ -12,7 +12,7 @@ var DetailsView = ValidatingView.extend({ ...@@ -12,7 +12,7 @@ var DetailsView = ValidatingView.extend({
"change textarea" : "updateModel", "change textarea" : "updateModel",
'click .remove-course-introduction-video' : "removeVideo", 'click .remove-course-introduction-video' : "removeVideo",
'focus #course-overview' : "codeMirrorize", 'focus #course-overview' : "codeMirrorize",
'mouseover #timezone' : "updateTime", 'mouseover .timezone' : "updateTime",
// would love to move to a general superclass, but event hashes don't inherit in backbone :-( // would love to move to a general superclass, but event hashes don't inherit in backbone :-(
'focus :input' : "inputFocus", 'focus :input' : "inputFocus",
'blur :input' : "inputUnfocus", 'blur :input' : "inputUnfocus",
...@@ -35,8 +35,6 @@ var DetailsView = ValidatingView.extend({ ...@@ -35,8 +35,6 @@ var DetailsView = ValidatingView.extend({
$(this).show(); $(this).show();
}); });
this.$el.find('#timezone').html("(" + tzAbbr() + ")");
this.listenTo(this.model, 'invalid', this.handleValidationError); this.listenTo(this.model, 'invalid', this.handleValidationError);
this.listenTo(this.model, 'change', this.showNotificationBar); this.listenTo(this.model, 'change', this.showNotificationBar);
this.selectorToField = _.invert(this.fieldToSelectorMap); this.selectorToField = _.invert(this.fieldToSelectorMap);
...@@ -81,11 +79,15 @@ var DetailsView = ValidatingView.extend({ ...@@ -81,11 +79,15 @@ var DetailsView = ValidatingView.extend({
}, },
updateTime : function(e) { updateTime : function(e) {
var now = new Date(); var now = new Date(),
var hours = now.getHours(); hours = now.getUTCHours(),
var minutes = now.getMinutes(); minutes = now.getUTCMinutes(),
$(e.currentTarget).attr('title', (hours % 12 === 0 ? 12 : hours % 12) + ":" + (minutes < 10 ? "0" : "") + currentTimeText = gettext('%(hours)s:%(minutes)s (current UTC time)');
now.getMinutes() + (hours < 12 ? "am" : "pm") + " (current local time)");
$(e.currentTarget).attr('title', interpolate(currentTimeText, {
'hours': hours,
'minutes': minutes
}, true));
}, },
setupDatePicker: function (fieldName) { setupDatePicker: function (fieldName) {
...@@ -95,13 +97,8 @@ var DetailsView = ValidatingView.extend({ ...@@ -95,13 +97,8 @@ var DetailsView = ValidatingView.extend({
var timefield = $(div).find("input:.time"); var timefield = $(div).find("input:.time");
var cachethis = this; var cachethis = this;
var setfield = function () { var setfield = function () {
var date = datefield.datepicker('getDate'); var newVal = DateUtils.getDate(datefield, timefield);
if (date) { if (newVal) {
var time = timefield.timepicker("getSecondsFromMidnight");
if (!time) {
time = 0;
}
var newVal = new Date(date.getTime() + time * 1000);
if (!cacheModel.has(fieldName) || cacheModel.get(fieldName).getTime() !== newVal.getTime()) { if (!cacheModel.has(fieldName) || cacheModel.get(fieldName).getTime() !== newVal.getTime()) {
cachethis.clearValidationErrors(); cachethis.clearValidationErrors();
cachethis.setAndValidate(fieldName, newVal); cachethis.setAndValidate(fieldName, newVal);
...@@ -126,13 +123,14 @@ var DetailsView = ValidatingView.extend({ ...@@ -126,13 +123,14 @@ var DetailsView = ValidatingView.extend({
timefield.on('changeTime', setfield); timefield.on('changeTime', setfield);
timefield.on('input', setfield); timefield.on('input', setfield);
datefield.datepicker('setDate', this.model.get(fieldName)); date = this.model.get(fieldName)
// timepicker doesn't let us set null, so check that we have a time // timepicker doesn't let us set null, so check that we have a time
if (this.model.has(fieldName)) { if (date) {
timefield.timepicker('setTime', this.model.get(fieldName)); DateUtils.setDate(datefield, timefield, date);
} // but reset the field either way } // but reset fields either way
else { else {
timefield.val(''); timefield.val('');
datefield.val('');
} }
}, },
......
...@@ -69,7 +69,6 @@ ...@@ -69,7 +69,6 @@
"jquery.immediateDescendents": "coffee/src/jquery.immediateDescendents", "jquery.immediateDescendents": "coffee/src/jquery.immediateDescendents",
"datepair": "js/vendor/timepicker/datepair", "datepair": "js/vendor/timepicker/datepair",
"date": "js/vendor/date", "date": "js/vendor/date",
"tzAbbr": "js/vendor/tzAbbr",
"underscore": "js/vendor/underscore-min", "underscore": "js/vendor/underscore-min",
"underscore.string": "js/vendor/underscore.string.min", "underscore.string": "js/vendor/underscore.string.min",
"backbone": "js/vendor/backbone-min", "backbone": "js/vendor/backbone-min",
......
...@@ -152,7 +152,7 @@ require(["domReady!", "jquery", "js/models/settings/course_details", "js/views/s ...@@ -152,7 +152,7 @@ require(["domReady!", "jquery", "js/models/settings/course_details", "js/views/s
<div class="field time" id="field-course-start-time"> <div class="field time" id="field-course-start-time">
<label for="course-start-time">${_("Course Start Time")}</label> <label for="course-start-time">${_("Course Start Time")}</label>
<input type="text" class="time start timepicker" id="course-start-time" value="" placeholder="HH:MM" autocomplete="off" /> <input type="text" class="time start timepicker" id="course-start-time" value="" placeholder="HH:MM" autocomplete="off" />
<span class="tip tip-stacked" id="timezone"></span> <span class="tip tip-stacked timezone">${_("(UTC)")}</span>
</div> </div>
</li> </li>
...@@ -166,7 +166,7 @@ require(["domReady!", "jquery", "js/models/settings/course_details", "js/views/s ...@@ -166,7 +166,7 @@ require(["domReady!", "jquery", "js/models/settings/course_details", "js/views/s
<div class="field time" id="field-course-end-time"> <div class="field time" id="field-course-end-time">
<label for="course-end-time">${_("Course End Time")}</label> <label for="course-end-time">${_("Course End Time")}</label>
<input type="text" class="time end" id="course-end-time" value="" placeholder="HH:MM" autocomplete="off" /> <input type="text" class="time end" id="course-end-time" value="" placeholder="HH:MM" autocomplete="off" />
<span class="tip tip-stacked" id="timezone"></span> <span class="tip tip-stacked timezone">${_("(UTC)")}</span>
</div> </div>
</li> </li>
</ol> </ol>
...@@ -182,7 +182,7 @@ require(["domReady!", "jquery", "js/models/settings/course_details", "js/views/s ...@@ -182,7 +182,7 @@ require(["domReady!", "jquery", "js/models/settings/course_details", "js/views/s
<div class="field time" id="field-enrollment-start-time"> <div class="field time" id="field-enrollment-start-time">
<label for="course-enrollment-start-time">${_("Enrollment Start Time")}</label> <label for="course-enrollment-start-time">${_("Enrollment Start Time")}</label>
<input type="text" class="time start" id="course-enrollment-start-time" value="" placeholder="HH:MM" autocomplete="off" /> <input type="text" class="time start" id="course-enrollment-start-time" value="" placeholder="HH:MM" autocomplete="off" />
<span class="tip tip-stacked" id="timezone"></span> <span class="tip tip-stacked timezone">${_("(UTC)")}</span>
</div> </div>
</li> </li>
...@@ -196,7 +196,7 @@ require(["domReady!", "jquery", "js/models/settings/course_details", "js/views/s ...@@ -196,7 +196,7 @@ require(["domReady!", "jquery", "js/models/settings/course_details", "js/views/s
<div class="field time" id="field-enrollment-end-time"> <div class="field time" id="field-enrollment-end-time">
<label for="course-enrollment-end-time">${_("Enrollment End Time")}</label> <label for="course-enrollment-end-time">${_("Enrollment End Time")}</label>
<input type="text" class="time end" id="course-enrollment-end-time" value="" placeholder="HH:MM" autocomplete="off" /> <input type="text" class="time end" id="course-enrollment-end-time" value="" placeholder="HH:MM" autocomplete="off" />
<span class="tip tip-stacked" id="timezone"></span> <span class="tip tip-stacked timezone">${_("(UTC)")}</span>
</div> </div>
</li> </li>
</ol> </ol>
......
/* Friendly timezone abbreviations in client-side JavaScript
`tzAbbr()` or `tzAbbr(new Date(79,5,24))`
=> "EDT", "CST", "GMT", etc.!
There's no 100% reliable way to get friendly timezone names in all
browsers using JS alone, but this tiny function scours a
stringified date as best it can and returns `null` in the few cases
where no friendly timezone name is found (so far, just Opera).
Device tested & works in:
* IE 6 [through] 11 (latest versions of all)
* Firefox 3 [through] 16 (16 = latest version to date)
* Chrome 22 (latest version to date)
* Safari 6 (latest version to date)
* Mobile Safari on iOS 5 & 6
* Android 4.0.3 stock browser
* Android 2.3.7 stock browser
* IE Mobile 9 (WP 7.5)
Known to fail in:
* Opera 12 (desktop, latest version to date)
For Opera, I've included (but commented out) a workaround spotted
on StackOverflow that returns a GMT offset when no abbreviation is
found. I haven't found a decent workaround.
If you find any other cases where this method returns null or dodgy
results, please say so in the comments; even if we can't find a
workaround it'll at least help others determine if this approach is
suitable for their project!
*/
define([], function() {
return function (dateInput) {
var dateObject = dateInput || new Date(),
dateString = dateObject + "",
tzAbbr = (
// Works for the majority of modern browsers
dateString.match(/\(([^\)]+)\)$/) ||
// IE outputs date strings in a different format:
dateString.match(/([A-Z]+) [\d]{4}$/)
);
if (tzAbbr) {
// Old Firefox uses the long timezone name (e.g., "Central
// Daylight Time" instead of "CDT")
/*
If the timezone string does not cotain capital English letters
(For example, the timezone string may be a Chinese string),
then the following code line will produce a null-reference
exception, and the execution of the javascript codes will
be stopped, which may cause some strange behaviors. So a
try-catch is needed here to prevent the execution being stopped.
*/
try {
tzAbbr = tzAbbr[1].match(/[A-Z]/g).join("");
} catch(err) {
tzAbbr = tzAbbr[1];
}
}
// Uncomment these lines to return a GMT offset for browsers
// that don't include the user's zone abbreviation (e.g.,
// "GMT-0500".) I prefer to have `null` in this case, but
// you may not!
// First seen on: http://stackoverflow.com/a/12496442
// if (!tzAbbr && /(GMT\W*\d{4})/.test(dateString)) {
// return RegExp.$1;
// }
return tzAbbr;
};
});
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment