Commit 282bddd4 by Alan Boudreault Committed by Jonathan Piacenti

XBlock Discussion changes

Conflicts:
	cms/djangoapps/contentstore/views/helpers.py
	common/static/coffee/src/discussion/content.coffee
	common/static/coffee/src/discussion/discussion_filter.coffee
	common/static/coffee/src/discussion/discussion_module_view.coffee
	common/static/coffee/src/discussion/discussion_router.coffee
	common/static/coffee/src/discussion/views/discussion_content_view.coffee
	common/static/coffee/src/discussion/views/discussion_thread_profile_view.coffee
	common/static/coffee/src/discussion/views/discussion_thread_show_view.coffee
	common/static/coffee/src/discussion/views/discussion_thread_view.coffee
	common/static/coffee/src/discussion/views/new_post_view.coffee
	common/static/coffee/src/discussion/views/response_comment_show_view.coffee
	common/static/coffee/src/discussion/views/thread_response_show_view.coffee
	common/static/coffee/src/discussion/views/thread_response_view.coffee
	lms/djangoapps/django_comment_client/forum/views.py
	lms/static/sass/discussion/_discussion.scss
	lms/templates/discussion/_discussion_module.html
	lms/templates/discussion/_filter_dropdown.html
	lms/templates/discussion/_js_head_dependencies.html
	lms/templates/discussion/_thread_list_template.html
	lms/templates/discussion/_underscore_templates.html
	lms/templates/discussion/index.html
	lms/templates/discussion/mustache/_inline_discussion.mustache
	lms/templates/discussion/mustache/_pagination.mustache
	lms/templates/discussion/mustache/_profile_thread.mustache
parent 650582eb
...@@ -12,6 +12,7 @@ from django.http import HttpResponse ...@@ -12,6 +12,7 @@ from django.http import HttpResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
from edxmako import add_lookup
from edxmako.shortcuts import render_to_string, render_to_response from edxmako.shortcuts import render_to_string, render_to_response
from opaque_keys.edx.keys import UsageKey from opaque_keys.edx.keys import UsageKey
from xblock.core import XBlock from xblock.core import XBlock
...@@ -37,6 +38,14 @@ GRADER_TYPES = { ...@@ -37,6 +38,14 @@ GRADER_TYPES = {
} }
# Add Discussion templates
add_lookup('lms.main', 'templates', package='discussion_app')
# Add Discussion templates
add_lookup('lms.main', 'templates', package='discussion_app')
# points to the temporary course landing page with log in and sign up # points to the temporary course landing page with log in and sign up
def landing(request, org, course, coursename): def landing(request, org, course, coursename):
return render_to_response('temp-course-landing.html', {}) return render_to_response('temp-course-landing.html', {})
...@@ -62,6 +71,22 @@ def render_from_lms(template_name, dictionary, context=None, namespace='main'): ...@@ -62,6 +71,22 @@ def render_from_lms(template_name, dictionary, context=None, namespace='main'):
return render_to_string(template_name, dictionary, context, namespace="lms." + namespace) return render_to_string(template_name, dictionary, context, namespace="lms." + namespace)
def _xmodule_recurse(item, action, ignore_exception=()):
"""
Recursively apply provided action on item and its children
ignore_exception (Exception Object): A optional argument; when passed ignores the corresponding
exception raised during xmodule recursion,
"""
for child in item.get_children():
_xmodule_recurse(child, action, ignore_exception)
try:
return action(item)
except ignore_exception:
return
def get_parent_xblock(xblock): def get_parent_xblock(xblock):
""" """
Returns the xblock that is the parent of the specified xblock, or None if it has no parent. Returns the xblock that is the parent of the specified xblock, or None if it has no parent.
......
...@@ -17,3 +17,6 @@ def run(): ...@@ -17,3 +17,6 @@ def run():
clear_lookups(namespace) clear_lookups(namespace)
for directory in directories: for directory in directories:
add_lookup(namespace, directory) add_lookup(namespace, directory)
# Add Discussion templates
add_lookup('main', 'templates', package='discussion_app')
...@@ -59,9 +59,9 @@ class DiscussionModule(DiscussionFields, XModule): ...@@ -59,9 +59,9 @@ class DiscussionModule(DiscussionFields, XModule):
'course': self.get_course(), 'course': self.get_course(),
} }
if getattr(self.system, 'is_author_mode', False): if getattr(self.system, 'is_author_mode', False):
template = 'discussion/_discussion_module_studio.html' template = '/discussion/_discussion_inline_studio.html'
else: else:
template = 'discussion/_discussion_module.html' template = '/discussion/_discussion_inline.html'
return self.system.render_template(template, context) return self.system.render_template(template, context)
def get_course(self): def get_course(self):
......
...@@ -3,6 +3,7 @@ import os ...@@ -3,6 +3,7 @@ import os
import sys import sys
import time import time
import yaml import yaml
import xml.sax.saxutils as saxutils
from contracts import contract, new_contract from contracts import contract, new_contract
from functools import partial from functools import partial
...@@ -1556,7 +1557,119 @@ class XMLParsingSystem(DescriptorSystem): ...@@ -1556,7 +1557,119 @@ class XMLParsingSystem(DescriptorSystem):
setattr(xblock, field.name, field_value) setattr(xblock, field.name, field_value)
class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # pylint: disable=abstract-method class DiscussionService(object):
"""
This is a temporary service that provides everything needed to render the discussion template.
Used by xblock-discussion
"""
def __init__(self, runtime):
self.runtime = runtime
def get_course_template_context(self):
"""
Returns the context to render the course-level discussion templates.
"""
import json
from django.http import HttpRequest
import lms.lib.comment_client as cc
from courseware.access import has_access
from courseware.courses import get_course_with_access
from django_comment_client.forum.views import get_threads
from django_comment_client.permissions import has_permission
import django_comment_client.utils as utils
from openedx.core.djangoapps.course_groups.cohorts import (
is_course_cohorted,
get_cohort_id,
get_cohorted_commentables,
get_course_cohorts
)
escapedict = {'"': '"'}
request = HttpRequest()
user = self.runtime.user
request.user = user
user_info = cc.User.from_django_user(self.runtime.user).to_dict()
course_id = self.runtime.course_id
course = get_course_with_access(self.runtime.user, 'load_forum', course_id)
user_cohort_id = get_cohort_id(user, course_id)
unsafethreads, query_params = get_threads(request, course_id)
threads = [utils.prepare_content(thread) for thread in unsafethreads]
flag_moderator = has_permission(user, 'openclose_thread', course_id) or \
has_access(user, 'staff', course)
annotated_content_info = utils.get_metadata_for_threads(course_id, threads, user, user_info)
category_map = utils.get_discussion_category_map(course, user)
cohorts = get_course_cohorts(course_id)
cohorted_commentables = get_cohorted_commentables(course_id)
context = {
'course': course,
'course_id': course_id,
'staff_access': has_access(user, 'staff', course),
'threads': saxutils.escape(json.dumps(threads), escapedict),
'thread_pages': query_params['num_pages'],
'user_info': saxutils.escape(json.dumps(user_info), escapedict),
'flag_moderator': flag_moderator,
'annotated_content_info': saxutils.escape(json.dumps(annotated_content_info), escapedict),
'category_map': category_map,
'roles': saxutils.escape(json.dumps(utils.get_role_ids(course_id)), escapedict),
'is_moderator': has_permission(user, "see_all_cohorts", course_id),
'cohorts': cohorts,
'user_cohort': user_cohort_id,
'cohorted_commentables': cohorted_commentables,
'is_course_cohorted': is_course_cohorted(course_id),
'has_permission_to_create_thread': has_permission(user, "create_thread", course_id),
'has_permission_to_create_comment': has_permission(user, "create_comment", course_id),
'has_permission_to_create_subcomment': has_permission(user, "create_subcomment", course_id),
'has_permission_to_openclose_thread': has_permission(user, "openclose_thread", course_id)
}
return context
def get_inline_template_context(self, discussion_id):
"""
Returns the context to render inline discussion templates.
"""
import lms.lib.comment_client as cc
from courseware.courses import get_course_with_access
from courseware.access import has_access
from django_comment_client.permissions import has_permission
from django_comment_client.utils import get_discussion_category_map
course_id = self.runtime.course_id
user = self.runtime.user
course = get_course_with_access(user, 'load_forum', course_id)
category_map = get_discussion_category_map(course)
is_moderator = has_permission(user, "see_all_cohorts", course_id)
flag_moderator = has_permission(user, 'openclose_thread', course_id) or \
has_access(user, 'staff', course)
context = {
'course': course,
'category_map': category_map,
'is_moderator': is_moderator,
'flag_moderator': flag_moderator,
'has_permission_to_create_thread': has_permission(user, "create_thread", course_id),
'has_permission_to_create_comment': has_permission(user, "create_comment", course_id),
'has_permission_to_create_subcomment': has_permission(user, "create_subcomment", course_id),
'has_permission_to_openclose_thread': has_permission(user, "openclose_thread", course_id)
}
return context
class ModuleSystem(MetricsMixin,ConfigurableFragmentWrapper, Runtime): # pylint: disable=abstract-method
""" """
This is an abstraction such that x_modules can function independent This is an abstraction such that x_modules can function independent
of the courseware (e.g. import into other types of courseware, LMS, of the courseware (e.g. import into other types of courseware, LMS,
...@@ -1646,6 +1759,10 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # pylin ...@@ -1646,6 +1759,10 @@ class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # pylin
modules, which have an anonymous handler, to set legitimate users' data modules, which have an anonymous handler, to set legitimate users' data
""" """
# Add the DiscussionService for the LMS and Studio.
services = kwargs.setdefault('services', {})
services['discussion'] = DiscussionService(self)
# Usage_store is unused, and field_data is often supplanted with an # Usage_store is unused, and field_data is often supplanted with an
# explicit field_data during construct_xblock. # explicit field_data during construct_xblock.
kwargs.setdefault('id_reader', getattr(descriptor_runtime, 'id_reader', OpaqueKeyReader())) kwargs.setdefault('id_reader', getattr(descriptor_runtime, 'id_reader', OpaqueKeyReader()))
......
...@@ -26,6 +26,8 @@ from openedx.core.djangoapps.course_groups.cohorts import ( ...@@ -26,6 +26,8 @@ from openedx.core.djangoapps.course_groups.cohorts import (
is_commentable_cohorted is_commentable_cohorted
) )
from courseware.tabs import EnrolledTab from courseware.tabs import EnrolledTab
from course_groups.cohorts import (is_course_cohorted, get_cohort_id, get_cohorted_threads_privacy,
get_cohorted_commentables, get_course_cohorts, get_cohort_by_id)
from courseware.access import has_access from courseware.access import has_access
from xmodule.modulestore.django import modulestore from xmodule.modulestore.django import modulestore
from ccx.overrides import get_current_ccx from ccx.overrides import get_current_ccx
...@@ -285,8 +287,9 @@ def forum_form_discussion(request, course_key): ...@@ -285,8 +287,9 @@ def forum_form_discussion(request, course_key):
'roles': _attr_safe_json(utils.get_role_ids(course_key)), 'roles': _attr_safe_json(utils.get_role_ids(course_key)),
'is_moderator': has_permission(request.user, "see_all_cohorts", course_key), 'is_moderator': has_permission(request.user, "see_all_cohorts", course_key),
'cohorts': course_settings["cohorts"], # still needed to render _thread_list_template 'cohorts': course_settings["cohorts"], # still needed to render _thread_list_template
'user_cohort': user_cohort_id, # read from container in NewPostView
'is_course_cohorted': is_course_cohorted(course_key), # still needed to render _thread_list_template 'is_course_cohorted': is_course_cohorted(course_key), # still needed to render _thread_list_template
'user_cohort': user_cohort_id, # read from container in NewPostView
'cohorted_commentables': (get_cohorted_commentables(course_key)),
'sort_preference': user.default_sort_key, 'sort_preference': user.default_sort_key,
'category_map': course_settings["category_map"], 'category_map': course_settings["category_map"],
'course_settings': _attr_safe_json(course_settings) 'course_settings': _attr_safe_json(course_settings)
...@@ -393,7 +396,12 @@ def single_thread(request, course_key, discussion_id, thread_id): ...@@ -393,7 +396,12 @@ def single_thread(request, course_key, discussion_id, thread_id):
'user_cohort': user_cohort, 'user_cohort': user_cohort,
'sort_preference': cc_user.default_sort_key, 'sort_preference': cc_user.default_sort_key,
'category_map': course_settings["category_map"], 'category_map': course_settings["category_map"],
'course_settings': _attr_safe_json(course_settings) 'course_settings': _attr_safe_json(course_settings),
'cohorted_commentables': (get_cohorted_commentables(course_id)),
'has_permission_to_create_thread': cached_has_permission(request.user, "create_thread", course_id),
'has_permission_to_create_comment': cached_has_permission(request.user, "create_comment", course_id),
'has_permission_to_create_subcomment': cached_has_permission(request.user, "create_subcomment", course_id),
'has_permission_to_openclose_thread': cached_has_permission(request.user, "openclose_thread", course_id)
} }
return render_to_response('discussion/index.html', context) return render_to_response('discussion/index.html', context)
......
import os
from django.conf import settings from django.conf import settings
from mako.template import Template from mako.template import Template
import os from discussion_app.views import get_template_dir as discussion_get_template_dir
def include_mustache_templates(): def include_mustache_templates():
mustache_dir = settings.PROJECT_ROOT / 'templates' / 'discussion' / 'mustache' mustache_dir = discussion_get_template_dir() + '/discussion/mustache'
def is_valid_file_name(file_name): def is_valid_file_name(file_name):
return file_name.endswith('.mustache') return file_name.endswith('.mustache')
......
...@@ -127,6 +127,34 @@ class LmsHandlerUrls(object): ...@@ -127,6 +127,34 @@ class LmsHandlerUrls(object):
return '//{}{}'.format(settings.SITE_NAME, path) return '//{}{}'.format(settings.SITE_NAME, path)
class LmsCourse(object):
"""
A runtime mixin that provides the course object.
This must be mixed in to a runtime that already accepts and stores
a course_id.
"""
@property
def course(self):
# TODO using 'modulestore().get_course(self._course_id)' doesn't work. return None
from courseware.courses import get_course
return get_course(self.course_id)
class LmsUser(object):
"""
A runtime mixin that provides the user object.
This must be mixed in to a runtime that already accepts and stores
a anonymous_student_id and has get_real_user method.
"""
@property
def user(self):
return self.get_real_user(self.anonymous_student_id)
class LmsPartitionService(PartitionService): class LmsPartitionService(PartitionService):
""" """
Another runtime mixin that provides access to the student partitions defined on the Another runtime mixin that provides access to the student partitions defined on the
...@@ -191,7 +219,7 @@ class UserTagsService(object): ...@@ -191,7 +219,7 @@ class UserTagsService(object):
) )
class LmsModuleSystem(LmsHandlerUrls, ModuleSystem): # pylint: disable=abstract-method class LmsModuleSystem(LmsHandlerUrls, LmsCourse, LmsUser, ModuleSystem): # pylint: disable=abstract-method
""" """
ModuleSystem specialized to the LMS ModuleSystem specialized to the LMS
""" """
......
...@@ -43,6 +43,11 @@ from xmodule.modulestore.modulestore_settings import update_module_store_setting ...@@ -43,6 +43,11 @@ from xmodule.modulestore.modulestore_settings import update_module_store_setting
from xmodule.mixin import LicenseMixin from xmodule.mixin import LicenseMixin
from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin from lms.djangoapps.lms_xblock.mixin import LmsBlockMixin
from discussion_app.views import (
get_js_urls as discussion_get_js_urls,
get_css_urls as discussion_get_css_urls
)
################################### FEATURES ################################### ################################### FEATURES ###################################
# The display name of the platform to be used in templates/emails/etc. # The display name of the platform to be used in templates/emails/etc.
PLATFORM_NAME = "Your Platform Name Here" PLATFORM_NAME = "Your Platform Name Here"
...@@ -1246,8 +1251,8 @@ dashboard_js = ( ...@@ -1246,8 +1251,8 @@ dashboard_js = (
sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/dashboard/**/*.js')) sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/dashboard/**/*.js'))
) )
dashboard_search_js = ['js/search/dashboard/main.js'] dashboard_search_js = ['js/search/dashboard/main.js']
discussion_js = sorted(rooted_glob(COMMON_ROOT / 'static', 'coffee/src/discussion/**/*.js'))
rwd_header_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/utils/rwd_header.js')) rwd_header_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'js/utils/rwd_header.js'))
discussion_js = discussion_get_js_urls()
staff_grading_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/staff_grading/**/*.js')) staff_grading_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/staff_grading/**/*.js'))
open_ended_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/open_ended/**/*.js')) open_ended_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/open_ended/**/*.js'))
notes_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/notes/**/*.js')) notes_js = sorted(rooted_glob(PROJECT_ROOT / 'static', 'coffee/src/notes/**/*.js'))
...@@ -1389,6 +1394,10 @@ PIPELINE_CSS = { ...@@ -1389,6 +1394,10 @@ PIPELINE_CSS = {
], ],
'output_filename': 'css/lms-main-rtl.css', 'output_filename': 'css/lms-main-rtl.css',
}, },
'style-discussion-app': {
'source_filenames': discussion_get_css_urls(),
'output_filename': 'css/lms-style-discussion-app.css',
},
'style-course-vendor': { 'style-course-vendor': {
'source_filenames': [ 'source_filenames': [
'js/vendor/CodeMirror/codemirror.css', 'js/vendor/CodeMirror/codemirror.css',
...@@ -1839,6 +1848,7 @@ INSTALLED_APPS = ( ...@@ -1839,6 +1848,7 @@ INSTALLED_APPS = (
'django_comment_common', 'django_comment_common',
'discussion_api', 'discussion_api',
'notes', 'notes',
'discussion_app',
'edxnotes', 'edxnotes',
......
...@@ -209,3 +209,40 @@ ...@@ -209,3 +209,40 @@
text-decoration: underline !important; text-decoration: underline !important;
} }
} }
%tooltip {
position: absolute;
top: 0;
left: 0;
z-index: 99999;
padding: 0 10px;
border-radius: 3px;
background: rgba(0, 0, 0, .85);
font-size: 11px;
font-weight: 400;
line-height: 26px;
color: #fff;
pointer-events: none;
opacity: 0;
@include transition(opacity .1s linear 0s);
&:after {
content: '▾';
display: block;
position: absolute;
bottom: -14px;
left: 50%;
margin-left: -7px;
font-size: 20px;
color: rgba(0, 0, 0, .85);
}
}
%loading-animation {
position: absolute;
left: 50%;
width: 20px;
height: 20px;
margin-left: -10px;
background: url(../images/spinner.gif) no-repeat;
}
// Discussion app styles
@import 'bourbon/bourbon';
// base - utilities
@import 'base/variables';
@import 'base/mixins';
@import 'base/extends';
// base - elements
@import 'elements/typography';
@import 'shared/modal';
@import 'discussion/discussion';
// forums - main app styling // forums - main app styling
// ==================== // ====================
body.discussion, .discussion-course {
body.discussion { // new post creation
.new-post-form-errors {
display: none;
background: $error-red;
padding: 0;
border: 1px solid $dark-gray;
list-style: none;
color: $white;
line-height: 1.6;
border-radius: 3px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3) inset, 0 1px 0 rgba(255, 255, 255, .2);
.course-tabs .right { li {
@include float(right); padding: ($baseline/2) $baseline 12px 45px;
border-bottom: 1px solid #dc4949;
background: url(../images/white-error-icon.png) no-repeat 15px 14px;
&:last-child {
border-bottom: none;
}
}
}
.course-tabs .right, .discussion-course-new.right {
float: right;
.new-post-btn { .new-post-btn {
@include blue-button; @include blue-button;
...@@ -110,7 +132,7 @@ body.discussion { ...@@ -110,7 +132,7 @@ body.discussion {
} }
.wmd-panel { .wmd-panel {
min-width: 500px; min-width: 425px;
width: 100%; width: 100%;
} }
...@@ -225,14 +247,28 @@ body.discussion { ...@@ -225,14 +247,28 @@ body.discussion {
} }
} }
.container .discussion-body { .container .discussion-body, .discussion-module, .discussion-course {
@include clearfix(); @include clearfix;
display: block; display: block;
border: none; border: none;
background: transparent; background: transparent;
box-shadow: none; box-shadow: none;
line-height: 1.4; line-height: 1.4;
.sidebar ul {
list-style: none !important;
margin: 0 !important;
padding-left: 0 !important;
}
.sr {
@extend %text-sr;
}
.wmd-panel textarea.wmd-input {
margin-bottom: 0px;
}
.bottom-post-status { .bottom-post-status {
padding: 30px; padding: 30px;
font-size: 20px; font-size: 20px;
......
...@@ -44,8 +44,6 @@ ${page_title_breadcrumbs(course_name())} ...@@ -44,8 +44,6 @@ ${page_title_breadcrumbs(course_name())}
<%block name="nav_skip">${"#seq_content" if section_title else "#course-content"}</%block> <%block name="nav_skip">${"#seq_content" if section_title else "#course-content"}</%block>
<%include file="../discussion/_js_head_dependencies.html" />
% if show_chat: % if show_chat:
<link rel="stylesheet" href="${static.url('css/vendor/ui-lightness/jquery-ui-1.8.22.custom.css')}" /> <link rel="stylesheet" href="${static.url('css/vendor/ui-lightness/jquery-ui-1.8.22.custom.css')}" />
## It'd be better to have this in a place like lms/css/vendor/candy, ## It'd be better to have this in a place like lms/css/vendor/candy,
......
...@@ -14,12 +14,10 @@ from django.core.urlresolvers import reverse ...@@ -14,12 +14,10 @@ from django.core.urlresolvers import reverse
<%block name="headextra"> <%block name="headextra">
<%static:css group='style-course-vendor'/> <%static:css group='style-course-vendor'/>
<%static:css group='style-course'/> <%static:css group='style-course'/>
<%include file="_js_head_dependencies.html" />
</%block> </%block>
<%block name="js_extra"> <%block name="js_extra">
<%include file="_js_body_dependencies.html" /> <%include file="/discussion/_js_body_dependencies.html" />
<%static:js group='discussion'/> <%static:js group='discussion'/>
</%block> </%block>
...@@ -47,3 +45,5 @@ from django.core.urlresolvers import reverse ...@@ -47,3 +45,5 @@ from django.core.urlresolvers import reverse
<%include file="_underscore_templates.html" /> <%include file="_underscore_templates.html" />
<%include file="_thread_list_template.html" /> <%include file="_thread_list_template.html" />
<%include file="/discussion/_discussion_course.html" />
...@@ -11,12 +11,10 @@ from django.template.defaultfilters import escapejs ...@@ -11,12 +11,10 @@ from django.template.defaultfilters import escapejs
<%block name="headextra"> <%block name="headextra">
<%static:css group='style-course-vendor'/> <%static:css group='style-course-vendor'/>
<%static:css group='style-course'/> <%static:css group='style-course'/>
<%include file="_js_head_dependencies.html" />
</%block> </%block>
<%block name="js_extra"> <%block name="js_extra">
<%include file="_js_body_dependencies.html" /> <%include file="/discussion/_js_body_dependencies.html" />
<%static:js group='discussion'/> <%static:js group='discussion'/>
</%block> </%block>
...@@ -28,7 +26,7 @@ from django.template.defaultfilters import escapejs ...@@ -28,7 +26,7 @@ from django.template.defaultfilters import escapejs
<nav aria-label="${_('User Profile')}"> <nav aria-label="${_('User Profile')}">
<article class="sidebar-module discussion-sidebar"> <article class="sidebar-module discussion-sidebar">
<%include file="_user_profile.html" /> <%include file="/discussion/_user_profile.html" />
</article> </article>
</nav> </nav>
...@@ -38,4 +36,4 @@ from django.template.defaultfilters import escapejs ...@@ -38,4 +36,4 @@ from django.template.defaultfilters import escapejs
</div> </div>
</section> </section>
<%include file="_underscore_templates.html" /> <%include file="/discussion/_underscore_templates.html" />
...@@ -63,6 +63,10 @@ from branding import api as branding_api ...@@ -63,6 +63,10 @@ from branding import api as branding_api
<%static:css group='style-vendor'/> <%static:css group='style-vendor'/>
<%static:css group='style-main'/> <%static:css group='style-main'/>
<%static:css group='style-app'/>
<%static:css group='style-app-extend1'/>
<%static:css group='style-app-extend2'/>
<%static:css group='style-discussion-app'/>
% if disable_courseware_js: % if disable_courseware_js:
<%static:js group='base_vendor'/> <%static:js group='base_vendor'/>
...@@ -157,6 +161,17 @@ from branding import api as branding_api ...@@ -157,6 +161,17 @@ from branding import api as branding_api
% endif % endif
% if not disable_window_wrap: % if not disable_window_wrap:
<body class="<%block name='bodyclass'/> lang_${LANGUAGE_CODE}">
<a class="nav-skip" href="<%block name="nav_skip">#content</%block>">${_("Skip to this view's content")}</a>
<%include file="mathjax_include.html" />
<%include file="mathjax_accessible.html" />
<%include file="${header_file}" />
<div class="content-wrapper" id="content">
${self.body()}
<%block name="bodyextra"/>
</div> </div>
% endif % endif
...@@ -167,8 +182,6 @@ from branding import api as branding_api ...@@ -167,8 +182,6 @@ from branding import api as branding_api
<%block name="js_extra"/> <%block name="js_extra"/>
<script type="text/javascript" src="${static.url('js/vendor/noreferrer.js')}" charset="utf-8"></script> <script type="text/javascript" src="${static.url('js/vendor/noreferrer.js')}" charset="utf-8"></script>
</body>
</html>
<%def name="login_query()">${ <%def name="login_query()">${
u"?next={0}".format(urlquote_plus(login_redirect_url)) if login_redirect_url else "" u"?next={0}".format(urlquote_plus(login_redirect_url)) if login_redirect_url else ""
...@@ -203,3 +216,5 @@ from branding import api as branding_api ...@@ -203,3 +216,5 @@ from branding import api as branding_api
}()); }());
</script> </script>
% endif % endif
</body>
</html>
\ No newline at end of file
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
{% compressed_css 'style-main' %} {% compressed_css 'style-main' %}
{% compressed_css 'style-course-vendor' %} {% compressed_css 'style-course-vendor' %}
{% compressed_css 'style-course' %} {% compressed_css 'style-course' %}
{% compressed_css 'style-discussion-app' %}
{% block main_vendor_js %} {% block main_vendor_js %}
{% compressed_js 'main_vendor' %} {% compressed_js 'main_vendor' %}
...@@ -52,6 +53,7 @@ ...@@ -52,6 +53,7 @@
{% compressed_js 'application' %} {% compressed_js 'application' %}
{% compressed_js 'module-js' %} {% compressed_js 'module-js' %}
{% include "mathjax_include.html" %}
{% render_block "js" %} {% render_block "js" %}
</body> </body>
......
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