Remove code and template responsible for subsection edit page
This commit is contained in:
@@ -1289,11 +1289,6 @@ class ContentStoreTest(ContentStoreTestCase):
|
||||
test_get_html('advanced_settings_handler')
|
||||
test_get_html('textbooks_list_handler')
|
||||
|
||||
# go look at a subsection page
|
||||
subsection_key = course_key.make_usage_key('sequential', 'test_sequence')
|
||||
resp = self.client.get_html(get_url('subsection_handler', subsection_key))
|
||||
self.assertEqual(resp.status_code, 200)
|
||||
|
||||
# go look at the Edit page
|
||||
unit_key = course_key.make_usage_key('vertical', 'test_vertical')
|
||||
resp = self.client.get_html(get_url('container_handler', unit_key))
|
||||
|
||||
@@ -17,7 +17,6 @@ from xmodule.modulestore.django import modulestore
|
||||
from xblock.core import XBlock
|
||||
from xblock.django.request import webob_to_django_response, django_to_webob_request
|
||||
from xblock.exceptions import NoSuchHandlerError
|
||||
from xblock.fields import Scope
|
||||
from xblock.plugin import PluginMissingError
|
||||
from xblock.runtime import Mixologist
|
||||
|
||||
@@ -25,7 +24,6 @@ from contentstore.utils import get_lms_link_for_item
|
||||
from contentstore.views.helpers import get_parent_xblock, is_unit, xblock_type_display_name
|
||||
from contentstore.views.item import create_xblock_info
|
||||
|
||||
from models.settings.course_grading import CourseGradingModel
|
||||
from opaque_keys.edx.keys import UsageKey
|
||||
|
||||
from .access import has_course_access
|
||||
@@ -33,7 +31,6 @@ from django.utils.translation import ugettext as _
|
||||
|
||||
__all__ = ['OPEN_ENDED_COMPONENT_TYPES',
|
||||
'ADVANCED_COMPONENT_POLICY_KEY',
|
||||
'subsection_handler',
|
||||
'container_handler',
|
||||
'component_handler'
|
||||
]
|
||||
|
||||
@@ -1,99 +0,0 @@
|
||||
define ["js/views/overview", "js/views/feedback_notification", "js/spec_helpers/create_sinon", "js/base", "date", "jquery.timepicker"],
|
||||
(Overview, Notification, create_sinon) ->
|
||||
|
||||
describe "Course Overview", ->
|
||||
beforeEach ->
|
||||
appendSetFixtures """
|
||||
<div class="section-published-date">
|
||||
<span class="published-status">
|
||||
<strong>Release date:</strong> 06/12/2013 at 04:00 UTC
|
||||
</span>
|
||||
<a href="#" class="edit-release-date action " data-date="06/12/2013" data-time="04:00" data-locator="i4x://pfogg/42/chapter/d6b47f7b084f49debcaf67fe5436c8e2"><i class="icon-time"></i> <span class="sr">Edit section release date</span></a>
|
||||
</div>
|
||||
"""
|
||||
|
||||
appendSetFixtures """
|
||||
<div class="wrapper wrapper-dialog wrapper-dialog-edit-sectionrelease edit-section-publish-settings" aria-describedby="dialog-edit-sectionrelease-description" aria-labelledby="dialog-edit-sectionrelease-title" aria-hidden="" role="dialog">
|
||||
<div class="dialog confirm">
|
||||
<form class="edit-sectionrelease-dialog" action="#">
|
||||
<div class="form-content">
|
||||
<h2 class="title dialog-edit-sectionrelease-title">Section Release Date</h2>
|
||||
<p id="dialog-edit-sectionrelease-description" class="message">On the date set below, this section - <strong class="section-name"></strong> - will be released to students. Any units marked private will only be visible to admins.</p>
|
||||
|
||||
<ul class="list-input picker datepair">
|
||||
<li class="field field-start-date">
|
||||
<label for="start_date">Release Day</label>
|
||||
<input class="start-date date" type="text" name="start_date" value="04/08/1990" placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
|
||||
</li>
|
||||
<li class="field field-start-time">
|
||||
<label for="start_time">Release Time (<abbr title="Coordinated Universal Time">UTC</abbr>)</label>
|
||||
<input class="start-time time" type="text" name="start_time" value="12:00" placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<h3 class="sr">Form Actions</h3>
|
||||
<ul>
|
||||
<li class="action-item">
|
||||
<a href="#" class="button action-primary action-save">Save</a>
|
||||
</li>
|
||||
<li class="action-item">
|
||||
<a href="#" class="button action-secondary action-cancel">Cancel</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
"""
|
||||
|
||||
appendSetFixtures """
|
||||
<section class="courseware-section is-collapsible is-draggable" data-parent="a-parent-locator-goes-here" data-locator="a-location-goes-here">
|
||||
<li class="branch collapsed id-holder" data-locator="an-id-goes-here">
|
||||
<a href="#" data-tooltip="Delete this section" class="delete-section-button"><i class="icon-trash"></i> <span class="sr">Delete section</span></a>
|
||||
</li>
|
||||
</section>
|
||||
"""
|
||||
|
||||
spyOn(Overview, 'saveSetSectionScheduleDate').andCallThrough()
|
||||
# Have to do this here, as it normally gets bound in document.ready()
|
||||
$('a.action-save').click(Overview.saveSetSectionScheduleDate)
|
||||
$('a.delete-section-button').click(deleteSection)
|
||||
$(".edit-subsection-publish-settings .start-date").datepicker()
|
||||
|
||||
@notificationSpy = spyOn(Notification.Mini.prototype, 'show').andCallThrough()
|
||||
window.analytics = jasmine.createSpyObj('analytics', ['track'])
|
||||
window.course_location_analytics = jasmine.createSpy()
|
||||
|
||||
afterEach ->
|
||||
delete window.analytics
|
||||
delete window.course_location_analytics
|
||||
@notificationSpy.reset()
|
||||
|
||||
it "should save model when save is clicked", ->
|
||||
$('a.edit-release-date').click()
|
||||
$('a.action-save').click()
|
||||
expect(Overview.saveSetSectionScheduleDate).toHaveBeenCalled()
|
||||
|
||||
it "should show a confirmation on save", ->
|
||||
$('a.edit-release-date').click()
|
||||
$('a.action-save').click()
|
||||
expect(@notificationSpy).toHaveBeenCalled()
|
||||
|
||||
# Fails sporadically in Jenkins.
|
||||
# it "should delete model when delete is clicked", ->
|
||||
# $('a.delete-section-button').click()
|
||||
# $('a.action-primary').click()
|
||||
# expect(@requests[0].url).toEqual('/delete_item')
|
||||
|
||||
it "should not delete model when cancel is clicked", ->
|
||||
requests = create_sinon["requests"](this)
|
||||
|
||||
$('a.delete-section-button').click()
|
||||
$('a.action-secondary').click()
|
||||
expect(requests.length).toEqual(0)
|
||||
|
||||
# Fails sporadically in Jenkins.
|
||||
# it "should show a confirmation on delete", ->
|
||||
# $('a.delete-section-button').click()
|
||||
# $('a.action-primary').click()
|
||||
# expect(@notificationSpy).toHaveBeenCalled()
|
||||
@@ -1,34 +1,19 @@
|
||||
require(["domReady", "jquery", "underscore", "gettext", "js/views/feedback_notification", "js/views/feedback_prompt",
|
||||
"js/utils/date_utils", "js/utils/module", "js/utils/handle_iframe_binding", "js/utils/change_on_enter", "jquery.ui",
|
||||
"jquery.leanModal", "jquery.form", "jquery.smoothScroll"],
|
||||
function(domReady, $, _, gettext, NotificationView, PromptView, DateUtils, ModuleUtils, IframeUtils, TriggerChangeEventOnEnter)
|
||||
"js/utils/date_utils", "js/utils/module", "js/utils/handle_iframe_binding",
|
||||
"jquery.ui", "jquery.leanModal", "jquery.form", "jquery.smoothScroll"],
|
||||
function(domReady, $, _, gettext, NotificationView, PromptView, DateUtils, ModuleUtils, IframeUtils)
|
||||
{
|
||||
|
||||
var $body;
|
||||
var $newComponentItem;
|
||||
var $changedInput;
|
||||
var $spinner;
|
||||
var $newComponentTypePicker;
|
||||
var $newComponentTemplatePickers;
|
||||
var $newComponentButton;
|
||||
|
||||
domReady(function() {
|
||||
$body = $('body');
|
||||
|
||||
$newComponentItem = $('.new-component-item');
|
||||
$newComponentTypePicker = $('.new-component');
|
||||
$newComponentTemplatePickers = $('.new-component-templates');
|
||||
$newComponentButton = $('.new-component-button');
|
||||
$spinner = $('<span class="spinner-in-field-icon"></span>');
|
||||
|
||||
$body.on('click', '.embeddable-xml-input', function() {
|
||||
$(this).select();
|
||||
});
|
||||
|
||||
$('body').addClass('js');
|
||||
|
||||
$('.unit .item-actions .delete-unit-button').bind('click', deleteUnit);
|
||||
$('.new-unit-item').bind('click', createNewUnit);
|
||||
$body.addClass('js');
|
||||
|
||||
// lean/simple modal
|
||||
$('a[rel*=modal]').leanModal({
|
||||
@@ -69,7 +54,10 @@ domReady(function() {
|
||||
});
|
||||
|
||||
// general link management - new window/tab
|
||||
$('a[rel="external"]').attr('title', gettext('This link will open in a new browser window/tab')).bind('click', linkNewWindow);
|
||||
$('a[rel="external"]').attr({
|
||||
title: gettext('This link will open in a new browser window/tab'),
|
||||
target: '_blank'
|
||||
});
|
||||
|
||||
// general link management - lean modal window
|
||||
$('a[rel="modal"]').attr('title', gettext('This link will open in a modal window')).leanModal({
|
||||
@@ -86,36 +74,6 @@ domReady(function() {
|
||||
// tender feedback window scrolling
|
||||
$('a.show-tender').bind('click', smoothScrollTop);
|
||||
|
||||
// autosave when leaving input field
|
||||
$body.on('change', '.subsection-display-name-input', saveSubsection);
|
||||
$('.subsection-display-name-input').each(function() {
|
||||
this.val = $(this).val();
|
||||
});
|
||||
$("#start_date, #start_time, #due_date, #due_time").change(autosaveInput).keyup(TriggerChangeEventOnEnter)
|
||||
$('.sync-date, .remove-date').bind('click', autosaveInput);
|
||||
|
||||
// expand/collapse methods for optional date setters
|
||||
$('.set-date').bind('click', showDateSetter);
|
||||
$('.remove-date').bind('click', removeDateSetter);
|
||||
|
||||
$('.delete-section-button').bind('click', deleteSection);
|
||||
$('.delete-subsection-button').bind('click', deleteSubsection);
|
||||
|
||||
$('.sync-date').bind('click', syncReleaseDate);
|
||||
|
||||
// section date setting
|
||||
$('.set-publish-date').bind('click', setSectionScheduleDate);
|
||||
$('.edit-section-start-cancel').bind('click', cancelSetSectionScheduleDate);
|
||||
|
||||
$body.on('change', '.edit-subsection-publish-settings .start-date', function() {
|
||||
if ($('.edit-subsection-publish-settings').find('.start-time').val() == '') {
|
||||
$('.edit-subsection-publish-settings').find('.start-time').val('12:00am');
|
||||
}
|
||||
});
|
||||
$('.edit-subsection-publish-settings').on('change', '.start-date, .start-time', function() {
|
||||
$('.edit-subsection-publish-settings').find('.save-button').show();
|
||||
});
|
||||
|
||||
IframeUtils.iframeBinding();
|
||||
});
|
||||
|
||||
@@ -143,183 +101,6 @@ function smoothScrollTop(e) {
|
||||
});
|
||||
}
|
||||
|
||||
function linkNewWindow(e) {
|
||||
window.open($(e.target).attr('href'));
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function syncReleaseDate(e) {
|
||||
e.preventDefault();
|
||||
$(this).closest('.notice').hide();
|
||||
$("#start_date").val("");
|
||||
$("#start_time").val("");
|
||||
}
|
||||
|
||||
|
||||
function autosaveInput(e) {
|
||||
var self = this;
|
||||
if (this.saveTimer) {
|
||||
clearTimeout(this.saveTimer);
|
||||
}
|
||||
|
||||
this.saveTimer = setTimeout(function() {
|
||||
$changedInput = $(e.target);
|
||||
saveSubsection();
|
||||
self.saveTimer = null;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
function saveSubsection() {
|
||||
// Spinner is no longer used by subsection name, but is still used by date and time pickers on the right.
|
||||
if ($changedInput && !$changedInput.hasClass('no-spinner')) {
|
||||
$spinner.css({
|
||||
'position': 'absolute',
|
||||
'top': Math.floor($changedInput.position().top + ($changedInput.outerHeight() / 2) + 3),
|
||||
'left': $changedInput.position().left + $changedInput.outerWidth() - 24,
|
||||
'margin-top': '-10px'
|
||||
});
|
||||
$changedInput.after($spinner);
|
||||
$spinner.show();
|
||||
}
|
||||
|
||||
var locator = $('.subsection-body').data('locator');
|
||||
|
||||
// pull all 'normalized' metadata editable fields on page
|
||||
var metadata_fields = $('input[data-metadata-name]');
|
||||
|
||||
var metadata = {};
|
||||
for (var i = 0; i < metadata_fields.length; i++) {
|
||||
var el = metadata_fields[i];
|
||||
metadata[$(el).data("metadata-name")] = el.value;
|
||||
}
|
||||
|
||||
// get datetimes for start and due, stick into metadata
|
||||
_(["start", "due"]).each(function(name) {
|
||||
|
||||
var datetime = DateUtils.getDate(
|
||||
document.getElementById(name+"_date"),
|
||||
document.getElementById(name+"_time")
|
||||
);
|
||||
// if datetime is null, we want to set that in metadata anyway;
|
||||
// its an indication to the server to clear the datetime in the DB
|
||||
metadata[name] = datetime;
|
||||
});
|
||||
|
||||
$.ajax({
|
||||
url: ModuleUtils.getUpdateUrl(locator),
|
||||
type: "PUT",
|
||||
dataType: "json",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify({
|
||||
'metadata': metadata
|
||||
}),
|
||||
success: function() {
|
||||
$spinner.delay(500).fadeOut(150);
|
||||
$changedInput = null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function createNewUnit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
var parent = $(this).data('parent');
|
||||
var category = $(this).data('category');
|
||||
|
||||
analytics.track('Created a Unit', {
|
||||
'course': course_location_analytics,
|
||||
'parent_locator': parent
|
||||
});
|
||||
|
||||
|
||||
$.postJSON(ModuleUtils.getUpdateUrl(), {
|
||||
'parent_locator': parent,
|
||||
'category': category,
|
||||
'display_name': 'New Unit'
|
||||
},
|
||||
|
||||
function(data) {
|
||||
// redirect to the edit page
|
||||
window.location = "/container/" + data['locator'];
|
||||
});
|
||||
}
|
||||
|
||||
function deleteUnit(e) {
|
||||
e.preventDefault();
|
||||
_deleteItem($(this).parents('li.courseware-unit'), 'Unit');
|
||||
}
|
||||
|
||||
function deleteSubsection(e) {
|
||||
e.preventDefault();
|
||||
_deleteItem($(this).parents('li.courseware-subsection'), 'Subsection');
|
||||
}
|
||||
|
||||
function deleteSection(e) {
|
||||
e.preventDefault();
|
||||
_deleteItem($(this).parents('section.courseware-section'), 'Section');
|
||||
}
|
||||
|
||||
function _deleteItem($el, type) {
|
||||
var confirm = new PromptView.Warning({
|
||||
title: gettext('Delete this ' + type + '?'),
|
||||
message: gettext('Deleting this ' + type + ' is permanent and cannot be undone.'),
|
||||
actions: {
|
||||
primary: {
|
||||
text: gettext('Yes, delete this ' + type),
|
||||
click: function(view) {
|
||||
view.hide();
|
||||
|
||||
var locator = $el.data('locator');
|
||||
|
||||
analytics.track('Deleted an Item', {
|
||||
'course': course_location_analytics,
|
||||
'id': locator
|
||||
});
|
||||
|
||||
var deleting = new NotificationView.Mini({
|
||||
title: gettext('Deleting…')
|
||||
});
|
||||
deleting.show();
|
||||
|
||||
$.ajax({
|
||||
type: 'DELETE',
|
||||
url: ModuleUtils.getUpdateUrl(locator),
|
||||
success: function () {
|
||||
$el.remove();
|
||||
deleting.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
secondary: {
|
||||
text: gettext('Cancel'),
|
||||
click: function(view) {
|
||||
view.hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
confirm.show();
|
||||
}
|
||||
|
||||
function showDateSetter(e) {
|
||||
e.preventDefault();
|
||||
var $block = $(this).closest('.due-date-input');
|
||||
$(this).hide();
|
||||
$block.find('.date-setter').show();
|
||||
}
|
||||
|
||||
function removeDateSetter(e) {
|
||||
e.preventDefault();
|
||||
var $block = $(this).closest('.due-date-input');
|
||||
$block.find('.date-setter').hide();
|
||||
$block.find('.set-date').show();
|
||||
// clear out the values
|
||||
$block.find('.date').val('');
|
||||
$block.find('.time').val('');
|
||||
}
|
||||
|
||||
function hideNotification(e) {
|
||||
(e).preventDefault();
|
||||
$(this).closest('.wrapper-notification').removeClass('is-shown').addClass('is-hiding').attr('aria-hidden', 'true');
|
||||
@@ -330,18 +111,4 @@ function hideAlert(e) {
|
||||
$(this).closest('.wrapper-alert').removeClass('is-shown');
|
||||
}
|
||||
|
||||
function setSectionScheduleDate(e) {
|
||||
e.preventDefault();
|
||||
$(this).closest("h4").hide();
|
||||
$(this).parent().siblings(".datepair").show();
|
||||
}
|
||||
|
||||
function cancelSetSectionScheduleDate(e) {
|
||||
e.preventDefault();
|
||||
$(this).closest(".datepair").hide();
|
||||
$(this).parent().siblings("h4").show();
|
||||
}
|
||||
|
||||
window.deleteSection = deleteSection;
|
||||
|
||||
}); // end require()
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
@import 'views/outline';
|
||||
@import 'views/settings';
|
||||
@import 'views/static-pages';
|
||||
@import 'views/subsection';
|
||||
@import 'views/unit';
|
||||
@import 'views/container';
|
||||
@import 'views/users';
|
||||
|
||||
@@ -1,511 +0,0 @@
|
||||
// studio - views - course subsection
|
||||
// ====================
|
||||
|
||||
.view-subsection {
|
||||
|
||||
.main-wrapper {
|
||||
margin-top: ($baseline*2);
|
||||
}
|
||||
|
||||
.unit-settings {
|
||||
.window-contents {
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.datepair {
|
||||
|
||||
.field {
|
||||
display: inline-block;
|
||||
margin-right: ($baseline/4);
|
||||
width: 45%;
|
||||
|
||||
&:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
label, input {
|
||||
display: block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
label {
|
||||
@extend %t-title8;
|
||||
margin-bottom: ($baseline/4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.unit-actions {
|
||||
border-bottom: none;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
.published-alert {
|
||||
display: none;
|
||||
padding: 10px;
|
||||
border: 1px solid #edbd3c;
|
||||
border-radius: 3px;
|
||||
background: #fbf6e1;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
|
||||
div {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
margin-right: 7px;
|
||||
}
|
||||
|
||||
.status {
|
||||
font-size: 12px;
|
||||
|
||||
strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
|
||||
.preview-button, .view-button {
|
||||
@include white-button;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.publish-button {
|
||||
@include orange-button;
|
||||
}
|
||||
|
||||
.delete-button {
|
||||
@include blue-button;
|
||||
}
|
||||
|
||||
.delete-draft {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.delete-button,
|
||||
.preview-button,
|
||||
.publish-button,
|
||||
.view-button {
|
||||
font-size: 11px;
|
||||
margin-top: 10px;
|
||||
padding: 6px 15px 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.unit-history {
|
||||
&.collapsed {
|
||||
h4 {
|
||||
border-bottom: none;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.window-contents {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
ol {
|
||||
border: 1px solid #ced2db;
|
||||
|
||||
li {
|
||||
display: block;
|
||||
padding: 6px 8px 8px 10px;
|
||||
background: #edf1f5;
|
||||
font-size: 12px;
|
||||
|
||||
&:hover {
|
||||
background: #fffcf1;
|
||||
|
||||
.item-actions {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
&.checked {
|
||||
background: #d1dae3;
|
||||
}
|
||||
|
||||
.item-actions {
|
||||
display: none;
|
||||
}
|
||||
|
||||
input[type="radio"] {
|
||||
margin-right: 7px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.unit-location {
|
||||
.url {
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.draft-tag,
|
||||
.hidden-tag,
|
||||
.private-tag,
|
||||
.has-new-draft-tag {
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
.window-contents > ol {
|
||||
@include tree-view;
|
||||
|
||||
.section-item {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
font-size: 11px;
|
||||
padding: 2px 8px 4px;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
@include box-sizing(border-box);
|
||||
}
|
||||
|
||||
ol {
|
||||
.section-item {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.new-unit-item {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
ol ol {
|
||||
.section-item {
|
||||
padding-left: 34px;
|
||||
}
|
||||
|
||||
.new-unit-item {
|
||||
margin: 0 0 10px 41px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.subsection-body {
|
||||
padding: 32px 40px;
|
||||
@include clearfix;
|
||||
|
||||
> div {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
input {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.subsection-name-input {
|
||||
label {
|
||||
display: block;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
font-size: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.scheduled-date-input,
|
||||
.due-date-input {
|
||||
@include clearfix;
|
||||
|
||||
.date-input,
|
||||
.time-input {
|
||||
display: inline-block;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.inherits-check {
|
||||
label {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.notice {
|
||||
@extend %t-copy-sub2;
|
||||
margin-top: 6px;
|
||||
color: #999;
|
||||
}
|
||||
}
|
||||
|
||||
.due-date-input {
|
||||
label {
|
||||
display: inline-block !important;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
a {
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.date-setter {
|
||||
@include clearfix;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.remove-date {
|
||||
display: block;
|
||||
margin-top: ($baseline/4);
|
||||
}
|
||||
}
|
||||
|
||||
.row.visibility {
|
||||
label {
|
||||
display: inline-block !important;
|
||||
margin-right: 10px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
a {
|
||||
display: inline-block;
|
||||
height: 31px;
|
||||
margin-right: 8px;
|
||||
vertical-align: middle;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
line-height: 31px;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.large-toggle {
|
||||
width: 41px;
|
||||
background: url(../img/large-toggles.png) no-repeat;
|
||||
background-position: 0 -50px;
|
||||
|
||||
.hidden {
|
||||
background-position: 0 -5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.sortable-unit-list {
|
||||
|
||||
.courseware-unit {
|
||||
@include font-size(13);
|
||||
@include clearfix();
|
||||
margin: -1px 0 0 0;
|
||||
|
||||
.section-item {
|
||||
@include transition(background $tmg-avg ease-in-out 0);
|
||||
@include font-size(13);
|
||||
position: relative;
|
||||
display: block;
|
||||
padding: 6px 8px 8px 16px;
|
||||
|
||||
&:hover {
|
||||
background: $blue-l5;
|
||||
}
|
||||
}
|
||||
|
||||
.public-item {
|
||||
color: $black;
|
||||
}
|
||||
|
||||
.private-item {
|
||||
color: $gray-l1;
|
||||
}
|
||||
|
||||
.draft-item {
|
||||
color: $yellow-d1;
|
||||
}
|
||||
|
||||
.draft-item:after,
|
||||
.public-item:after,
|
||||
.private-item:after {
|
||||
@include font-size(9);
|
||||
margin-left: 3px;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.draft-item:after {
|
||||
content: "- draft";
|
||||
}
|
||||
|
||||
.private-item:after {
|
||||
content: "- private";
|
||||
}
|
||||
}
|
||||
|
||||
.actions-list {
|
||||
display: inline-block;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.actions-item {
|
||||
@include font-size(13);
|
||||
display: inline-block;
|
||||
padding: 0 4px;
|
||||
vertical-align: middle;
|
||||
|
||||
.action {
|
||||
min-width: ($baseline*.75);
|
||||
color: $gray-l2;
|
||||
|
||||
&:hover,
|
||||
&.is-set {
|
||||
color: $blue;
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
//reset old drag handle style
|
||||
&.drag-handle {
|
||||
float: none;
|
||||
margin: 0;
|
||||
background: transparent url(../img/drag-handles.png) right 5px no-repeat;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.new-unit-item {
|
||||
@extend %ui-btn-flat-outline;
|
||||
width: 100%;
|
||||
margin: 0 0 ($baseline/2) 0;
|
||||
border: 1px solid $gray-l3;
|
||||
padding: ($baseline/2) 0;
|
||||
color: $gray-l2;
|
||||
|
||||
&:hover {
|
||||
box-shadow: none;
|
||||
background-image: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.gradable {
|
||||
|
||||
label {
|
||||
@extend %t-title8;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.gradable-status {
|
||||
position: relative;
|
||||
top: -4px;
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
width: 65%;
|
||||
|
||||
.status-label {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
color: $blue;
|
||||
border: none;
|
||||
font-size: 11px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
background: transparent;
|
||||
|
||||
&:hover, &.is-active {
|
||||
color: $blue;
|
||||
}
|
||||
}
|
||||
|
||||
.menu {
|
||||
@include transition(opacity $tmg-f2 linear 0s);
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
top: -12px;
|
||||
left: -7px;
|
||||
display: none;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
padding: 8px 12px;
|
||||
opacity: 0.0;
|
||||
background: $white;
|
||||
border: 1px solid $mediumGrey;
|
||||
font-size: 12px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .2);
|
||||
|
||||
|
||||
li {
|
||||
margin-bottom: 3px;
|
||||
padding-bottom: 3px;
|
||||
border-bottom: 1px solid $lightGrey;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
padding-bottom: 0;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
|
||||
&.is-selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// dropdown state
|
||||
&.is-active {
|
||||
|
||||
.menu {
|
||||
z-index: 10000;
|
||||
display: block;
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
.menu-toggle {
|
||||
z-index: 1000;
|
||||
}
|
||||
}
|
||||
|
||||
// set state
|
||||
&.is-set {
|
||||
|
||||
.menu-toggle {
|
||||
color: $blue;
|
||||
}
|
||||
|
||||
.status-label {
|
||||
display: block;
|
||||
color: $blue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UI: DnD - specific elems/cases - units
|
||||
.courseware-unit {
|
||||
|
||||
.draggable-drop-indicator-before {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.draggable-drop-indicator-after {
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// UI: DnD - specific elems/cases - empty parents initial drop indicator
|
||||
.draggable-drop-indicator-initial {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ from django.utils.translation import ugettext as _
|
||||
<%block name="bodyclass">is-signedin course container view-container</%block>
|
||||
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
<%namespace name="units" file="widgets/units.html" />
|
||||
|
||||
<%!
|
||||
templates = ["basic-modal", "modal-button", "edit-xblock-modal",
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
<%inherit file="base.html" />
|
||||
<%def name="online_help_token()"><% return "subsection" %></%def>
|
||||
<%!
|
||||
import logging
|
||||
from util.date_utils import get_default_time_display, almost_same_datetime
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.core.urlresolvers import reverse
|
||||
%>
|
||||
<%block name="title">${_("CMS Subsection")}</%block>
|
||||
<%block name="bodyclass">is-signedin course view-subsection</%block>
|
||||
|
||||
|
||||
<%namespace name="units" file="widgets/units.html" />
|
||||
<%namespace name='static' file='static_content.html'/>
|
||||
|
||||
<%block name="content">
|
||||
<div class="main-wrapper">
|
||||
<div class="inner-wrapper">
|
||||
<div class="main-column">
|
||||
<article class="subsection-body window" data-locator="${locator}" data-course-key="${locator.course_key}">
|
||||
<div class="subsection-name-input">
|
||||
<label>${_("Display Name:")}</label>
|
||||
<input type="text" value="${subsection.display_name_with_default | h}" class="subsection-display-name-input" data-metadata-name="display_name"/>
|
||||
</div>
|
||||
<div class="wrapper-dnd">
|
||||
<div class="sortable-unit-list">
|
||||
<label>${_("Units:")}</label>
|
||||
${units.enum_units(subsection, subsection_units=subsection_units)}
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
<div class="sidebar">
|
||||
<div class="unit-settings window id-holder" data-locator="${locator}" data-course-key="${locator.course_key}">
|
||||
<h4 class="header">${_("Subsection Settings")}</h4>
|
||||
<div class="window-contents">
|
||||
<div class="scheduled-date-input row">
|
||||
<div class="datepair" data-language="javascript">
|
||||
<div class="field field-start-date">
|
||||
<label for="start_date">${_("Release Day")}</label>
|
||||
<input type="text" id="start_date" name="start_date"
|
||||
value="${subsection.start.strftime('%m/%d/%Y') if subsection.start else ''}"
|
||||
placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
|
||||
</div>
|
||||
<div class="field field-start-time">
|
||||
<label for="start_time">${_("Release Time")} (<abbr title="${_("Coordinated Universal Time")}">${_("UTC")}</abbr>)</label>
|
||||
<input type="text" id="start_time" name="start_time"
|
||||
value="${subsection.start.strftime('%H:%M') if subsection.start else ''}"
|
||||
placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
|
||||
</div>
|
||||
</div>
|
||||
% if subsection.start and not almost_same_datetime(subsection.start, parent_item.start):
|
||||
% if parent_item.start is None:
|
||||
<p class="notice">${_("The date above differs from the release date of {name}, which is unset.").format(name=parent_item.display_name_with_default)}
|
||||
% else:
|
||||
<p class="notice">${_("The date above differs from the release date of {name} - {start_time}").format(name=parent_item.display_name_with_default, start_time=get_default_time_display(parent_item.start))}.
|
||||
% endif
|
||||
<a href="#" class="sync-date no-spinner">${_("Sync to {name}.").format(name=parent_item.display_name_with_default)}</a></p>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
<div class="row gradable">
|
||||
<label>${_("Graded as:")}</label>
|
||||
|
||||
<div class="gradable-status" data-initial-status="${subsection.format if subsection.format is not None else 'notgraded'}">
|
||||
</div>
|
||||
|
||||
<div class="due-date-input row">
|
||||
<a href="#" class="set-date">${_("Set a due date")}</a>
|
||||
<div class="datepair date-setter">
|
||||
<div class="field field-start-date">
|
||||
<label for="due_date">${_("Due Day")}</label>
|
||||
<input type="text" id="due_date" name="due_date"
|
||||
value="${subsection.due.strftime('%m/%d/%Y') if subsection.due else ''}"
|
||||
placeholder="MM/DD/YYYY" class="date" size='15' autocomplete="off"/>
|
||||
</div>
|
||||
<div class="field field-start-time">
|
||||
<label for="due_time">${_("Due Time")} (<abbr title="${_('Coordinated Universal Time')}">UTC</abbr>)</label>
|
||||
<input type="text" id="due_time" name="due_time"
|
||||
value="${subsection.due.strftime('%H:%M') if subsection.due else ''}"
|
||||
placeholder="HH:MM" class="time" size='10' autocomplete="off"/>
|
||||
</div>
|
||||
<a href="#" class="remove-date">${_("Remove due date")}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row unit-actions">
|
||||
<a href="${preview_link}" target="_blank" class="preview-button">${_("Preview Drafts")}</a>
|
||||
%if can_view_live:
|
||||
<a href="${lms_link}" target="_blank" class="preview-button">${_("View Live")}</a>
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</%block>
|
||||
|
||||
<%block name="jsextra">
|
||||
<link rel="stylesheet" type="text/css" href="${static.url('js/vendor/timepicker/jquery.timepicker.css')}" />
|
||||
|
||||
<script type="text/javascript">
|
||||
require(["domReady!", "jquery", "js/models/location", "js/views/overview_assignment_grader",
|
||||
"js/collections/course_grader", "js/views/overview"],
|
||||
function(doc, $, Location, OverviewAssignmentGrader, CourseGraderCollection) {
|
||||
// expand the due-date area if the values are set
|
||||
if ($('#due_date').val() != '') {
|
||||
var $block = $('.set-date').closest('.due-date-input');
|
||||
$('.set-date').hide();
|
||||
$block.find('.date-setter').show();
|
||||
}
|
||||
// TODO figure out whether these should be in window or someplace else or whether they're only needed as local vars
|
||||
// I believe that current (New Section/New Subsection) cause full page reloads which means these aren't needed globally
|
||||
// but we really should change that behavior.
|
||||
if (!window.graderTypes) {
|
||||
window.graderTypes = new CourseGraderCollection(${course_graders|n}, {parse:true});
|
||||
}
|
||||
|
||||
$(".gradable-status").each(function(index, ele) {
|
||||
var gradeView = new OverviewAssignmentGrader({
|
||||
el : ele,
|
||||
graders : window.graderTypes,
|
||||
hideSymbol : true
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</%block>
|
||||
@@ -11,7 +11,6 @@
|
||||
<%block name="bodyclass">is-signedin course uploads view-container</%block>
|
||||
|
||||
<%namespace name='static' file='../../static_content.html'/>
|
||||
<%namespace name="units" file="../../widgets/units.html" />
|
||||
|
||||
<%block name="content">
|
||||
<div id="content">
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
<%! from django.utils.translation import ugettext as _ %>
|
||||
<%! from contentstore.views.helpers import xblock_studio_url %>
|
||||
|
||||
<!--
|
||||
This def will enumerate through a passed in subsection and list all of the units
|
||||
-->
|
||||
<%def name="enum_units(subsection, actions=True, selected=None, sortable=True, subsection_units=None)">
|
||||
<ol ${'class="sortable-unit-list"' if sortable else ''}>
|
||||
<%
|
||||
if subsection_units is None:
|
||||
subsection_units = subsection.get_children()
|
||||
%>
|
||||
% for unit in subsection_units:
|
||||
<li class="courseware-unit unit is-draggable" data-locator="${unit.location}"
|
||||
data-parent="${subsection.location}" data-course-key="${unit.location.course_key}">
|
||||
|
||||
<%include file="_ui-dnd-indicator-before.html" />
|
||||
|
||||
<%
|
||||
unit_state = 'draft' # Note: this is a hack since this HTML file is being removed in bulk-publishing
|
||||
if unit.location == selected:
|
||||
selected_class = 'editing'
|
||||
else:
|
||||
selected_class = ''
|
||||
%>
|
||||
<div class="section-item ${selected_class}">
|
||||
<a href="${xblock_studio_url(unit)}" class="${unit_state}-item">
|
||||
<span class="unit-name">${unit.display_name_with_default}</span>
|
||||
</a>
|
||||
% if actions:
|
||||
<div class="item-actions">
|
||||
<ul class="actions-list">
|
||||
<li class="actions-item delete">
|
||||
<a href="#" data-tooltip="${_("Delete this unit")}" class="delete-unit-button action" data-locator="${unit.location}"><i class="icon-trash"></i><span class="sr">${_("Delete unit")}</span></a>
|
||||
</li>
|
||||
<li class="actions-item drag">
|
||||
<span data-tooltip="${_("Drag to sort")}" class="drag-handle unit-drag-handle"><span class="sr"> ${_("Drag to reorder unit")}</span></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
% endif
|
||||
</div>
|
||||
|
||||
<%include file="_ui-dnd-indicator-after.html" />
|
||||
</li>
|
||||
% endfor
|
||||
<li class="courseware-unit add-new-unit">
|
||||
<%include file="_ui-dnd-indicator-initial.html" />
|
||||
|
||||
<a href="#" class="new-unit-item" data-category="${new_unit_category}" data-parent="${subsection.location}">
|
||||
<i class="icon-plus"></i> ${_("New Unit")}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</%def>
|
||||
@@ -74,7 +74,6 @@ urlpatterns += patterns(
|
||||
),
|
||||
url(r'^course/{}?$'.format(settings.COURSE_KEY_PATTERN), 'course_handler', name='course_handler'),
|
||||
url(r'^course_notifications/{}/(?P<action_state_id>\d+)?$'.format(settings.COURSE_KEY_PATTERN), 'course_notifications_handler'),
|
||||
url(r'^subsection/{}$'.format(settings.USAGE_KEY_PATTERN), 'subsection_handler'),
|
||||
url(r'^container/{}$'.format(settings.USAGE_KEY_PATTERN), 'container_handler'),
|
||||
url(r'^checklists/{}/(?P<checklist_index>\d+)?$'.format(settings.COURSE_KEY_PATTERN), 'checklists_handler'),
|
||||
url(r'^orphan/{}$'.format(settings.COURSE_KEY_PATTERN), 'orphan_handler'),
|
||||
|
||||
@@ -46,7 +46,7 @@ REQUIREJS_WAIT = {
|
||||
# Note that calling your org, course number, or display name, 'course' will mess this up
|
||||
re.compile('^Course Outline \|'): [
|
||||
"js/base", "js/models/course", "js/models/location", "js/models/section",
|
||||
"js/views/overview", "js/views/section_edit"],
|
||||
"js/views/section_edit"],
|
||||
|
||||
# Dashboard
|
||||
re.compile('^My Courses \|'): [
|
||||
|
||||
@@ -258,11 +258,6 @@ function objectTagForFlashCamera(name) {
|
||||
}
|
||||
}
|
||||
|
||||
function linkNewWindow(e) {
|
||||
window.open($(e.target).attr('href'));
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
function waitForFlashLoad(func, flash_object) {
|
||||
if(!flash_object.hasOwnProperty('percentLoaded') || flash_object.percentLoaded() < 100){
|
||||
setTimeout(function() {
|
||||
@@ -334,6 +329,9 @@ $(document).ready(function() {
|
||||
analytics.pageview("Capture Face Photo");
|
||||
initSnapshotHandler(["photo_id", "face"], hasHtml5CameraSupport);
|
||||
|
||||
$('a[rel="external"]').attr('title', gettext('This link will open in a new browser window/tab')).bind('click', linkNewWindow);
|
||||
$('a[rel="external"]').attr({
|
||||
title: gettext('This link will open in a new browser window/tab'),
|
||||
target: '_blank'
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user