Commit 606e2dba by Chris Dodge

Merge branch 'feature/cale/cms-master' of github.com:MITx/mitx into…

Merge branch 'feature/cale/cms-master' of github.com:MITx/mitx into feature/cdodge/import-course-info
parents fec6c42a 4432712e
......@@ -574,11 +574,11 @@ def save_item(request):
store = _modulestore(Location(item_location));
if request.POST['data']:
if request.POST['data'] is not None:
data = request.POST['data']
store.update_item(item_location, data)
if request.POST['children']:
if request.POST['children'] is not None:
children = request.POST['children']
store.update_children(item_location, children)
......@@ -587,7 +587,7 @@ def save_item(request):
# NOTE, that the postback is not the complete metadata, as there's system metadata which is
# not presented to the end-user for editing. So let's fetch the original and
# 'apply' the submitted metadata, so we don't end up deleting system metadata
if request.POST['metadata']:
if request.POST['metadata'] is not None:
posted_metadata = request.POST['metadata']
# fetch original
existing_item = modulestore().get_item(item_location)
......
class CMS.Models.Module extends Backbone.Model
url: '/save_item'
defaults:
data: ''
children: ''
metadata: {}
data: null
children: null
metadata: null
......@@ -5,11 +5,10 @@ class CMS.Views.UnitEdit extends Backbone.View
'click .new-component-templates .new-component-template a': 'saveNewComponent'
'click .new-component-templates .cancel-button': 'closeNewComponent'
'click .new-component-button': 'showNewComponentForm'
'click #save-draft': 'saveDraft'
'click #delete-draft': 'deleteDraft'
'click #create-draft': 'createDraft'
'click #publish-draft': 'publishDraft'
'change #visibility': 'setVisibility'
'click .delete-draft': 'deleteDraft'
'click .create-draft': 'createDraft'
'click .publish-draft': 'publishDraft'
'change .visibility-select': 'setVisibility'
initialize: =>
@visibilityView = new CMS.Views.UnitEdit.Visibility(
......@@ -17,11 +16,6 @@ class CMS.Views.UnitEdit extends Backbone.View
model: @model
)
@saveView = new CMS.Views.UnitEdit.SaveDraftButton(
el: @$('#save-draft')
model: @model
)
@locationView = new CMS.Views.UnitEdit.LocationState(
el: @$('.section-item.editing a')
model: @model
......@@ -41,7 +35,7 @@ class CMS.Views.UnitEdit extends Backbone.View
@$('.components').sortable(
handle: '.drag-handle'
update: (event, ui) => @model.set('children', @components())
update: (event, ui) => @model.save(children: @components())
helper: 'clone'
opacity: '0.5'
placeholder: 'component-placeholder'
......@@ -58,7 +52,6 @@ class CMS.Views.UnitEdit extends Backbone.View
id: $(element).data('id'),
)
)
update: (event, ui) => @model.set('children', @components())
)
# New component creation
......@@ -124,7 +117,7 @@ class CMS.Views.UnitEdit extends Backbone.View
id: $component.data('id')
}, =>
$component.remove()
@model.set('children', @components())
@model.save(children: @components())
)
deleteDraft: (event) ->
......@@ -167,7 +160,7 @@ class CMS.Views.UnitEdit extends Backbone.View
$.post(target_url, {
id: @$el.data('id')
}, =>
@model.set('state', @$('#visibility').val())
@model.set('state', @$('.visibility-select').val())
)
class CMS.Views.UnitEdit.NameEdit extends Backbone.View
......@@ -187,7 +180,6 @@ class CMS.Views.UnitEdit.NameEdit extends Backbone.View
metadata = $.extend({}, @model.get('metadata'))
metadata.display_name = @$('.unit-display-name-input').val()
$('.unit-location .editing .unit-name').html(metadata.display_name)
@model.set 'metadata', metadata
inputField = this.$el.find('input')
......@@ -204,7 +196,7 @@ class CMS.Views.UnitEdit.NameEdit extends Backbone.View
if @timer
clearTimeout @timer
@timer = setTimeout( =>
@model.save()
@model.save(metadata: metadata)
@timer = null
@$spinner.delay(500).fadeOut(150)
, 500)
......@@ -223,17 +215,3 @@ class CMS.Views.UnitEdit.Visibility extends Backbone.View
render: =>
@$el.val(@model.get('state'))
class CMS.Views.UnitEdit.SaveDraftButton extends Backbone.View
initialize: =>
@model.on('change:children', @enable)
@model.on('change:metadata', @enable)
@model.on('sync', @disable)
@disable()
disable: =>
@$el.addClass('disabled')
enable: =>
@$el.removeClass('disabled')
\ No newline at end of file
......@@ -33,7 +33,6 @@ $(document).ready(function() {
$('.unit .item-actions .delete-button').bind('click', deleteUnit);
$('.new-unit-item').bind('click', createNewUnit);
$('.save-subsection').bind('click', saveSubsection);
// autosave when a field is updated on the subsection page
$body.on('keyup', '.subsection-display-name-input, .unit-subtitle, .policy-list-value', checkForNewValue);
......@@ -63,6 +62,8 @@ $(document).ready(function() {
// add/remove policy metadata button click handlers
$('.add-policy-data').bind('click', addPolicyMetadata);
$('.remove-policy-data').bind('click', removePolicyMetadata);
$body.on('click', '.policy-list-element .save-button', savePolicyMetadata);
$body.on('click', '.policy-list-element .cancel-button', cancelPolicyMetadata);
$('.sync-date').bind('click', syncReleaseDate);
......@@ -161,19 +162,30 @@ function addPolicyMetadata(e) {
newNode.insertBefore('.add-policy-data');
$('.remove-policy-data').bind('click', removePolicyMetadata);
newNode.find('.policy-list-name').focus();
newNode.find('.save-button').bind('click', savePolicyMetadata);
newNode.find('.cancel-button').bind('click', cancelPolicyMetadata);
}
function savePolicyMetadata(e) {
e.preventDefault();
$('.save-subsection').click();
$(this).parents('.policy-list-element').removeClass('new-policy-list-element');
var $policyElement = $(this).parents('.policy-list-element');
saveSubsection()
$policyElement.removeClass('new-policy-list-element');
$policyElement.find('.policy-list-name').attr('disabled', 'disabled');
$policyElement.removeClass('editing');
}
function cancelPolicyMetadata(e) {
e.preventDefault();
$(this).parents('.policy-list-element').remove();
var $policyElement = $(this).parents('.policy-list-element');
if(!$policyElement.hasClass('editing')) {
$policyElement.remove();
} else {
$policyElement.removeClass('new-policy-list-element');
$policyElement.find('.policy-list-name').val($policyElement.data('currentValues')[0]);
$policyElement.find('.policy-list-value').val($policyElement.data('currentValues')[1]);
}
$policyElement.removeClass('editing');
}
function removePolicyMetadata(e) {
......@@ -189,7 +201,7 @@ function removePolicyMetadata(e) {
} else {
_parent_el.appendTo("#policy-to-delete");
}
$('.save-subsection').click();
saveSubsection()
}
......@@ -286,7 +298,7 @@ function checkForNewValue(e) {
this.saveTimer = setTimeout(function() {
$changedInput = $(e.target);
$('.save-subsection').click();
saveSubsection()
this.saveTimer = null;
}, 500);
}
......@@ -299,14 +311,12 @@ function autosaveInput(e) {
this.saveTimer = setTimeout(function() {
$changedInput = $(e.target);
$('.save-subsection').click();
saveSubsection()
this.saveTimer = null;
}, 500);
}
function saveSubsection(e) {
e.preventDefault();
function saveSubsection() {
if($changedInput && !$changedInput.hasClass('no-spinner')) {
$spinner.css({
'position': 'absolute',
......@@ -315,9 +325,10 @@ function saveSubsection(e) {
'margin-top': '-10px'
});
$changedInput.after($spinner);
$spinner.show();
}
var id = $(this).data('id');
var id = $('.subsection-body').data('id');
// pull all 'normalized' metadata editable fields on page
var metadata_fields = $('input[data-metadata-name]');
......@@ -417,7 +428,6 @@ function showUploadModal(e) {
e.preventDefault();
$modal = $('.upload-modal').show();
$('.file-input').bind('change', startUpload);
$('.upload-modal .choose-file-button').bind('click', showFileSelectionMenu);
$modalCover.show();
}
......@@ -428,7 +438,7 @@ function showFileSelectionMenu(e) {
function startUpload(e) {
$('.upload-modal h1').html('Uploading…');
$('.upload-modal .file-name').html($('.file-input').val());
$('.upload-modal .file-name').html($('.file-input').val().replace('C:\\fakepath\\', ''));
$('.upload-modal .file-chooser').ajaxSubmit({
beforeSend: resetUploadBar,
uploadProgress: showUploadFeedback,
......@@ -720,6 +730,9 @@ function saveEditSectionName(e) {
id = $(this).closest("section.courseware-section").data("id");
display_name = $.trim($(this).prev('.edit-section-name').val());
$(this).closest('.courseware-section .section-name').append($spinner);
$spinner.show();
if (display_name == '') {
alert("You must specify a name before saving.")
return;
......@@ -735,7 +748,7 @@ function saveEditSectionName(e) {
data:JSON.stringify({ 'id' : id, 'metadata' : {'display_name' : display_name}, 'data': null, 'children' : null})
}).success(function()
{
alert('Your changes have been saved.');
$spinner.delay(250).fadeOut(250);
$_this.parent().siblings('span.section-name-span').html(display_name);
$_this.parent().siblings('span.section-name-span').show();
$_this.parent().hide();
......
......@@ -22,12 +22,18 @@
}
.policy-list {
input[disabled] {
border: none;
@include box-shadow(none);
}
.policy-list-name {
margin-right: 5px;
margin-bottom: 10px;
}
.policy-list-value {
width: 320px;
margin-right: 10px;
}
}
......@@ -37,11 +43,26 @@
.cancel-button {
display: none;
}
.edit-icon {
margin-right: 8px;
}
&.editing,
&.new-policy-list-element {
.policy-list-name,
.policy-list-value {
border: 1px solid #b0b6c2;
@include linear-gradient(top, rgba(255, 255, 255, 0), rgba(255, 255, 255, .3));
background-color: #edf1f5;
@include box-shadow(0 1px 2px rgba(0, 0, 0, .1) inset);
}
}
}
.new-policy-list-element {
padding: 10px 10px 0;
margin: 0 -10px;
margin: 0 -10px 10px;
border-radius: 3px;
background: $mediumGrey;
......@@ -54,6 +75,10 @@
@include white-button;
}
.edit-icon {
display: none;
}
.delete-icon {
display: none;
}
......
......@@ -321,12 +321,15 @@
@include orange-button;
}
.save-button {
.delete-button {
@include blue-button;
display: none;
}
.save-button,
.delete-draft {
display: inline-block;
}
.delete-button,
.preview-button,
.publish-button,
.view-button {
......@@ -443,11 +446,10 @@
}
.edit-state-public {
#save-draft,
#delete-draft,
.delete-draft,
.component-actions,
.new-component-item,
#published-alert,
.editing-draft-alert,
.publish-draft-message,
.preview-button {
display: none;
......@@ -463,10 +465,10 @@
}
.edit-state-private {
#delete-draft,
#publish-draft,
#published-alert,
#create-draft,
.delete-draft,
.publish-draft,
.editing-draft-alert,
.create-draft,
.view-button {
display: none;
}
......
......@@ -18,7 +18,7 @@
<div class="main-wrapper">
<div class="inner-wrapper">
<div class="main-column">
<article class="subsection-body window">
<article class="subsection-body window" data-id="${subsection.location}">
<div class="subsection-name-input">
<label>Display Name:</label>
<input type="text" value="${subsection.metadata['display_name']}" class="subsection-display-name-input" data-metadata-name="display_name"/>
......@@ -36,7 +36,9 @@
<ol class='policy-list'>
% for policy_name in policy_metadata.keys():
<li class="policy-list-element">
<input type="text" class="policy-list-name" name="${policy_name}" value="${policy_name}" disabled size="15"/>:&nbsp;<input type="text" class="policy-list-value" name="${policy_metadata[policy_name]}" value="${policy_metadata[policy_name]}" size="40"/><a href="#" class="delete-icon remove-policy-data"></a>
<input type="text" class="policy-list-name" name="${policy_name}" value="${policy_name}" disabled size="15"/>:&nbsp;<input type="text" class="policy-list-value" name="${policy_metadata[policy_name]}" value="${policy_metadata[policy_name]}" size="40"/>
<a href="#" class="cancel-button">Cancel</a>
<a href="#" class="delete-icon remove-policy-data"></a>
</li>
% endfor
<a href="#" class="new-policy-item add-policy-data">
......@@ -98,7 +100,6 @@
</div>
</div>
<div class="row unit-actions">
<a href="#" class="save-button save-subsection" data-id="${subsection.location}">Save</a>
<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>
......
......@@ -9,7 +9,7 @@
<article class="user-overview">
<div class="details">
<p>The following list of users have been designated as course staff. This means that these users will have permissions to modify course content. You may add additional source staff below, if you are the course instructor. Please note that they must have already registered and verified their account.</p>
<p>The following list of users have been designated as course staff. This means that these users will have permissions to modify course content. You may add additional course staff below, if you are the course instructor. Please note that they must have already registered and verified their account.</p>
</div>
<div class="list-header">
%if allow_actions:
......@@ -97,4 +97,4 @@
});
});
</script>
</%block>
\ No newline at end of file
</%block>
......@@ -17,7 +17,7 @@
<%block name="content">
<div class="main-wrapper edit-state-${unit_state}" data-id="${unit_location}">
<div class="inner-wrapper">
<div class="alert" id="published-alert">
<div class="alert editing-draft-alert">
<p class="alert-message"><strong>You are editing a draft.</strong>
% if published_date:
This unit was originally published on ${published_date}.
......@@ -75,21 +75,20 @@
<div class="window-contents">
<div class="row visibility">
<label class="inline-label">Visibility:</label>
<select id='visibility'>
<select class='visibility-select'>
<option value="public">Public</option>
<option value="private">Private</option>
</select>
</div>
<div class="row published-alert">
<p class="edit-draft-message">This unit has been published. To make changes, you must <a href="#" id="create-draft">edit a draft</a>.</p>
<p class="publish-draft-message">This is a draft of the published unit. To update the live version, you must <a href="#" id="publish-draft">replace it with this draft</a>.</p>
<p class="edit-draft-message">This unit has been published. To make changes, you must <a href="#" class="create-draft">edit a draft</a>.</p>
<p class="publish-draft-message">This is a draft of the published unit. To update the live version, you must <a href="#" class="publish-draft">replace it with this draft</a>.</p>
</div>
<div class="row status">
<p>This unit is scheduled to be released to <strong>students</strong> on <strong>${release_date}</strong> with the subsection <a href="${reverse('edit_subsection', kwargs={'location': subsection.location})}">"${subsection.display_name}"</a></p>
</div>
<div class="row unit-actions">
<a id="save-draft" href="#" class="save-button">Save Draft</a>
<a id="delete-draft" href="#" class="save-button">Delete Draft</a>
<a href="#" class="delete-draft delete-button">Delete Draft</a>
<a href="${draft_preview_link}" target="_blank" class="preview-button">Preview</a>
<a href="${published_preview_link}" target="_blank" class="view-button">View Live</a>
</div>
......
......@@ -66,7 +66,7 @@ class ABTestModule(XModule):
class ABTestDescriptor(RawDescriptor, XmlDescriptor):
module_class = ABTestModule
# template_dir_name = "abtest"
template_dir_name = "abtest"
def __init__(self, system, definition=None, **kwargs):
"""
......
......@@ -168,7 +168,7 @@ class CourseDescriptor(SequenceDescriptor):
def read_grading_policy(cls, paths, system):
"""Load a grading policy from the specified paths, in order, if it exists."""
# Default to a blank policy
policy_str = ""
policy_str = '""'
for policy_path in paths:
if not system.resources_fs.exists(policy_path):
......
......@@ -38,6 +38,7 @@ class CustomTagModule(XModule):
class CustomTagDescriptor(RawDescriptor):
""" Descriptor for custom tags. Loads the template when created."""
module_class = CustomTagModule
template_dir_name = 'customtag'
@staticmethod
def render_template(system, xml_data):
......
......@@ -31,8 +31,6 @@ def all_templates():
templates = defaultdict(list)
for category, descriptor in XModuleDescriptor.load_classes():
if category == 'course':
logging.debug(descriptor.templates())
templates[category] = descriptor.templates()
return templates
......@@ -67,7 +65,13 @@ def update_templates():
template_location = Location('i4x', 'edx', 'templates', category, Location.clean_for_url_name(template.metadata['display_name']))
try:
json_data = {'definition': {'data': template.data, 'children' : template.children}}
json_data = {
'definition': {
'data': template.data,
'children': template.children
},
'metadata': template.metadata
}
json_data['location'] = template_location.dict()
XModuleDescriptor.load_from_json(json_data, TemplateTestSystem())
......
---
metadata:
display_name: Empty
start: 2020-10-10T10:00
data: { 'textbooks' : [ ], 'wiki_slug' : null }
children: []
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