Merge branch 'feature/cale/cms-master' of github.com:MITx/mitx into feature/cdodge/xlint
This commit is contained in:
@@ -66,7 +66,10 @@ log = logging.getLogger(__name__)
|
||||
|
||||
COMPONENT_TYPES = ['customtag', 'discussion', 'html', 'problem', 'video']
|
||||
|
||||
DIRECT_ONLY_CATEGORIES = ['course', 'chapter', 'sequential']
|
||||
DIRECT_ONLY_CATEGORIES = ['course', 'chapter', 'sequential', 'about', 'static_tab', 'course_info']
|
||||
|
||||
# cdodge: these are categories which should not be parented, they are detached from the hierarchy
|
||||
DETACHED_CATEGORIES = ['about', 'static_tab', 'course_info']
|
||||
|
||||
|
||||
def _modulestore(location):
|
||||
@@ -692,7 +695,9 @@ def clone_item(request):
|
||||
new_item.metadata['display_name'] = display_name
|
||||
|
||||
_modulestore(template).update_metadata(new_item.location.url(), new_item.own_metadata)
|
||||
_modulestore(parent.location).update_children(parent_location, parent.definition.get('children', []) + [new_item.location.url()])
|
||||
|
||||
if new_item.location.category not in DETACHED_CATEGORIES:
|
||||
_modulestore(parent.location).update_children(parent_location, parent.definition.get('children', []) + [new_item.location.url()])
|
||||
|
||||
return HttpResponse(json.dumps({'id': dest_location.url()}))
|
||||
|
||||
@@ -873,6 +878,25 @@ def edit_static(request, org, course, coursename):
|
||||
return render_to_response('edit-static-page.html', {})
|
||||
|
||||
|
||||
def edit_tabs(request, org, course, coursename):
|
||||
location = ['i4x', org, course, 'course', coursename]
|
||||
course_item = modulestore().get_item(location)
|
||||
static_tabs_loc = Location('i4x', org, course, 'static_tab', None)
|
||||
|
||||
static_tabs = modulestore('direct').get_items(static_tabs_loc)
|
||||
|
||||
components = [
|
||||
static_tab.location.url()
|
||||
for static_tab
|
||||
in static_tabs
|
||||
]
|
||||
|
||||
return render_to_response('edit-tabs.html', {
|
||||
'active_tab': 'pages',
|
||||
'context_course':course_item,
|
||||
'components': components
|
||||
})
|
||||
|
||||
def not_found(request):
|
||||
return render_to_response('error.html', {'error': '404'})
|
||||
|
||||
@@ -977,6 +1001,17 @@ def create_new_course(request):
|
||||
# set a default start date to now
|
||||
new_course.metadata['start'] = stringify_time(time.gmtime())
|
||||
|
||||
# set up the default tabs
|
||||
# I've added this because when we add static tabs, the LMS either expects a None for the tabs list or
|
||||
# at least a list populated with the minimal times
|
||||
# @TODO: I don't like the fact that the presentation tier is away of these data related constraints, let's find a better
|
||||
# place for this. Also rather than using a simple list of dictionaries a nice class model would be helpful here
|
||||
new_course.tabs = [{"type": "courseware"},
|
||||
{"type": "course_info", "name": "Course Info"},
|
||||
{"type": "discussion", "name": "Discussion"},
|
||||
{"type": "wiki", "name": "Wiki"},
|
||||
{"type": "progress", "name": "Progress"}]
|
||||
|
||||
modulestore('direct').update_metadata(new_course.location.url(), new_course.own_metadata)
|
||||
|
||||
create_all_course_groups(request.user, new_course.location)
|
||||
|
||||
54
cms/static/coffee/src/views/tabs.coffee
Normal file
54
cms/static/coffee/src/views/tabs.coffee
Normal file
@@ -0,0 +1,54 @@
|
||||
class CMS.Views.TabsEdit extends Backbone.View
|
||||
events:
|
||||
'click .new-tab': 'addNewTab'
|
||||
|
||||
initialize: =>
|
||||
@$('.component').each((idx, element) =>
|
||||
new CMS.Views.ModuleEdit(
|
||||
el: element,
|
||||
onDelete: @deleteTab,
|
||||
model: new CMS.Models.Module(
|
||||
id: $(element).data('id'),
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@$('.components').sortable(
|
||||
handle: '.drag-handle'
|
||||
update: (event, ui) => alert 'not yet implemented!'
|
||||
helper: 'clone'
|
||||
opacity: '0.5'
|
||||
placeholder: 'component-placeholder'
|
||||
forcePlaceholderSize: true
|
||||
axis: 'y'
|
||||
items: '> .component'
|
||||
)
|
||||
|
||||
addNewTab: (event) =>
|
||||
event.preventDefault()
|
||||
|
||||
editor = new CMS.Views.ModuleEdit(
|
||||
onDelete: @deleteTab
|
||||
model: new CMS.Models.Module()
|
||||
)
|
||||
|
||||
$('.new-component-item').before(editor.$el)
|
||||
|
||||
editor.cloneTemplate(
|
||||
@model.get('id'),
|
||||
'i4x://edx/templates/static_tab/Empty'
|
||||
)
|
||||
|
||||
deleteTab: (event) =>
|
||||
if not confirm 'Are you sure you want to delete this component? This action cannot be undone.'
|
||||
return
|
||||
$component = $(event.currentTarget).parents('.component')
|
||||
$.post('/delete_item', {
|
||||
id: $component.data('id')
|
||||
}, =>
|
||||
$component.remove()
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
42
cms/templates/edit-tabs.html
Normal file
42
cms/templates/edit-tabs.html
Normal file
@@ -0,0 +1,42 @@
|
||||
<%inherit file="base.html" />
|
||||
<%! from django.core.urlresolvers import reverse %>
|
||||
<%block name="title">Tabs</%block>
|
||||
<%block name="bodyclass">static-pages</%block>
|
||||
|
||||
<%block name="jsextra">
|
||||
<script type='text/javascript'>
|
||||
new CMS.Views.TabsEdit({
|
||||
el: $('.main-wrapper'),
|
||||
model: new CMS.Models.Module({
|
||||
id: '${context_course.location}'
|
||||
})
|
||||
});
|
||||
</script>
|
||||
</%block>
|
||||
|
||||
<%block name="content">
|
||||
<div class="main-wrapper">
|
||||
<div class="inner-wrapper">
|
||||
<div>
|
||||
<h1>Static Tabs</h1>
|
||||
</div>
|
||||
<div class="main-column">
|
||||
<article class="unit-body window">
|
||||
<div class="tab-list">
|
||||
<ol class='components'>
|
||||
% for id in components:
|
||||
<li class="component" data-id="${id}"/>
|
||||
% endfor
|
||||
|
||||
<li class="new-component-item">
|
||||
<a href="#" class="new-component-button new-tab">
|
||||
<span class="plus-icon"></span>New Tab
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</%block>
|
||||
@@ -10,7 +10,7 @@
|
||||
<a href="${reverse('course_index', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, name=ctx_loc.name))}" class="class-name">${context_course.display_name}</a>
|
||||
<ul class="class-nav">
|
||||
<li><a href="${reverse('course_index', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, name=ctx_loc.name))}" id='courseware-tab'>Courseware</a></li>
|
||||
<li><a href="${reverse('static_pages', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, coursename=ctx_loc.name))}" id='pages-tab' style="display:none">Pages</a></li>
|
||||
<li><a href="${reverse('edit_tabs', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, coursename=ctx_loc.name))}" id='pages-tab'>Tabs</a></li>
|
||||
<li><a href="${reverse('asset_index', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, name=ctx_loc.name))}" id='assets-tab'>Assets</a></li>
|
||||
<li><a href="${reverse('manage_users', kwargs=dict(location=ctx_loc))}" id='users-tab'>Users</a></li>
|
||||
<li><a href="${reverse('import_course', kwargs=dict(org=ctx_loc.org, course=ctx_loc.course, name=ctx_loc.name))}" id='import-tab'>Import</a></li>
|
||||
|
||||
@@ -36,6 +36,7 @@ urlpatterns = ('',
|
||||
'contentstore.views.remove_user', name='remove_user'),
|
||||
url(r'^pages/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$', 'contentstore.views.static_pages', name='static_pages'),
|
||||
url(r'^edit_static/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$', 'contentstore.views.edit_static', name='edit_static'),
|
||||
url(r'^edit_tabs/(?P<org>[^/]+)/(?P<course>[^/]+)/course/(?P<coursename>[^/]+)$', 'contentstore.views.edit_tabs', name='edit_tabs'),
|
||||
url(r'^(?P<org>[^/]+)/(?P<course>[^/]+)/assets/(?P<name>[^/]+)$', 'contentstore.views.asset_index', name='asset_index'),
|
||||
|
||||
# temporary landing page for a course
|
||||
|
||||
Reference in New Issue
Block a user