Implement localized datetimes in browser

moment-timezone require config

jasmine test fix, duplicate req. cleanup
This commit is contained in:
Greg Martin
2016-10-11 10:51:12 -04:00
committed by Gregory Martin
parent 65723e2b12
commit 4ddda443b8
19 changed files with 12915 additions and 105 deletions

View File

@@ -50,8 +50,8 @@
'jquery.immediateDescendents': 'coffee/src/jquery.immediateDescendents',
'datepair': 'js/vendor/timepicker/datepair',
'date': 'js/vendor/date',
'moment': 'js/vendor/moment.min',
'moment-with-locales': 'js/vendor/moment-with-locales.min',
moment: 'common/js/vendor/moment-with-locales',
'moment-timezone': 'common/js/vendor/moment-timezone-with-data',
'text': 'js/vendor/requirejs/text',
'underscore': 'common/js/vendor/underscore',
'underscore.string': 'common/js/vendor/underscore.string',

View File

@@ -32,8 +32,7 @@
'jquery.simulate': 'xmodule_js/common_static/js/vendor/jquery.simulate',
'datepair': 'xmodule_js/common_static/js/vendor/timepicker/datepair',
'date': 'xmodule_js/common_static/js/vendor/date',
'moment': 'xmodule_js/common_static/js/vendor/moment.min',
'moment-with-locales': 'xmodule_js/common_static/js/vendor/moment-with-locales.min',
moment: 'common/js/vendor/moment-with-locales',
'text': 'xmodule_js/common_static/js/vendor/requirejs/text',
'underscore': 'common/js/vendor/underscore',
'underscore.string': 'common/js/vendor/underscore.string',

View File

@@ -32,7 +32,7 @@ var options = {
{pattern: 'common_static/js/vendor/jquery-ui.min.js', included: true},
{pattern: 'common_static/js/vendor/jquery.ui.draggable.js', included: true},
{pattern: 'common_static/js/vendor/json2.js', included: true},
{pattern: 'common_static/js/vendor/moment.min.js', included: true},
{pattern: 'common_static/js/vendor/moment-with-locales.js', included: true},
{pattern: 'common_static/js/vendor/tinymce/js/tinymce/jquery.tinymce.min.js', included: true},
{pattern: 'common_static/js/vendor/tinymce/js/tinymce/tinymce.full.min.js', included: true},
{pattern: 'common_static/js/src/accessibility_tools.js', included: true},

View File

@@ -34,7 +34,7 @@
requirejs.config({
baseUrl: '/base/',
paths: {
'moment': 'common_static/js/vendor/moment.min',
moment: 'common_static/js/vendor/moment-with-locales',
'draggabilly': 'common_static/js/vendor/draggabilly',
'edx-ui-toolkit': 'common_static/edx-ui-toolkit'
},

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -919,7 +919,7 @@ class ViewsTestCase(ModuleStoreTestCase):
)
# removes newlines and whitespace from the returned view string
view = ''.join(render_accordion(request, self.course, table_of_contents['chapters']).split())
view = ''.join(render_accordion(request, self.course, table_of_contents['chapters'], 'en').split())
# the course id unicode is re-encoded here because the quote function does not accept unicode
course_id = quote(unicode(self.course.id).encode("utf-8"))

View File

@@ -398,7 +398,12 @@ class CoursewareIndex(View):
self.section_url_name,
self.field_data_cache,
)
courseware_context['accordion'] = render_accordion(self.request, self.course, table_of_contents['chapters'])
courseware_context['accordion'] = render_accordion(
self.request,
self.course,
table_of_contents['chapters'],
courseware_context['language_preference'],
)
# entrance exam data
if course_has_entrance_exam(self.course):
@@ -494,7 +499,7 @@ class CoursewareIndex(View):
raise
def render_accordion(request, course, table_of_contents):
def render_accordion(request, course, table_of_contents, language_preference):
"""
Returns the HTML that renders the navigation for the given course.
Expects the table_of_contents to have data on each chapter and section,
@@ -506,7 +511,9 @@ def render_accordion(request, course, table_of_contents):
('course_id', unicode(course.id)),
('csrf', csrf(request)['csrf_token']),
('due_date_display_format', course.due_date_display_format),
('time_zone', get_user_time_zone(request.user).zone),
('time_zone', request.user.preferences.model.get_value(request.user, "time_zone", None)),
('language', language_preference),
] + TEMPLATE_IMPORTS.items()
)
return render_to_string('courseware/accordion.html', context)

View File

@@ -1,6 +1,6 @@
define(['jquery',
'underscore',
'moment-with-locales',
'moment',
'teams/js/views/team_card',
'teams/js/models/team'],
function($, _, moment, TeamCardView, Team) {

View File

@@ -5,7 +5,7 @@
'backbone',
'underscore',
'gettext',
'moment-with-locales',
'moment',
'js/components/card/views/card',
'teams/js/views/team_utils',
'text!teams/templates/team-membership-details.underscore',

View File

@@ -1567,7 +1567,7 @@ PIPELINE_JS = {
[
'js/sticky_filter.js',
'js/query-params.js',
'js/vendor/moment-with-locales.min.js',
'common/js/vendor/moment-with-locales.js',
]
),
'output_filename': 'js/lms-application.js',
@@ -1715,7 +1715,7 @@ REQUIRE_ENVIRONMENT = "node"
REQUIRE_JS_PATH_OVERRIDES = {
'js/bookmarks/views/bookmark_button': 'js/bookmarks/views/bookmark_button.js',
'js/views/message_banner': 'js/views/message_banner.js',
'moment': 'js/vendor/moment-with-locales.min.js',
'moment': 'common/js/vendor/moment-with-locales.js',
'js/courseware/course_home_events': 'js/courseware/course_home_events.js',
'js/courseware/accordion_events': 'js/courseware/accordion_events.js',
'js/courseware/link_clicked_events': 'js/courseware/link_clicked_events.js',

View File

@@ -0,0 +1,91 @@
/**
*
* A helper function to utilize DateUtils quickly in display templates.
*
* @param: {string} data-datetime A pre-localized datetime string, assumed to be in UTC.
* @param: {string} lang The user's preferred language.
* @param: {string} data-timezone (optional) A user-set timezone preference.
* @param: {object} data-format (optional) a format constant as defined in DataUtil.dateFormatEnum.
* @param: {string} data-string (optional) a string for parsing through StringUtils after localizing
* datetime
*
* @return: {string} a user-time, localized, formatted datetime string
*
*/
(function(define) {
'use strict';
define([
'jquery',
'edx-ui-toolkit/js/utils/date-utils',
'edx-ui-toolkit/js/utils/string-utils'
], function($, DateUtils, StringUtils) {
var DateUtilFactory;
var localizedTime;
var stringHandler;
var displayDatetime;
var isValid;
var transform;
transform = function(iterationKey) {
var context;
$(iterationKey).each(function() {
if (isValid($(this).data('datetime'))) {
context = {
datetime: $(this).data('datetime'),
timezone: $(this).data('timezone'),
language: $(this).attr('lang'),
format: $(this).data('format')
};
displayDatetime = stringHandler(
localizedTime(context),
$(this).data('string'),
$(this).data('datetoken')
);
$(this).text(displayDatetime);
}
});
};
localizedTime = function(context) {
return DateUtils.localize(context);
};
stringHandler = function(localTimeString, containerString, token) {
var returnString;
var interpolateDict = {};
var dateToken;
if (isValid(token)) {
dateToken = token;
} else {
dateToken = 'date';
}
interpolateDict[dateToken] = localTimeString;
if (isValid(containerString)) {
returnString = StringUtils.interpolate(
containerString,
interpolateDict
);
} else {
returnString = localTimeString;
}
return returnString;
};
isValid = function(candidateVariable) {
return candidateVariable !== undefined
&& candidateVariable !== ''
&& candidateVariable !== 'Invalid date'
&& candidateVariable !== 'None';
};
DateUtilFactory = {
transform: transform,
stringHandler: stringHandler
};
return DateUtilFactory;
});
}).call(this, define || RequireJS.define);

View File

@@ -0,0 +1,50 @@
define(['../dateutil_factory.js'], function(DateUtilIterator) {
'use strict';
describe('DateUtilFactory', function() {
beforeEach(function() {
setFixtures('<div class="test"></div>');
});
describe('stringHandler', function() {
it('returns a complete string', function() {
var localTimeString = 'RANDOM_STRING';
var containerString = 'RANDOM_STRING_TWO {random_token}';
var dateToken = 'random_token';
var answer = 'RANDOM_STRING_TWO RANDOM_STRING';
expect(DateUtilIterator.stringHandler(localTimeString, containerString, dateToken)).toEqual(answer);
});
});
describe('transform', function() {
var $form;
it('localizes some times', function() {
/* we have to generate a fake span and then test the resultant texts */
var iterationKey = '.localized-datetime';
var testLangs = {
en: 'Due Oct 14, 2016 08:00 UTC',
ru: 'Due 14 окт. 2016 г. 08:00 UTC',
ar: 'Due ١٤ تشرين الأول أكتوبر ٢٠١٦ ٠٨:٠٠ UTC',
fr: 'Due 14 oct. 2016 08:00 UTC'
};
$form = $(
'<span class="subtitle-name localized-datetime" ' +
'data-timezone="UTC" ' +
'data-datetime="2016-10-14 08:00:00+00:00" ' +
'data-string="Due {date}"></span>'
);
Object.keys(testLangs).forEach(function(key) {
$form.attr('lang', String(key));
$(document.body).append($form);
DateUtilIterator.transform(iterationKey);
expect($form.text()).toEqual(testLangs[key]);
$form.remove();
});
$form = null;
});
});
});
});

View File

@@ -57,8 +57,8 @@
paths: {
'annotator_1.2.9': 'js/vendor/edxnotes/annotator-full.min',
'date': 'js/vendor/date',
'moment': 'js/vendor/moment.min',
'moment-with-locales': 'xmodule_js/common_static/js/vendor/moment-with-locales.min',
moment: 'common/js/vendor/moment-with-locales',
'moment-timezone': 'common/js/vendor/moment-timezone-with-data',
'text': 'js/vendor/requirejs/text',
'logger': 'js/src/logger',
'backbone': 'common/js/vendor/backbone',
@@ -212,8 +212,9 @@
'moment': {
exports: 'moment'
},
'moment-with-locales': {
exports: 'moment'
'moment-timezone': {
exports: 'moment',
deps: ['moment']
},
// Because Draggabilly is being used by video code, the namespaced version of
// require is not being recognized. Therefore the library is being added to the

View File

@@ -32,8 +32,8 @@
'jquery.url': 'xmodule_js/common_static/js/vendor/url.min',
'datepair': 'xmodule_js/common_static/js/vendor/timepicker/datepair',
'date': 'xmodule_js/common_static/js/vendor/date',
'moment': 'xmodule_js/common_static/js/vendor/moment.min',
'moment-with-locales': 'xmodule_js/common_static/js/vendor/moment-with-locales.min',
moment: 'common/js/vendor/moment-with-locales',
'moment-timezone': 'common/js/vendor/moment-timezone-with-data',
'text': 'xmodule_js/common_static/js/vendor/requirejs/text',
'underscore': 'common/js/vendor/underscore',
'underscore.string': 'common/js/vendor/underscore.string',
@@ -731,6 +731,7 @@
'js/spec/learner_dashboard/course_card_view_spec.js',
'js/spec/learner_dashboard/course_enroll_view_spec.js',
'js/spec/markdown_editor_spec.js',
'js/spec/dateutil_factory_spec.js',
'js/spec/navigation_spec.js',
'js/spec/search/search_spec.js',
'js/spec/shoppingcart/shoppingcart_spec.js',

View File

@@ -34,7 +34,7 @@
requirejs.config({
baseUrl: '/base/',
paths: {
'moment': 'xmodule_js/common_static/js/vendor/moment.min',
moment: 'xmodule_js/common_static/js/vendor/moment-with-locales',
'draggabilly': 'xmodule_js/common_static/js/vendor/draggabilly',
'edx-ui-toolkit': 'edx-ui-toolkit'
},

View File

@@ -6,7 +6,7 @@
"backbone-validation": "~0.11.5",
"coffee-script": "1.6.1",
"edx-pattern-library": "0.16.6",
"edx-ui-toolkit": "1.4.1",
"edx-ui-toolkit": "1.5.0",
"jquery": "~2.2.0",
"jquery-migrate": "^1.4.1",
"jquery.scrollto": "~2.1.2",

View File

@@ -55,6 +55,8 @@ NPM_INSTALLED_LIBRARIES = [
'backbone/backbone.js',
'edx-ui-toolkit/node_modules/backbone.paginator/lib/backbone.paginator.js',
'backbone-validation/dist/backbone-validation-min.js',
'edx-ui-toolkit/node_modules/moment-timezone/builds/moment-timezone-with-data.js',
'edx-ui-toolkit/node_modules/moment/min/moment-with-locales.js',
]
# Directory to install static vendor files