Refactor staff preview menu logic out of template
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
**/vendor
|
||||
node_modules
|
||||
cms/static/js/i18n/**/*.js
|
||||
lms/static/js/i18n/**/*.js
|
||||
lms/static/lms/js/build.js
|
||||
lms/static/lms/js/spec/main.js
|
||||
node_modules
|
||||
venv
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
"immed" : true, // Prohibits the use of immediate function invocations without wrapping them in parentheses.
|
||||
// "indent" : 4, // Enforces specific tab width for your code. Has no effect when "white" option is not used.
|
||||
"latedef" : "nofunc", // Prohibits the use of a variable before it was defined. Setting this option to "nofunc" will allow function declarations to be ignored.
|
||||
"newcap" : true, // Requires you to capitalize names of constructor functions.
|
||||
"newcap" : false, // Requires you to capitalize names of constructor functions.
|
||||
"noarg" : true, // Prohibits the use of arguments.caller and arguments.callee.
|
||||
"noempty" : true, // Warns when you have an empty block in your code.
|
||||
"nonbsp" : true, // Warns about "non-breaking whitespace" characters.
|
||||
|
||||
@@ -29,12 +29,14 @@ var options = {
|
||||
sourceFiles: [
|
||||
{pattern: 'coffee/src/**/!(*spec).js'},
|
||||
{pattern: 'js/**/!(*spec|djangojs).js'},
|
||||
{pattern: 'lms/js/**/!(*spec).js'},
|
||||
{pattern: 'support/js/**/!(*spec).js'},
|
||||
{pattern: 'teams/js/**/!(*spec).js'}
|
||||
],
|
||||
|
||||
specFiles: [
|
||||
{pattern: 'js/spec/**/*spec.js'},
|
||||
{pattern: 'lms/js/spec/**/*spec.js'},
|
||||
{pattern: 'support/js/spec/**/*spec.js'},
|
||||
{pattern: 'teams/js/spec/**/*spec.js'},
|
||||
{pattern: 'xmodule_js/common_static/coffee/spec/**/*.js'}
|
||||
@@ -42,13 +44,14 @@ var options = {
|
||||
|
||||
fixtureFiles: [
|
||||
{pattern: 'js/fixtures/**/*.html'},
|
||||
{pattern: 'lms/fixtures/**/*.html'},
|
||||
{pattern: 'support/templates/**/*.*'},
|
||||
{pattern: 'teams/templates/**/*.*'},
|
||||
{pattern: 'templates/**/*.*'}
|
||||
],
|
||||
|
||||
runFiles: [
|
||||
{pattern: 'js/spec/main.js', included: true}
|
||||
{pattern: 'lms/js/spec/main.js', included: true}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ var options = {
|
||||
// Avoid adding files to this list. Use RequireJS.
|
||||
libraryFilesToInclude: [
|
||||
{pattern: 'xmodule_js/common_static/js/vendor/requirejs/require.js', included: true},
|
||||
{pattern: 'js/spec/main_requirejs_coffee.js', included: true},
|
||||
{pattern: 'lms/js/spec/main_requirejs_coffee.js', included: true},
|
||||
|
||||
{pattern: 'js/RequireJS-namespace-undefine.js', included: true},
|
||||
{pattern: 'xmodule_js/common_static/coffee/src/ajax_prefix.js', included: true},
|
||||
|
||||
23
lms/static/lms/fixtures/preview/course_preview.html
Normal file
23
lms/static/lms/fixtures/preview/course_preview.html
Normal file
@@ -0,0 +1,23 @@
|
||||
<nav class="wrapper-preview-menu" aria-label="Course View">
|
||||
<div class="preview-menu">
|
||||
<ol class="preview-actions">
|
||||
<li class="action-preview">
|
||||
<form action="#" class="action-preview-form" method="post">
|
||||
<label for="action-preview-select" class="action-preview-label">View this course as:</label>
|
||||
<select class="action-preview-select" id="action-preview-select" name="select">
|
||||
<option value="staff" selected>Staff</option>
|
||||
<option value="student">Student</option>
|
||||
<option value="specific student">Specific student</option>
|
||||
<option value="group-a" data-group-id="group-a">Student in Group A</option>
|
||||
<option value="group-b" data-group-id="group-b">Student in Group B</option>
|
||||
</select>
|
||||
<div class="action-preview-username-container">
|
||||
<label for="action-preview-username" class="action-preview-label">Username or email:</label>
|
||||
<input type="text" class="action-preview-username" id="action-preview-username">
|
||||
</div>
|
||||
<button type="submit" class="sr" name="submit" value="submit">Set preview mode</button>
|
||||
</form>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</nav>
|
||||
@@ -1,9 +1,9 @@
|
||||
(function () {
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var getModulesList = function (modules) {
|
||||
return modules.map(function (moduleName) {
|
||||
return { name: moduleName };
|
||||
var getModulesList = function(modules) {
|
||||
return modules.map(function(moduleName) {
|
||||
return {name: moduleName};
|
||||
});
|
||||
};
|
||||
|
||||
@@ -11,19 +11,23 @@
|
||||
process.env.REQUIRE_BUILD_PROFILE_OPTIMIZE : 'uglify2';
|
||||
|
||||
return {
|
||||
namespace: "RequireJS",
|
||||
namespace: 'RequireJS',
|
||||
/**
|
||||
* List the modules that will be optimized. All their immediate and deep
|
||||
* dependencies will be included in the module's file when the build is
|
||||
* done.
|
||||
*/
|
||||
modules: getModulesList([
|
||||
'js/api_admin/catalog_preview_factory',
|
||||
'js/courseware/courseware_factory',
|
||||
'js/discovery/discovery_factory',
|
||||
'js/edxnotes/views/notes_visibility_factory',
|
||||
'js/edxnotes/views/page_factory',
|
||||
'js/financial-assistance/financial_assistance_form_factory',
|
||||
'js/groups/views/cohorts_dashboard_factory',
|
||||
'js/header_factory',
|
||||
'js/learner_dashboard/program_details_factory',
|
||||
'js/learner_dashboard/program_list_factory',
|
||||
'js/search/course/course_search_factory',
|
||||
'js/search/dashboard/dashboard_search_factory',
|
||||
'js/student_account/logistration_factory',
|
||||
@@ -31,13 +35,10 @@
|
||||
'js/student_account/views/finish_auth_factory',
|
||||
'js/student_profile/views/learner_profile_factory',
|
||||
'js/views/message_banner',
|
||||
'teams/js/teams_tab_factory',
|
||||
'lms/js/preview/preview_factory',
|
||||
'support/js/certificates_factory',
|
||||
'support/js/enrollment_factory',
|
||||
'js/courseware/courseware_factory',
|
||||
'js/learner_dashboard/program_details_factory',
|
||||
'js/learner_dashboard/program_list_factory',
|
||||
'js/api_admin/catalog_preview_factory'
|
||||
'teams/js/teams_tab_factory'
|
||||
]),
|
||||
|
||||
/**
|
||||
@@ -91,7 +92,7 @@
|
||||
/**
|
||||
* Stub out requireJS text in the optimized file, but leave available for non-optimized development use.
|
||||
*/
|
||||
stubModules: ["text"],
|
||||
stubModules: ['text'],
|
||||
|
||||
/**
|
||||
* If shim config is used in the app during runtime, duplicate the config
|
||||
@@ -161,4 +162,4 @@
|
||||
*/
|
||||
logLevel: 1
|
||||
};
|
||||
} ())
|
||||
}())
|
||||
|
||||
78
lms/static/lms/js/preview/preview_factory.js
Normal file
78
lms/static/lms/js/preview/preview_factory.js
Normal file
@@ -0,0 +1,78 @@
|
||||
;(function(define) {
|
||||
'use strict';
|
||||
|
||||
define(['jquery', 'common/js/components/utils/view_utils'],
|
||||
function($, ViewUtils) {
|
||||
return function(options) {
|
||||
|
||||
var $selectElement = $('.action-preview-select'),
|
||||
$userNameElement = $('.action-preview-username'),
|
||||
$userNameContainer = $('.action-preview-username-container');
|
||||
|
||||
if (options.disableStudentAccess) {
|
||||
$selectElement.attr('disabled', true);
|
||||
$selectElement.attr('title', gettext('Course is not yet visible to students.'));
|
||||
}
|
||||
|
||||
if (options.specificStudentSelected) {
|
||||
$userNameContainer.css('display', 'inline-block');
|
||||
$userNameElement.val(options.masqueradeUsername);
|
||||
}
|
||||
|
||||
$selectElement.change(function() {
|
||||
var selectedOption;
|
||||
if ($selectElement.attr('disabled')) {
|
||||
return alert(gettext('You cannot view the course as a student or beta tester before the course release date.')); // jshint ignore:line
|
||||
}
|
||||
selectedOption = $selectElement.find('option:selected');
|
||||
if (selectedOption.val() === 'specific student') {
|
||||
$userNameContainer.css('display', 'inline-block');
|
||||
} else {
|
||||
$userNameContainer.hide();
|
||||
masquerade(selectedOption);
|
||||
}
|
||||
});
|
||||
|
||||
$userNameElement.keypress(function(event) {
|
||||
if (event.keyCode === 13) {
|
||||
// Avoid submitting the form on enter, since the submit action isn't implemented.
|
||||
// Instead, blur the element to trigger a change event in case the value was edited,
|
||||
// which in turn will trigger an AJAX request to update the masquerading data.
|
||||
$userNameElement.blur();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
$userNameElement.change(function() {
|
||||
masquerade($selectElement.find('option:selected'));
|
||||
});
|
||||
|
||||
function masquerade(selectedOption) {
|
||||
var data = {
|
||||
role: selectedOption.val() === 'staff' ? 'staff' : 'student',
|
||||
user_partition_id: options.cohortedUserPartitionId,
|
||||
group_id: selectedOption.data('group-id'),
|
||||
user_name: selectedOption.val() === 'specific student' ? $userNameElement.val() : null
|
||||
};
|
||||
$.ajax({
|
||||
url: '/courses/' + options.courseId + '/masquerade',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(data),
|
||||
success: function(result) {
|
||||
if (result.success) {
|
||||
ViewUtils.reload();
|
||||
} else {
|
||||
alert(result.error);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('Error: cannot connect to server');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
}).call(this, define || RequireJS.define);
|
||||
@@ -1,4 +1,4 @@
|
||||
(function(requirejs, define) {
|
||||
(function(requirejs) {
|
||||
'use strict';
|
||||
|
||||
// TODO: how can we share the vast majority of this config that is in common with CMS?
|
||||
@@ -120,7 +120,7 @@
|
||||
'date': {
|
||||
exports: 'Date'
|
||||
},
|
||||
"jquery-migrate": ['jquery'],
|
||||
'jquery-migrate': ['jquery'],
|
||||
'jquery.ui': {
|
||||
deps: ['jquery'],
|
||||
exports: 'jQuery.ui'
|
||||
@@ -204,8 +204,8 @@
|
||||
deps: ['backbone'],
|
||||
exports: 'Backbone.PageableCollection'
|
||||
},
|
||||
"backbone-super": {
|
||||
deps: ["backbone"]
|
||||
'backbone-super': {
|
||||
deps: ['backbone']
|
||||
},
|
||||
'paging-collection': {
|
||||
deps: ['jquery', 'underscore', 'backbone.paginator']
|
||||
@@ -292,13 +292,13 @@
|
||||
},
|
||||
'coffee/src/instructor_dashboard/util': {
|
||||
exports: 'coffee/src/instructor_dashboard/util',
|
||||
deps: ['jquery', 'gettext'],
|
||||
deps: ['jquery', 'underscore', 'slick.core', 'slick.grid'],
|
||||
init: function() {
|
||||
// Set global variables that the util code is expecting to be defined
|
||||
require([
|
||||
'edx-ui-toolkit/js/utils/html-utils',
|
||||
'edx-ui-toolkit/js/utils/string-utils'
|
||||
], function (HtmlUtils, StringUtils) {
|
||||
], function(HtmlUtils, StringUtils) {
|
||||
window.edx = edx || {};
|
||||
window.edx.HtmlUtils = HtmlUtils;
|
||||
window.edx.StringUtils = StringUtils;
|
||||
@@ -309,10 +309,6 @@
|
||||
exports: 'coffee/src/instructor_dashboard/student_admin',
|
||||
deps: ['jquery', 'underscore', 'coffee/src/instructor_dashboard/util', 'string_utils']
|
||||
},
|
||||
'coffee/src/instructor_dashboard/util': {
|
||||
exports: 'coffee/src/instructor_dashboard/util',
|
||||
deps: ['jquery', 'underscore', 'slick.core', 'slick.grid']
|
||||
},
|
||||
'js/instructor_dashboard/certificates': {
|
||||
exports: 'js/instructor_dashboard/certificates',
|
||||
deps: ['jquery', 'gettext', 'underscore']
|
||||
@@ -369,11 +365,11 @@
|
||||
},
|
||||
'js/verify_student/models/verification_model': {
|
||||
exports: 'edx.verify_student.VerificationModel',
|
||||
deps: [ 'jquery', 'underscore', 'backbone', 'jquery.cookie' ]
|
||||
deps: ['jquery', 'underscore', 'backbone', 'jquery.cookie']
|
||||
},
|
||||
'js/verify_student/views/error_view': {
|
||||
exports: 'edx.verify_student.ErrorView',
|
||||
deps: [ 'jquery', 'underscore', 'backbone' ]
|
||||
deps: ['jquery', 'underscore', 'backbone']
|
||||
},
|
||||
'js/verify_student/views/webcam_photo_view': {
|
||||
exports: 'edx.verify_student.WebcamPhotoView',
|
||||
@@ -387,11 +383,11 @@
|
||||
},
|
||||
'js/verify_student/views/image_input_view': {
|
||||
exports: 'edx.verify_student.ImageInputView',
|
||||
deps: [ 'jquery', 'underscore', 'backbone', 'gettext' ]
|
||||
deps: ['jquery', 'underscore', 'backbone', 'gettext']
|
||||
},
|
||||
'js/verify_student/views/step_view': {
|
||||
exports: 'edx.verify_student.StepView',
|
||||
deps: [ 'jquery', 'underscore', 'underscore.string', 'backbone', 'gettext' ],
|
||||
deps: ['jquery', 'underscore', 'underscore.string', 'backbone', 'gettext'],
|
||||
init: function() {
|
||||
// Set global variables that the payment code is expecting to be defined
|
||||
require([
|
||||
@@ -538,7 +534,7 @@
|
||||
exports: 'DiscussionUtil',
|
||||
init: function() {
|
||||
// Set global variables that the discussion code is expecting to be defined
|
||||
require(['backbone', 'URI'], function (Backbone, URI) {
|
||||
require(['backbone', 'URI'], function(Backbone, URI) {
|
||||
window.Backbone = Backbone;
|
||||
window.URI = URI;
|
||||
});
|
||||
@@ -686,6 +682,7 @@
|
||||
});
|
||||
|
||||
var testFiles = [
|
||||
'lms/js/spec/preview/preview_factory_spec.js',
|
||||
'js/spec/api_admin/catalog_preview_spec.js',
|
||||
'js/spec/courseware/bookmark_button_view_spec.js',
|
||||
'js/spec/courseware/bookmarks_list_view_spec.js',
|
||||
@@ -821,8 +818,8 @@
|
||||
|
||||
// Jasmine has a global stack for creating a tree of specs. We need to load
|
||||
// spec files one by one, otherwise some end up getting nested under others.
|
||||
window.requireSerial(specHelpers.concat(testFiles), function () {
|
||||
window.requireSerial(specHelpers.concat(testFiles), function() {
|
||||
// start test run, once Require.js is done
|
||||
window.__karma__.start();
|
||||
});
|
||||
}).call(this, requirejs, define);
|
||||
}).call(this, requirejs);
|
||||
122
lms/static/lms/js/spec/preview/preview_factory_spec.js
Normal file
122
lms/static/lms/js/spec/preview/preview_factory_spec.js
Normal file
@@ -0,0 +1,122 @@
|
||||
define(
|
||||
[
|
||||
'common/js/spec_helpers/ajax_helpers',
|
||||
'common/js/components/utils/view_utils',
|
||||
'lms/js/preview/preview_factory'
|
||||
],
|
||||
function(AjaxHelpers, ViewUtils, PreviewFactory) {
|
||||
'use strict';
|
||||
|
||||
describe('Preview Factory', function() {
|
||||
var showPreview,
|
||||
previewActionSelect,
|
||||
usernameInput;
|
||||
|
||||
showPreview = function(options) {
|
||||
PreviewFactory(options);
|
||||
};
|
||||
|
||||
previewActionSelect = function() {
|
||||
return $('.action-preview-select');
|
||||
};
|
||||
|
||||
usernameInput = function() {
|
||||
return $('.action-preview-username');
|
||||
};
|
||||
|
||||
beforeEach(function() {
|
||||
loadFixtures('lms/fixtures/preview/course_preview.html');
|
||||
});
|
||||
|
||||
it('can render preview for a staff user', function() {
|
||||
showPreview({
|
||||
courseId: 'test_course'
|
||||
});
|
||||
expect(previewActionSelect().val()).toBe('staff');
|
||||
});
|
||||
|
||||
it('can disable course access for a student', function() {
|
||||
var select;
|
||||
showPreview({
|
||||
courseId: 'test_course',
|
||||
disableStudentAccess: true
|
||||
});
|
||||
select = previewActionSelect();
|
||||
expect(select.attr('disabled')).toBe('disabled');
|
||||
expect(select.attr('title')).toBe('Course is not yet visible to students.');
|
||||
});
|
||||
|
||||
it('can switch to view as a student', function() {
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
reloadSpy = spyOn(ViewUtils, 'reload');
|
||||
showPreview({
|
||||
courseId: 'test_course'
|
||||
});
|
||||
previewActionSelect().find('option[value="student"]').prop('selected', 'selected').change();
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'POST', '/courses/test_course/masquerade',
|
||||
{
|
||||
role: 'student',
|
||||
user_name: null
|
||||
}
|
||||
);
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
success: true
|
||||
});
|
||||
expect(reloadSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('can switch to view as a content group', function() {
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
reloadSpy = spyOn(ViewUtils, 'reload');
|
||||
showPreview({
|
||||
cohortedUserPartitionId: 'test_partition_id',
|
||||
courseId: 'test_course'
|
||||
});
|
||||
previewActionSelect().find('option[value="group-b"]').prop('selected', 'selected').change();
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'POST', '/courses/test_course/masquerade',
|
||||
{
|
||||
role: 'student',
|
||||
user_name: null,
|
||||
user_partition_id: 'test_partition_id',
|
||||
group_id: 'group-b'
|
||||
}
|
||||
);
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
success: true
|
||||
});
|
||||
expect(reloadSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('can switch to masquerade as a specific student', function() {
|
||||
var requests = AjaxHelpers.requests(this),
|
||||
reloadSpy = spyOn(ViewUtils, 'reload');
|
||||
showPreview({
|
||||
courseId: 'test_course'
|
||||
});
|
||||
previewActionSelect().find('option[value="specific student"]').prop('selected', 'selected').change();
|
||||
usernameInput().val('test_user').change();
|
||||
AjaxHelpers.expectJsonRequest(
|
||||
requests, 'POST', '/courses/test_course/masquerade',
|
||||
{
|
||||
role: 'student',
|
||||
user_name: 'test_user'
|
||||
}
|
||||
);
|
||||
AjaxHelpers.respondWithJson(requests, {
|
||||
success: true
|
||||
});
|
||||
expect(reloadSpy).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('shows the correct information when masquerading as a specific student', function() {
|
||||
showPreview({
|
||||
specificStudentSelected: true,
|
||||
masqueradeUsername: 'test_user'
|
||||
});
|
||||
expect(usernameInput().val()).toBe('test_user');
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -6,9 +6,11 @@ from courseware.tabs import get_course_tab_list
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.conf import settings
|
||||
from openedx.core.djangoapps.course_groups.partition_scheme import get_cohorted_user_partition
|
||||
from openedx.core.djangolib.js_utils import dump_js_escaped_json
|
||||
from openedx.core.djangolib.markup import HTML, Text
|
||||
from student.models import CourseEnrollment
|
||||
%>
|
||||
<%page args="active_page=None" />
|
||||
<%page args="active_page=None" expression_filter="h" />
|
||||
|
||||
<%
|
||||
if active_page is None and active_page_context is not UNDEFINED:
|
||||
@@ -29,13 +31,13 @@ include_special_exams = settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False) and
|
||||
%>
|
||||
|
||||
% if include_special_exams:
|
||||
<%static:js group='proctoring'/>
|
||||
% for template_name in ["proctored-exam-status"]:
|
||||
<script type="text/template" id="${template_name}-tpl">
|
||||
<%static:include path="courseware/${template_name}.underscore" />
|
||||
</script>
|
||||
% endfor
|
||||
<div class="proctored_exam_status"></div>
|
||||
<%static:js group='proctoring'/>
|
||||
% for template_name in ["proctored-exam-status"]:
|
||||
<script type="text/template" id="${template_name}-tpl">
|
||||
<%static:include path="courseware/${template_name}.underscore" />
|
||||
</script>
|
||||
% endfor
|
||||
<div class="proctored_exam_status"></div>
|
||||
% endif
|
||||
% if show_preview_menu:
|
||||
<nav class="wrapper-preview-menu" aria-label="${_('Course View')}">
|
||||
@@ -65,102 +67,46 @@ include_special_exams = settings.FEATURES.get('ENABLE_SPECIAL_EXAMS', False) and
|
||||
</li>
|
||||
</ol>
|
||||
% if specific_student_selected:
|
||||
<div class="preview-specific-student-notice">
|
||||
<p>
|
||||
${_("You are now viewing the course as <i>{user_name}</i>.").format(user_name=masquerade_user_name)}
|
||||
</p>
|
||||
</div>
|
||||
<div class="preview-specific-student-notice">
|
||||
<p>
|
||||
${Text(_("You are now viewing the course as {i_start}{user_name}{i_end}.")).format(
|
||||
user_name=masquerade_user_name,
|
||||
i_start=HTML(u'<i>'),
|
||||
i_end=HTML(u'</i>'),
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
</nav>
|
||||
% endif
|
||||
|
||||
% if disable_tabs is UNDEFINED or not disable_tabs:
|
||||
<nav class="${active_page} wrapper-course-material" aria-label="${_('Course Material')}">
|
||||
<div class="course-material">
|
||||
<%
|
||||
tab_list = get_course_tab_list(request, course)
|
||||
tabs_tmpl = static.get_template_path('/courseware/tabs.html')
|
||||
%>
|
||||
<ol class="course-tabs">
|
||||
<%include file="${tabs_tmpl}" args="tab_list=tab_list,active_page=active_page,default_tab=default_tab,tab_image=tab_image" />
|
||||
<%block name="extratabs" />
|
||||
</ol>
|
||||
</div>
|
||||
</nav>
|
||||
<nav class="${active_page} wrapper-course-material" aria-label="${_('Course Material')}">
|
||||
<div class="course-material">
|
||||
<%
|
||||
tab_list = get_course_tab_list(request, course)
|
||||
tabs_tmpl = static.get_template_path('/courseware/tabs.html')
|
||||
%>
|
||||
<ol class="course-tabs">
|
||||
<%include file="${tabs_tmpl}" args="tab_list=tab_list,active_page=active_page,default_tab=default_tab,tab_image=tab_image" />
|
||||
<%block name="extratabs" />
|
||||
</ol>
|
||||
</div>
|
||||
</nav>
|
||||
%endif
|
||||
|
||||
% if show_preview_menu:
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
var selectElement = $('.action-preview-select');
|
||||
var userNameElement = $('#action-preview-username');
|
||||
var userNameContainer = $('.action-preview-username-container')
|
||||
|
||||
% if disable_student_access:
|
||||
selectElement.attr("disabled", true);
|
||||
selectElement.attr("title", "${_("Course is not yet visible to students.")}");
|
||||
% endif
|
||||
|
||||
% if specific_student_selected:
|
||||
userNameContainer.css('display', 'inline-block');
|
||||
userNameElement.val('${masquerade_user_name}');
|
||||
% endif
|
||||
|
||||
selectElement.change(function() {
|
||||
var selectedOption;
|
||||
if (selectElement.attr("disabled")) {
|
||||
return alert("${_("You cannot view the course as a student or beta tester before the course release date.")}");
|
||||
}
|
||||
selectedOption = selectElement.find('option:selected');
|
||||
if (selectedOption.val() === 'specific student') {
|
||||
userNameContainer.css('display', 'inline-block');
|
||||
} else {
|
||||
userNameContainer.hide();
|
||||
masquerade(selectedOption);
|
||||
}
|
||||
});
|
||||
|
||||
userNameElement.keypress(function(event) {
|
||||
if (event.keyCode === 13) {
|
||||
// Avoid submitting the form on enter, since the submit action isn't implemented. Instead, blur the
|
||||
// element to trigger a change event in case the value was edited, which in turn will trigger an AJAX
|
||||
// request to update the masquerading data.
|
||||
userNameElement.blur();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
userNameElement.change(function() {
|
||||
masquerade(selectElement.find('option:selected'));
|
||||
});
|
||||
|
||||
function masquerade(selectedOption) {
|
||||
var data = {
|
||||
role: selectedOption.val() === 'staff' ? 'staff' : 'student',
|
||||
user_partition_id: ${cohorted_user_partition.id if cohorted_user_partition else 'null'},
|
||||
group_id: selectedOption.data('group-id'),
|
||||
user_name: selectedOption.val() === 'specific student' ? userNameElement.val() : null
|
||||
};
|
||||
$.ajax({
|
||||
url: '/courses/${course.id}/masquerade',
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(data),
|
||||
success: function(result) {
|
||||
if (result.success) {
|
||||
location.reload();
|
||||
} else {
|
||||
alert(result.error);
|
||||
}
|
||||
},
|
||||
error: function() {
|
||||
alert('Error: cannot connect to server');
|
||||
}
|
||||
});
|
||||
<%
|
||||
preview_options = {
|
||||
"courseId": course.id,
|
||||
"disableStudentAccess": disable_student_access if disable_student_access is not UNDEFINED else False,
|
||||
"specificStudentSelected": specific_student_selected,
|
||||
"cohortedUserPartitionId": cohorted_user_partition.id if cohorted_user_partition else None,
|
||||
"masqueradeUsername" : masquerade_user_name if masquerade_user_name is not UNDEFINED else None,
|
||||
}
|
||||
}());
|
||||
</script>
|
||||
%>
|
||||
<%static:require_module module_name="lms/js/preview/preview_factory" class_name="PreviewFactory">
|
||||
PreviewFactory(${preview_options | n, dump_js_escaped_json});
|
||||
</%static:require_module>
|
||||
% endif
|
||||
|
||||
Reference in New Issue
Block a user