diff --git a/cms/djangoapps/contentstore/views.py b/cms/djangoapps/contentstore/views.py index 5963814918..f680dd7262 100644 --- a/cms/djangoapps/contentstore/views.py +++ b/cms/djangoapps/contentstore/views.py @@ -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) diff --git a/cms/static/coffee/src/views/tabs.coffee b/cms/static/coffee/src/views/tabs.coffee new file mode 100644 index 0000000000..34d86a3051 --- /dev/null +++ b/cms/static/coffee/src/views/tabs.coffee @@ -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() + ) + + + + diff --git a/cms/templates/edit-tabs.html b/cms/templates/edit-tabs.html new file mode 100644 index 0000000000..94c5e38260 --- /dev/null +++ b/cms/templates/edit-tabs.html @@ -0,0 +1,42 @@ +<%inherit file="base.html" /> +<%! from django.core.urlresolvers import reverse %> +<%block name="title">Tabs +<%block name="bodyclass">static-pages + +<%block name="jsextra"> + + + +<%block name="content"> +
+
+
+

Static Tabs

+
+
+
+
+
    + % for id in components: +
  1. + % endfor + +
  2. + + New Tab + +
  3. +
+
+
+
+
+
+ \ No newline at end of file diff --git a/cms/templates/widgets/header.html b/cms/templates/widgets/header.html index 2b9b2c7884..0f5780a5d2 100644 --- a/cms/templates/widgets/header.html +++ b/cms/templates/widgets/header.html @@ -10,7 +10,7 @@ ${context_course.display_name}