Commit c5fc30c5 by Andy Armstrong Committed by marco

First rough cut of a container page.

parent b23e9fb6
......@@ -35,6 +35,7 @@ __all__ = ['OPEN_ENDED_COMPONENT_TYPES',
'ADVANCED_COMPONENT_POLICY_KEY',
'subsection_handler',
'unit_handler',
'container_handler',
'component_handler'
]
......@@ -304,6 +305,159 @@ def unit_handler(request, tag=None, package_id=None, branch=None, version_guid=N
return HttpResponseBadRequest("Only supports html requests")
@require_http_methods(["GET"])
@login_required
def container_handler(request, tag=None, package_id=None, branch=None, version_guid=None, block=None):
"""
The restful handler for unit-specific requests.
GET
html: return html page for editing a unit
json: not currently supported
"""
if 'text/html' in request.META.get('HTTP_ACCEPT', 'text/html'):
locator = BlockUsageLocator(package_id=package_id, branch=branch, version_guid=version_guid, block_id=block)
try:
old_location, course, item, lms_link = _get_item_in_course(request, locator)
except ItemNotFoundError:
return HttpResponseBadRequest()
component_templates = defaultdict(list)
for category in COMPONENT_TYPES:
component_class = _load_mixed_class(category)
# add the default template
# TODO: Once mixins are defined per-application, rather than per-runtime,
# this should use a cms mixed-in class. (cpennington)
if hasattr(component_class, 'display_name'):
display_name = component_class.display_name.default or 'Blank'
else:
display_name = 'Blank'
component_templates[category].append((
display_name,
category,
False, # No defaults have markdown (hardcoded current default)
None # no boilerplate for overrides
))
# add boilerplates
if hasattr(component_class, 'templates'):
for template in component_class.templates():
filter_templates = getattr(component_class, 'filter_templates', None)
if not filter_templates or filter_templates(template, course):
component_templates[category].append((
template['metadata'].get('display_name'),
category,
template['metadata'].get('markdown') is not None,
template.get('template_id')
))
# Check if there are any advanced modules specified in the course policy.
# These modules should be specified as a list of strings, where the strings
# are the names of the modules in ADVANCED_COMPONENT_TYPES that should be
# enabled for the course.
course_advanced_keys = course.advanced_modules
# Set component types according to course policy file
if isinstance(course_advanced_keys, list):
for category in course_advanced_keys:
if category in ADVANCED_COMPONENT_TYPES:
# Do I need to allow for boilerplates or just defaults on the
# class? i.e., can an advanced have more than one entry in the
# menu? one for default and others for prefilled boilerplates?
try:
component_class = _load_mixed_class(category)
component_templates['advanced'].append(
(
component_class.display_name.default or category,
category,
False,
None # don't override default data
)
)
except PluginMissingError:
# dhm: I got this once but it can happen any time the
# course author configures an advanced component which does
# not exist on the server. This code here merely
# prevents any authors from trying to instantiate the
# non-existent component type by not showing it in the menu
pass
else:
log.error(
"Improper format for course advanced keys! %s",
course_advanced_keys
)
components = [
loc_mapper().translate_location(
course.location.course_id, component.location, False, True
)
for component
in item.get_children()
]
# TODO (cpennington): If we share units between courses,
# this will need to change to check permissions correctly so as
# to pick the correct parent subsection
containing_subsection_locs = modulestore().get_parent_locations(old_location, None)
containing_subsection = modulestore().get_item(containing_subsection_locs[0])
containing_section_locs = modulestore().get_parent_locations(
containing_subsection.location, None
)
containing_section = modulestore().get_item(containing_section_locs[0])
# cdodge hack. We're having trouble previewing drafts via jump_to redirect
# so let's generate the link url here
# need to figure out where this item is in the list of children as the
# preview will need this
index = 1
for child in containing_subsection.get_children():
if child.location == item.location:
break
index = index + 1
preview_lms_base = settings.FEATURES.get('PREVIEW_LMS_BASE')
preview_lms_link = (
'//{preview_lms_base}/courses/{org}/{course}/'
'{course_name}/courseware/{section}/{subsection}/{index}'
).format(
preview_lms_base=preview_lms_base,
lms_base=settings.LMS_BASE,
org=course.location.org,
course=course.location.course,
course_name=course.location.name,
section=containing_section.location.name,
subsection=containing_subsection.location.name,
index=index
)
return render_to_response('container.html', {
'context_course': course,
'unit': item,
'unit_locator': locator,
'components': components,
'component_templates': component_templates,
'draft_preview_link': preview_lms_link,
'published_preview_link': lms_link,
'subsection': containing_subsection,
'release_date': (
get_default_time_display(containing_subsection.start)
if containing_subsection.start is not None else None
),
'section': containing_section,
'new_unit_category': 'vertical',
'unit_state': compute_unit_state(item),
'published_date': (
get_default_time_display(item.published_date)
if item.published_date is not None else None
),
})
else:
return HttpResponseBadRequest("Only supports html requests")
@login_required
def _get_item_in_course(request, locator):
"""
......
......@@ -41,6 +41,7 @@
@import 'views/static-pages';
@import 'views/subsection';
@import 'views/unit';
@import 'views/container';
@import 'views/users';
@import 'views/checklists';
@import 'views/textbooks';
......
<%inherit file="base.html" />
<%!
from django.core.urlresolvers import reverse
from django.utils.translation import ugettext as _
%>
<%block name="title">${_("Container")}</%block>
<%block name="bodyclass">is-signedin course uploads view-container</%block>
<%namespace name='static' file='static_content.html'/>
<%block name="header_extras">
% for template_name in [ ]:
<script type="text/template" id="${template_name}-tpl">
<%static:include path="js/${template_name}.underscore" />
</script>
% endfor
</%block>
<%block name="jsextra">
<script type='text/javascript'>
require(["domReady!", "jquery", "js/models/module_info", "coffee/src/views/unit", "jquery.ui"],
function(doc, $, ModuleModel, UnitEditView, ui) {
window.unit_location_analytics = '${unit_locator}';
// tabs
$('.tab-group').tabs();
new UnitEditView({
el: $('.main-wrapper'),
model: new ModuleModel({
id: '${unit_locator}',
state: '${unit_state}'
})
});
$('.new-component-template').each(function(){
$emptyEditor = $(this).find('.empty');
$(this).prepend($emptyEditor);
});
});
</script>
</%block>
<%block name="content">
<div class="wrapper-mast wrapper">
<header class="mast has-actions has-subtitle">
<h1 class="page-header">
<small class="subtitle">${_("Content")}</small>
<span class="sr">&gt; </span>${_("Container")}
</h1>
<nav class="nav-actions">
<h3 class="sr">${_("Page Actions")}</h3>
<ul>
<li class="nav-item">
<a href="#" class="button upload-button new-button"><i class="icon-plus"></i> ${_("Upload New File")}</a>
</li>
</ul>
</nav>
</header>
</div>
<div class="wrapper-content wrapper">
<section class="content">
<article class="unit-body window">
<p class="unit-name-input"><label for="unit-display-name-input">${_("Display Name:")}</label><input type="text" value="${unit.display_name_with_default | h}" id="unit-display-name-input" class="unit-display-name-input" /></p>
<ol class="components">
% for locator in components:
<li class="component" data-locator="${locator}"/>
% endfor
<li class="new-component-item adding">
<div class="new-component">
<h5>${_("Add New Component")}</h5>
<ul class="new-component-type">
% for type, templates in sorted(component_templates.items()):
<li>
% if type == 'advanced' or len(templates) > 1:
<a href="#" class="multiple-templates" data-type="${type}">
% else:
% for __, category, __, __ in templates:
<a href="#" class="single-template" data-type="${type}" data-category="${category}">
% endfor
% endif
<span class="large-template-icon large-${type}-icon"></span>
<span class="name">${type}</span>
</a>
</li>
% endfor
</ul>
</div>
% for type, templates in sorted(component_templates.items()):
% if len(templates) > 1 or type == 'advanced':
<div class="new-component-templates new-component-${type}">
% if type == "problem":
<div class="tab-group tabs">
<ul class="problem-type-tabs nav-tabs">
<li class="current">
<a class="link-tab" href="#tab1">${_("Common Problem Types")}</a>
</li>
<li>
<a class="link-tab" href="#tab2">${_("Advanced")}</a>
</li>
</ul>
% endif
<div class="tab current" id="tab1">
<ul class="new-component-template">
% for name, category, has_markdown, boilerplate_name in sorted(templates):
% if has_markdown or type != "problem":
% if boilerplate_name is None:
<li class="editor-md empty">
<a href="#" data-category="${category}">
<span class="name">${name}</span>
</a>
</li>
% else:
<li class="editor-md">
<a href="#" data-category="${category}"
data-boilerplate="${boilerplate_name}">
<span class="name">${name}</span>
</a>
</li>
% endif
% endif
%endfor
</ul>
</div>
% if type == "problem":
<div class="tab" id="tab2">
<ul class="new-component-template">
% for name, category, has_markdown, boilerplate_name in sorted(templates):
% if not has_markdown:
<li class="editor-manual">
<a href="#" data-category="${category}"
data-boilerplate="${boilerplate_name}">
<span class="name">${name}</span>
</a>
</li>
% endif
% endfor
</ul>
</div>
</div>
% endif
<a href="#" class="cancel-button">Cancel</a>
</div>
% endif
% endfor
</li>
</ol>
</article>
<aside class="content-supplementary" role="complimentary">
<div class="bit">
<h3 class="title-3">${_("What files are listed here?")}</h3>
<p>${_("In addition to the files you upload on this page, any files that you add to the course appear in this list. These files include your course image, textbook chapters, and files that appear on your Course Handouts sidebar.")}</p>
</div>
<div class="bit">
<h3 class="title-3">${_("What can I do on this page?")}</h3>
<ul class="list-details">
<li class="item-detail">${_("You can upload new files or view, download, or delete existing files. You can lock a file so that people who are not enrolled in your course cannot access that file.")}</li>
<li class="item-detail">${_("Use the URL listed for a file to create a link to that file in the Course Handouts sidebar or in the body of the course.")}</li>
</ul>
</div>
</aside>
</section>
</div>
</%block>
<%block name="view_alerts">
<!-- alert: save confirmed with close -->
<div class="wrapper wrapper-alert wrapper-alert-confirmation" role="status">
<div class="alert confirmation">
<i class="icon-ok"></i>
<div class="copy">
<h2 class="title title-3">${_('Your file has been deleted.')}</h2>
</div>
<a href="" rel="view" class="action action-alert-close">
<i class="icon-remove-sign"></i>
<span class="label">${_('close alert')}</span>
</a>
</div>
</div>
</%block>
......@@ -70,6 +70,7 @@ urlpatterns += patterns(
url(r'(?ix)^course($|/){}$'.format(parsers.URL_RE_SOURCE), 'course_handler'),
url(r'(?ix)^subsection($|/){}$'.format(parsers.URL_RE_SOURCE), 'subsection_handler'),
url(r'(?ix)^unit($|/){}$'.format(parsers.URL_RE_SOURCE), 'unit_handler'),
url(r'(?ix)^container($|/){}$'.format(parsers.URL_RE_SOURCE), 'container_handler'),
url(r'(?ix)^checklists/{}(/)?(?P<checklist_index>\d+)?$'.format(parsers.URL_RE_SOURCE), 'checklists_handler'),
url(r'(?ix)^orphan/{}$'.format(parsers.URL_RE_SOURCE), 'orphan_handler'),
url(r'(?ix)^assets/{}(/)?(?P<asset_id>.+)?$'.format(parsers.URL_RE_SOURCE), 'assets_handler'),
......
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