diff --git a/common/test/acceptance/tests/discussion/test_discussion.py b/common/test/acceptance/tests/discussion/test_discussion.py
index 9f200ecd8f..0bc146166d 100644
--- a/common/test/acceptance/tests/discussion/test_discussion.py
+++ b/common/test/acceptance/tests/discussion/test_discussion.py
@@ -1037,7 +1037,7 @@ class DiscussionUserProfileTest(UniqueCourseTest):
Tests for user profile page in discussion tab.
"""
- PAGE_SIZE = 20 # django_comment_client.forum.views.THREADS_PER_PAGE
+ PAGE_SIZE = 20 # discussion.views.THREADS_PER_PAGE
PROFILED_USERNAME = "profiled-user"
def setUp(self):
diff --git a/lms/djangoapps/courseware/tests/test_tabs.py b/lms/djangoapps/courseware/tests/test_tabs.py
index 692b5311fa..2f814bb746 100644
--- a/lms/djangoapps/courseware/tests/test_tabs.py
+++ b/lms/djangoapps/courseware/tests/test_tabs.py
@@ -754,7 +754,7 @@ class DiscussionLinkTestCase(TabTestCase):
"""Custom reverse function"""
def reverse_discussion_link(viewname, args):
"""reverse lookup for discussion link"""
- if viewname == "django_comment_client.forum.views.forum_form_discussion" and args == [unicode(course.id)]:
+ if viewname == "discussion.views.forum_form_discussion" and args == [unicode(course.id)]:
return "default_discussion_link"
return reverse_discussion_link
diff --git a/lms/djangoapps/django_comment_client/forum/__init__.py b/lms/djangoapps/discussion/__init__.py
similarity index 100%
rename from lms/djangoapps/django_comment_client/forum/__init__.py
rename to lms/djangoapps/discussion/__init__.py
diff --git a/lms/djangoapps/discussion/plugins.py b/lms/djangoapps/discussion/plugins.py
new file mode 100644
index 0000000000..50e5d830b5
--- /dev/null
+++ b/lms/djangoapps/discussion/plugins.py
@@ -0,0 +1,28 @@
+"""
+Views handling read (GET) requests for the Discussion tab and inline discussions.
+"""
+
+from django.conf import settings
+from django.utils.translation import ugettext_noop
+
+from courseware.tabs import EnrolledTab
+import django_comment_client.utils as utils
+
+
+class DiscussionTab(EnrolledTab):
+ """
+ A tab for the cs_comments_service forums.
+ """
+
+ type = 'discussion'
+ title = ugettext_noop('Discussion')
+ priority = None
+ view_name = 'discussion.views.forum_form_discussion'
+ is_hideable = settings.FEATURES.get('ALLOW_HIDING_DISCUSSION_TAB', False)
+ is_default = False
+
+ @classmethod
+ def is_enabled(cls, course, user=None):
+ if not super(DiscussionTab, cls).is_enabled(course, user):
+ return False
+ return utils.is_discussion_enabled(course.id)
diff --git a/lms/djangoapps/discussion/static/discussion/js/discussion_board_factory.js b/lms/djangoapps/discussion/static/discussion/js/discussion_board_factory.js
new file mode 100644
index 0000000000..66e45b005a
--- /dev/null
+++ b/lms/djangoapps/discussion/static/discussion/js/discussion_board_factory.js
@@ -0,0 +1,36 @@
+;(function(define) {
+ 'use strict';
+
+ define(['jquery', 'backbone'],
+ function($, Backbone) {
+ return function(options) {
+ var element = options.el,
+ userInfo = element.data('user-info'),
+ sortPreference = element.data('sort-preference'),
+ threads = element.data('threads'),
+ threadPages = element.data('thread-pages'),
+ contentInfo = element.data('content-info'),
+ user = new window.DiscussionUser(userInfo),
+ discussion,
+ courseSettings;
+ // TODO: Perhaps eliminate usage of global variables when possible
+ window.DiscussionUtil.loadRolesFromContainer();
+ window.$$course_id = options.courseId;
+ window.courseName = element.data('course-name');
+ window.DiscussionUtil.setUser(user);
+ window.user = user;
+ window.Content.loadContentInfos(contentInfo);
+ discussion = new window.Discussion(threads, {pages: threadPages, sort: sortPreference});
+ courseSettings = new window.DiscussionCourseSettings(element.data('course-settings'));
+ // jshint nonew:false
+ new window.DiscussionRouter({
+ discussion: discussion,
+ course_settings: courseSettings
+ });
+ Backbone.history.start({
+ pushState: true,
+ root: '/courses/' + options.courseId + '/discussion/forum/'
+ });
+ };
+ });
+}).call(this, define || RequireJS.define);
diff --git a/lms/djangoapps/discussion/static/discussion/js/discussion_profile_page_factory.js b/lms/djangoapps/discussion/static/discussion/js/discussion_profile_page_factory.js
new file mode 100644
index 0000000000..79e3ad4b85
--- /dev/null
+++ b/lms/djangoapps/discussion/static/discussion/js/discussion_profile_page_factory.js
@@ -0,0 +1,29 @@
+;(function(define) {
+ 'use strict';
+
+ define(['jquery', 'DiscussionUserProfileView'],
+ function($, DiscussionUserProfileView) {
+ return function(options) {
+ var element = options.el,
+ threads = element.data('threads'),
+ userInfo = element.data('user-info'),
+ page = element.data('page'),
+ numPages = element.data('num-pages');
+ // Roles are not included in user profile page, but they are not used for anything
+ window.DiscussionUtil.loadRoles({
+ 'Moderator': [],
+ 'Administrator': [],
+ 'Community TA': []
+ });
+ window.$$course_id = element.data('course-id');
+ window.user = new window.DiscussionUser(userInfo);
+ // jshint nonew:false
+ new DiscussionUserProfileView({
+ el: element,
+ collection: threads,
+ page: page,
+ numPages: numPages
+ });
+ };
+ });
+}).call(this, define || RequireJS.define);
diff --git a/common/static/common/js/discussion/discussion_router.js b/lms/djangoapps/discussion/static/discussion/js/discussion_router.js
similarity index 100%
rename from common/static/common/js/discussion/discussion_router.js
rename to lms/djangoapps/discussion/static/discussion/js/discussion_router.js
diff --git a/common/static/common/js/spec/discussion/view/discussion_user_profile_view_spec.js b/lms/djangoapps/discussion/static/discussion/js/spec/views/discussion_user_profile_view_spec.js
similarity index 100%
rename from common/static/common/js/spec/discussion/view/discussion_user_profile_view_spec.js
rename to lms/djangoapps/discussion/static/discussion/js/spec/views/discussion_user_profile_view_spec.js
diff --git a/common/static/common/js/discussion/views/discussion_user_profile_view.js b/lms/djangoapps/discussion/static/discussion/js/views/discussion_user_profile_view.js
similarity index 100%
rename from common/static/common/js/discussion/views/discussion_user_profile_view.js
rename to lms/djangoapps/discussion/static/discussion/js/views/discussion_user_profile_view.js
diff --git a/lms/templates/discussion/index.html b/lms/djangoapps/discussion/templates/discussion/discussion_board.html
similarity index 69%
rename from lms/templates/discussion/index.html
rename to lms/djangoapps/discussion/templates/discussion/discussion_board.html
index 6e0ca8e363..9d44984873 100644
--- a/lms/templates/discussion/index.html
+++ b/lms/djangoapps/discussion/templates/discussion/discussion_board.html
@@ -9,25 +9,38 @@
from django.utils.translation import ugettext as _
from django.template.defaultfilters import escapejs
from django.core.urlresolvers import reverse
+from openedx.core.djangolib.js_utils import (
+ dump_js_escaped_json, js_escaped_string
+)
%>
<%block name="bodyclass">discussion%block>
<%block name="pagetitle">${_("Discussion - {course_number}").format(course_number=course.display_number_with_default)}%block>
<%block name="headextra">
-<%include file="_js_head_dependencies.html" />
+<%include file="../discussion/_js_head_dependencies.html" />
%block>
<%block name="js_extra">
## Enable fast preview to fix discussion MathJax rendering bug when page first loads.
-<%include file="_js_body_dependencies.html" args="disable_fast_preview=False"/>
+<%include file="/discussion/_js_body_dependencies.html" args="disable_fast_preview=False"/>
<%static:js group='discussion'/>
+
+
+<%static:require_module module_name="discussion/js/discussion_board_factory" class_name="DiscussionBoardFactory">
+ DiscussionBoardFactory({
+ courseId: '${unicode(course.id) | n, js_escaped_string}',
+ el: $(".discussion-board")
+ });
+%static:require_module>
%block>
-<%include file="_discussion_course_navigation.html" args="active_page='discussion'" />
+<%include file="/discussion/_discussion_course_navigation.html" args="active_page='discussion'" />
<%block name="content">
-
+
+<%page expression_filter="h"/>
+<%inherit file="../main.html" />
+<%namespace name='static' file='../static_content.html'/>
+<%!
+from django.utils.translation import ugettext as _
+from django.template.defaultfilters import escapejs
+from openedx.core.djangolib.js_utils import (
+ dump_js_escaped_json, js_escaped_string
+)
+%>
+
+<%block name="bodyclass">discussion-user-profile%block>
+<%block name="pagetitle">${_("Discussion - {course_number}").format(course_number=course.display_number_with_default)}%block>
+
+<%block name="headextra">
+<%include file="_js_head_dependencies.html" />
+%block>
+
+<%block name="js_extra">
+<%include file="_js_body_dependencies.html" />
+<%static:js group='discussion'/>
+
+
+<%static:require_module module_name="discussion/js/discussion_profile_page_factory" class_name="DiscussionProfilePageFactory">
+ DiscussionProfilePageFactory({
+ courseId: '${unicode(course.id) | n, js_escaped_string}',
+ el: $(".discussion-user-threads")
+ });
+%static:require_module>
+%block>
+
+<%include file="../courseware/course_navigation.html" args="active_page='discussion'" />
+
+
+
+<%include file="_underscore_templates.html" />
diff --git a/lms/djangoapps/django_comment_client/forum/tests.py b/lms/djangoapps/discussion/tests/test_views.py
similarity index 99%
rename from lms/djangoapps/django_comment_client/forum/tests.py
rename to lms/djangoapps/discussion/tests/test_views.py
index de82c41f0b..69a76bdc90 100644
--- a/lms/djangoapps/django_comment_client/forum/tests.py
+++ b/lms/djangoapps/discussion/tests/test_views.py
@@ -10,7 +10,6 @@ from django.utils import translation
from lms.lib.comment_client.utils import CommentClientPaginatedResult
from django_comment_common.utils import ThreadContext
-from django_comment_client.forum import views
from django_comment_client.permissions import get_team
from django_comment_client.tests.group_id import (
CohortedTopicGroupIdTestMixin,
@@ -19,6 +18,7 @@ from django_comment_client.tests.group_id import (
from django_comment_client.tests.unicode import UnicodeTestMixin
from django_comment_client.tests.utils import CohortedTestCase
from django_comment_client.utils import strip_none
+from lms.djangoapps.discussion import views
from student.tests.factories import UserFactory, CourseEnrollmentFactory
from util.testing import UrlResetMixin
from openedx.core.djangoapps.util.testing import ContentGroupTestCase
@@ -87,7 +87,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase):
# that gets the current user's info
mock_from_django_user.return_value = Mock()
- url = reverse('django_comment_client.forum.views.user_profile',
+ url = reverse('discussion.views.user_profile',
kwargs={'course_id': self.course.id.to_deprecated_string(), 'user_id': '12345'}) # There is no user 12345
self.response = self.client.get(url)
self.assertEqual(self.response.status_code, 404)
@@ -104,7 +104,7 @@ class ViewsExceptionTestCase(UrlResetMixin, ModuleStoreTestCase):
# that gets the current user's info
mock_from_django_user.return_value = Mock()
- url = reverse('django_comment_client.forum.views.followed_threads',
+ url = reverse('discussion.views.followed_threads',
kwargs={'course_id': self.course.id.to_deprecated_string(), 'user_id': '12345'}) # There is no user 12345
self.response = self.client.get(url)
self.assertEqual(self.response.status_code, 404)
@@ -1257,7 +1257,7 @@ class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase):
self.client.get(
reverse(
- "django_comment_client.forum.views.single_thread",
+ "discussion.views.single_thread",
kwargs={
"course_id": self.course.id.to_deprecated_string(),
"discussion_id": "dummy_discussion_id",
@@ -1274,7 +1274,7 @@ class CommentsServiceRequestHeadersTestCase(UrlResetMixin, ModuleStoreTestCase):
self.client.get(
reverse(
- "django_comment_client.forum.views.forum_form_discussion",
+ "discussion.views.forum_form_discussion",
kwargs={"course_id": self.course.id.to_deprecated_string()}
),
)
@@ -1361,7 +1361,7 @@ class ForumDiscussionXSSTestCase(UrlResetMixin, ModuleStoreTestCase):
Test that XSS attack is prevented
"""
reverse_url = "%s%s" % (reverse(
- "django_comment_client.forum.views.forum_form_discussion",
+ "discussion.views.forum_form_discussion",
kwargs={"course_id": unicode(self.course.id)}), '/forum_form_discussion')
# Test that malicious code does not appear in html
url = "%s?%s=%s" % (reverse_url, 'sort_key', malicious_code)
@@ -1380,7 +1380,7 @@ class ForumDiscussionXSSTestCase(UrlResetMixin, ModuleStoreTestCase):
mock_from_django_user.return_value = Mock()
mock_request.side_effect = make_mock_request_impl(course=self.course, text='dummy')
- url = reverse('django_comment_client.forum.views.user_profile',
+ url = reverse('discussion.views.user_profile',
kwargs={'course_id': unicode(self.course.id), 'user_id': str(self.student.id)})
# Test that malicious code does not appear in html
url_string = "%s?%s=%s" % (url, 'page', malicious_code)
diff --git a/lms/djangoapps/django_comment_client/forum/urls.py b/lms/djangoapps/discussion/urls.py
similarity index 93%
rename from lms/djangoapps/django_comment_client/forum/urls.py
rename to lms/djangoapps/discussion/urls.py
index 7064858ed5..4c7939866c 100644
--- a/lms/djangoapps/django_comment_client/forum/urls.py
+++ b/lms/djangoapps/discussion/urls.py
@@ -4,7 +4,7 @@ Forum urls for the django_comment_client.
from django.conf.urls import url, patterns
urlpatterns = patterns(
- 'django_comment_client.forum.views',
+ 'discussion.views',
url(r'users/(?P\w+)/followed$', 'followed_threads', name='followed_threads'),
url(r'users/(?P\w+)$', 'user_profile', name='user_profile'),
diff --git a/lms/djangoapps/django_comment_client/forum/views.py b/lms/djangoapps/discussion/views.py
similarity index 95%
rename from lms/djangoapps/django_comment_client/forum/views.py
rename to lms/djangoapps/discussion/views.py
index 2ba8f558a9..2de4d10541 100644
--- a/lms/djangoapps/django_comment_client/forum/views.py
+++ b/lms/djangoapps/discussion/views.py
@@ -7,23 +7,20 @@ import json
import logging
from django.contrib.auth.decorators import login_required
-from django.conf import settings
from django.core.context_processors import csrf
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.http import Http404, HttpResponseBadRequest
-from django.utils.translation import ugettext_noop
+from django.shortcuts import render_to_response
from django.views.decorators.http import require_GET
import newrelic.agent
-from edxmako.shortcuts import render_to_response
from courseware.courses import get_course_with_access
from openedx.core.djangoapps.course_groups.cohorts import (
is_course_cohorted,
get_cohort_id,
get_course_cohorts,
)
-from courseware.tabs import EnrolledTab
from courseware.access import has_access
from xmodule.modulestore.django import modulestore
@@ -48,25 +45,6 @@ PAGES_NEARBY_DELTA = 2
log = logging.getLogger("edx.discussions")
-class DiscussionTab(EnrolledTab):
- """
- A tab for the cs_comments_service forums.
- """
-
- type = 'discussion'
- title = ugettext_noop('Discussion')
- priority = None
- view_name = 'django_comment_client.forum.views.forum_form_discussion'
- is_hideable = settings.FEATURES.get('ALLOW_HIDING_DISCUSSION_TAB', False)
- is_default = False
-
- @classmethod
- def is_enabled(cls, course, user=None):
- if not super(DiscussionTab, cls).is_enabled(course, user):
- return False
- return utils.is_discussion_enabled(course.id)
-
-
@newrelic.agent.function_trace()
def make_course_settings(course, user):
"""
@@ -115,7 +93,8 @@ def get_threads(request, course, discussion_id=None, per_page=THREADS_PER_PAGE):
# If the user did not select a sort key, use their last used sort key
cc_user = cc.User.from_django_user(request.user)
cc_user.retrieve()
- # TODO: After the comment service is updated this can just be user.default_sort_key because the service returns the default value
+ # TODO: After the comment service is updated this can just be
+ # user.default_sort_key because the service returns the default value
default_query_params['sort_key'] = cc_user.get('default_sort_key') or default_query_params['sort_key']
else:
# If the user clicked a sort key, update their default sort key
@@ -239,7 +218,10 @@ def forum_form_discussion(request, course_key):
threads = [utils.prepare_content(thread, course_key, is_staff) for thread in unsafethreads]
except cc.utils.CommentClientMaintenanceError:
log.warning("Forum is in maintenance mode")
- return render_to_response('discussion/maintenance.html', {})
+ return render_to_response('discussion/maintenance.html', {
+ 'disable_courseware_js': True,
+ 'uses_pattern_library': True,
+ })
except ValueError:
return HttpResponseBadRequest("Invalid group_id")
@@ -290,7 +272,7 @@ def forum_form_discussion(request, course_key):
'uses_pattern_library': True,
}
# print "start rendering.."
- return render_to_response('discussion/index.html', context)
+ return render_to_response('discussion/discussion_board.html', context)
@require_GET
@@ -318,8 +300,8 @@ def single_thread(request, course_key, discussion_id, thread_id):
response_skip=request.GET.get("resp_skip"),
response_limit=request.GET.get("resp_limit")
)
- except cc.utils.CommentClientRequestError as e:
- if e.status_code == 404:
+ except cc.utils.CommentClientRequestError as error:
+ if error.status_code == 404:
raise Http404
raise
@@ -404,7 +386,7 @@ def single_thread(request, course_key, discussion_id, thread_id):
'disable_courseware_js': True,
'uses_pattern_library': True,
}
- return render_to_response('discussion/index.html', context)
+ return render_to_response('discussion/discussion_board.html', context)
@require_GET
@@ -465,7 +447,9 @@ def user_profile(request, course_key, user_id):
'annotated_content_info': json.dumps(annotated_content_info),
'page': query_params['page'],
'num_pages': query_params['num_pages'],
- 'learner_profile_page_url': reverse('learner_profile', kwargs={'username': django_user.username})
+ 'learner_profile_page_url': reverse('learner_profile', kwargs={'username': django_user.username}),
+ 'disable_courseware_js': True,
+ 'uses_pattern_library': True,
}
return render_to_response('discussion/user_profile.html', context)
diff --git a/lms/djangoapps/django_comment_client/urls.py b/lms/djangoapps/django_comment_client/urls.py
index 03e18b38c2..d2972b4c79 100644
--- a/lms/djangoapps/django_comment_client/urls.py
+++ b/lms/djangoapps/django_comment_client/urls.py
@@ -6,6 +6,5 @@ from django.conf.urls import url, patterns, include
urlpatterns = patterns(
'',
- url(r'forum/?', include('django_comment_client.forum.urls')),
url(r'', include('django_comment_client.base.urls')),
)
diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py
index e713ce05e3..43172f8e58 100644
--- a/lms/djangoapps/django_comment_client/utils.py
+++ b/lms/djangoapps/django_comment_client/utils.py
@@ -591,10 +591,10 @@ def permalink(content):
else:
course_id = content['course_id']
if content['type'] == 'thread':
- return reverse('django_comment_client.forum.views.single_thread',
+ return reverse('discussion.views.single_thread',
args=[course_id, content['commentable_id'], content['id']])
else:
- return reverse('django_comment_client.forum.views.single_thread',
+ return reverse('discussion.views.single_thread',
args=[course_id, content['commentable_id'], content['thread_id']]) + '#' + content['id']
diff --git a/lms/envs/common.py b/lms/envs/common.py
index 7d801363b0..3b380aa83c 100644
--- a/lms/envs/common.py
+++ b/lms/envs/common.py
@@ -1941,8 +1941,10 @@ INSTALLED_APPS = (
'django_comment_client',
'django_comment_common',
'discussion_api',
- 'notes',
+ 'lms.djangoapps.discussion',
+ # Notes
+ 'notes',
'edxnotes',
# Splash screen
diff --git a/lms/static/lms/js/build.js b/lms/static/lms/js/build.js
index c774837178..0da320d920 100644
--- a/lms/static/lms/js/build.js
+++ b/lms/static/lms/js/build.js
@@ -18,6 +18,7 @@
* done.
*/
modules: getModulesList([
+ 'discussion/js/discussion_board_factory',
'js/api_admin/catalog_preview_factory',
'js/courseware/courseware_factory',
'js/discovery/discovery_factory',
diff --git a/lms/static/sass/discussion/_build.scss b/lms/static/sass/discussion/_build.scss
index f04d7faf40..288f4ff0c7 100644
--- a/lms/static/sass/discussion/_build.scss
+++ b/lms/static/sass/discussion/_build.scss
@@ -27,6 +27,7 @@ $static-path: '../..' !default;
// Discussion styling
@import 'mixins';
@import 'discussion'; // Process old file after definitions but before everything else, partial is deprecated.
+@import 'layouts';
@import 'elements/actions';
@import 'elements/editor';
@import 'elements/labels';
diff --git a/lms/static/sass/discussion/_discussion.scss b/lms/static/sass/discussion/_discussion.scss
index 67a0e99127..88b01dd076 100644
--- a/lms/static/sass/discussion/_discussion.scss
+++ b/lms/static/sass/discussion/_discussion.scss
@@ -4,10 +4,6 @@
body.discussion {
- .course-tabs .right {
- @include float(right);
- }
-
.edit-post-form {
@include clearfix();
box-sizing: border-box;
@@ -65,39 +61,6 @@ body.discussion {
font-size: 21px;
}
- section.user-profile {
- // TODO: don't use table-cell for layout purposes as it switches the screenreader mode
- display: table-cell;
- border-right: 1px solid #ddd;
- border-radius: 3px 0 0 3px;
- background-color: $sidebar-color;
- box-shadow: none;
-
- .user-profile {
- padding: 32px 36px;
- }
-
- .sidebar-username {
- font-weight: 700;
- font-size: 18px;
- }
-
- .sidebar-user-roles {
- margin-top: 6px;
- font-style: italic;
- font-size: 13px;
- }
-
- .sidebar-threads-count {
- margin-top: 14px;
- }
-
- .sidebar-threads-count span,
- .sidebar-comments-count span {
- font-weight: 700;
- }
- }
-
.wmd-panel {
width: 100%;
}
@@ -227,16 +190,6 @@ body.discussion {
text-align: center;
}
- .discussion-column {
- @include float(right);
- box-sizing: border-box;
- padding-left: ($baseline/2);
- width: 68%;
- max-width: 800px;
- min-height: 500px;
- border-radius: 3px;
- }
-
.discussion-article {
position: relative;
min-height: 500px;
@@ -406,108 +359,6 @@ body.discussion {
.threads {
}
-
- .discussion-thread {
- padding: 0;
- margin-bottom: $baseline;
- @include transition(all .25s linear 0s);
-
- p {
- margin-bottom: 0;
- }
-
- .discussion-article {
- @include transition(all .2s linear 0s);
- border: 1px solid $forum-color-border;
- border-radius: 3px;
- min-height: 0;
- background: $forum-color-background;
- box-shadow: 0 1px 0 $shadow;
- @include transition(all .2s linear 0s);
-
- .thread-wrapper {
- @include border-radius(3px, 3px, 0, 0);
- position: relative;
- overflow-x: hidden;
- overflow-y: auto;
- max-height: 600px;
- background-color: $forum-color-background;
-
- .discussion-post {
-
- .inline-comment-count {
- @extend %ui-depth2;
- position: relative;
- float: right;
- display: block;
- height: 27px;
- margin-top: 6px;
- margin-right: 8px;
- padding: 0 8px;
- border-radius: ($baseline/4);
- font-size: 12px;
- font-weight: 400;
- line-height: 25px;
- color: #888;
- }
- }
-
- .responses {
- header {
- padding-bottom: 0;
- margin-bottom: ($baseline*0.75);
-
- .posted-by {
- float: left;
- margin-right: ($baseline/4);
- font-size: 16px;
- }
- }
-
- .response-body {
- margin-bottom: 0.2em;
- font-size: 14px;
- }
- }
-
- .discussion-reply-new {
- .wmd-input {
- height: 120px;
- }
- }
-
- // Content that is hidden by default in the inline view
- .post-extended-content{
- display: none;
- }
- }
-
- .post-tools {
- box-shadow: 0 1px 1px $shadow inset;
- background: $gray-l6;
-
- &:hover {
- background: #fcfcfc;
-
- .icon {
- color: $link-hover;
- }
- }
-
- a {
- display: block;
- padding: ($baseline*0.25) $baseline;
- font-size: 12px;
- line-height: 30px;
-
- .icon {
- color: $link-color;
- margin-right: ($baseline*0.25);
- }
- }
- }
- }
- }
}
.new-post-article {
@@ -603,14 +454,6 @@ body.discussion {
}
}
-.discussion-user-threads {
- @extend .discussion-module;
-
- .discussion-post {
- padding-bottom: $baseline !important;
- }
-}
-
.xblock-student_view-discussion {
@extend %ui-print-excluded;
}
diff --git a/lms/static/sass/discussion/_layouts.scss b/lms/static/sass/discussion/_layouts.scss
new file mode 100644
index 0000000000..016ee2c442
--- /dev/null
+++ b/lms/static/sass/discussion/_layouts.scss
@@ -0,0 +1,40 @@
+// Layouts for discussion pages
+
+section.user-profile {
+ background-color: $sidebar-color;
+
+ .user-profile {
+ padding: 32px 36px;
+ min-height: 500px;
+ }
+
+ .sidebar-username {
+ font-weight: 700;
+ font-size: 18px;
+ }
+
+ .sidebar-user-roles {
+ margin-top: 6px;
+ font-style: italic;
+ font-size: 13px;
+ }
+
+ .sidebar-threads-count {
+ margin-top: 14px;
+ }
+
+ .sidebar-threads-count span,
+ .sidebar-comments-count span {
+ font-weight: 700;
+ }
+}
+
+.discussion-column {
+ @include float(right);
+ box-sizing: border-box;
+ padding-left: ($baseline/2);
+ width: 68%;
+ max-width: 800px;
+ min-height: 500px;
+ border-radius: 3px;
+}
diff --git a/lms/static/sass/discussion/views/_thread.scss b/lms/static/sass/discussion/views/_thread.scss
index c552894829..8ab2ffc6fb 100644
--- a/lms/static/sass/discussion/views/_thread.scss
+++ b/lms/static/sass/discussion/views/_thread.scss
@@ -9,136 +9,132 @@
// * +post - individual element styling
// * +post - answered question - collapsed comment area
-// +general thread layout
-body.discussion, .discussion-module {
-
- // post layout
- .discussion-post {
+// post layout
+.discussion-post {
padding: 0 ($baseline/2);
.wrapper-post-header {
- padding-bottom: 0;
- margin-bottom: ($baseline*0.75);
+ padding-bottom: 0;
+ margin-bottom: ($baseline*0.75);
}
.post-header-content {
- display: inline-block;
- width: flex-grid(9,12);
+ display: inline-block;
+ width: flex-grid(9,12);
}
.post-header-actions {
- @include float(right);
+ @include float(right);
}
.post-body {
- width: flex-grid(10,12);
+ width: flex-grid(10,12);
}
- }
+}
- .posted-details {
+.posted-details {
@extend %t-copy-sub2;
margin-top: ($baseline/5);
color: $gray-d1;
.username {
- @extend %t-strong;
- display: inline;
+ @extend %t-strong;
+ display: inline;
}
.timeago, .top-post-status {
- color: inherit;
+ color: inherit;
}
- }
+}
- // response layout
- .discussion-response {
+// response layout
+.discussion-response {
min-height: ($baseline*5);
.response-header-content {
- display: inline-block;
- vertical-align: top;
- width: flex-grid(11,12);
+ display: inline-block;
+ vertical-align: top;
+ width: flex-grid(11,12);
}
.response-header-actions {
- @include float(right);
- @include right($baseline);
- position: absolute;
- top: $baseline;
+ @include float(right);
+ @include right($baseline);
+ position: absolute;
+ top: $baseline;
}
- }
+}
- // comments layout
- .discussion-comment {
+// comments layout
+.discussion-comment {
.response-body {
- @extend %t-copy-sub2;
- display: inline-block;
- margin-bottom: ($baseline/2);
- width: flex-grid(10,12);
+ @extend %t-copy-sub2;
+ display: inline-block;
+ margin-bottom: ($baseline/2);
+ width: flex-grid(10,12);
- p + p {
- margin-top: 12px;
- }
+ p + p {
+ margin-top: 12px;
+ }
}
.comment-actions-list {
- @include float(right);
+ @include float(right);
}
- }
}
// +thread - wrapper styling
.thread-wrapper {
- .thread-main-wrapper {
- padding-bottom: $baseline;
- }
+ .thread-main-wrapper {
+ padding-bottom: $baseline;
+ }
}
// +thread - elements - shared styles
body.discussion {
- .discussion-post, .discussion-response, .discussion-comment {
- @include clearfix();
+ .discussion-post, .discussion-response, .discussion-comment {
+ @include clearfix();
- // thread - images
- .author-image {
- @include margin-right($baseline/2);
- display: inline-block;
- vertical-align: top;
+ // thread - images
+ .author-image {
+ @include margin-right($baseline/2);
+ display: inline-block;
+ vertical-align: top;
- // STATE: No profile image
- &:empty {
- display: none;
- }
+ // STATE: No profile image
+ &:empty {
+ display: none;
+ }
- // CASE: post image
- &.level-post {
- height: $post-image-dimension;
- width: $post-image-dimension;
- }
+ // CASE: post image
+ &.level-post {
+ height: $post-image-dimension;
+ width: $post-image-dimension;
+ }
- // CASE: response image
- &.level-response {
- height: $response-image-dimension;
- width: $response-image-dimension;
- }
+ // CASE: response image
+ &.level-response {
+ height: $response-image-dimension;
+ width: $response-image-dimension;
+ }
- // CASE: comment image
- &.level-comment {
- height: $comment-image-dimension;
- width: $comment-image-dimension;
- }
+ // CASE: comment image
+ &.level-comment {
+ height: $comment-image-dimension;
+ width: $comment-image-dimension;
+ }
- img {
- border-radius: 3px;
- }
+ img {
+ border-radius: 3px;
+ }
+ }
}
- }
- .discussion-response .response-body {
- @include padding-right($baseline); //ensures content doesn't overlap on post or response actions.
- }
+ .discussion-response .response-body {
+ @include padding-right($baseline); //ensures content doesn't overlap on post or response actions.
+ }
}
// +post - individual element styling
@@ -146,62 +142,170 @@ body.discussion .discussion-post,
body.discussion .discussion-article,
body.view-in-course .discussion-post,
body.view-in-course .discussion-article {
- // NOTE: discussion-article is used for inline discussion modules.
- @include clearfix();
+ // NOTE: discussion-article is used for inline discussion modules.
+ @include clearfix();
- .post-header-content {
+ .post-header-content {
- // post title
- .post-title {
- @extend %t-title4;
- @extend %t-ultrastrong;
- margin-bottom: ($baseline/4);
- letter-spacing: 0;
- }
- }
-
- // post body
- .post-body {
- @extend %t-copy-sub1;
- // clear: both; //TO-DO: confirm that removing this is ok for all cases of discussion posts.
- }
-
- // post context
- .post-context {
- @extend %t-copy-sub2;
- margin-top: $baseline;
- color: $gray-d1;
-
- // CASE: no courseware context or cohort visibility rules
- &:empty {
- display: none;
+ // post title
+ .post-title {
+ @extend %t-title4;
+ @extend %t-ultrastrong;
+ margin-bottom: ($baseline/4);
+ letter-spacing: 0;
+ }
}
- // post visibility - cohorts
- .group-visibility-label {
- margin-top: ($baseline/4);
+ // post body
+ .post-body {
+ @extend %t-copy-sub1;
+ // clear: both; //TO-DO: confirm that removing this is ok for all cases of discussion posts.
+ }
+
+ // post context
+ .post-context {
+ @extend %t-copy-sub2;
+ margin-top: $baseline;
+ color: $gray-d1;
+
+ // CASE: no courseware context or cohort visibility rules
+ &:empty {
+ display: none;
+ }
+
+ // post visibility - cohorts
+ .group-visibility-label {
+ margin-top: ($baseline/4);
+ }
}
- }
}
// Layout control for discussion modules that does not apply to the discussion board
.discussion-module {
- .discussion-thread {
+ .btn-brand {
+ @include blue-button;
+ display: inline-block;
+ padding-bottom: ($baseline/10);
+ height: 37px;
+
+ &:hover, &:focus {
+ border-color: #222;
+ }
+ }
+}
+
+// Styling for discussion threads
+.discussion-thread {
+ padding: 0;
+ margin-bottom: $baseline;
+ @include transition(all .25s linear 0s);
+
+ p {
+ margin-bottom: 0;
+ }
+
.thread-main-wrapper, .thread-responses-wrapper {
- padding: $baseline;
+ padding: $baseline;
}
- }
- .btn-brand {
- @include blue-button;
- display: inline-block;
- padding-bottom: ($baseline/10);
- height: 37px;
+ .discussion-article {
+ @include transition(all .2s linear 0s);
+ border: 1px solid $forum-color-border;
+ border-radius: 3px;
+ min-height: 0;
+ background: $forum-color-background;
+ box-shadow: 0 1px 0 $shadow;
+ @include transition(all .2s linear 0s);
- &:hover, &:focus {
- border-color: #222;
+ .thread-wrapper {
+ @include border-radius(3px, 3px, 0, 0);
+ position: relative;
+ overflow-x: hidden;
+ overflow-y: auto;
+ max-height: 600px;
+ background-color: $forum-color-background;
+
+ .discussion-post {
+
+ .inline-comment-count {
+ @extend %ui-depth2;
+ position: relative;
+ float: right;
+ display: block;
+ height: 27px;
+ margin-top: 6px;
+ margin-right: 8px;
+ padding: 0 8px;
+ border-radius: ($baseline/4);
+ font-size: 12px;
+ font-weight: 400;
+ line-height: 25px;
+ color: #888;
+ }
+ }
+
+ .responses {
+ header {
+ padding-bottom: 0;
+ margin-bottom: ($baseline*0.75);
+
+ .posted-by {
+ float: left;
+ margin-right: ($baseline/4);
+ font-size: 16px;
+ }
+ }
+
+ .response-body {
+ margin-bottom: 0.2em;
+ font-size: 14px;
+ }
+ }
+
+ .discussion-reply-new {
+ .wmd-input {
+ height: 120px;
+ }
+ }
+
+ // Content that is hidden by default in the inline view
+ .post-extended-content {
+ display: none;
+ }
+ }
+
+ .post-tools {
+ box-shadow: 0 1px 1px $shadow inset;
+ background: $gray-l6;
+
+ &:hover {
+ background: #fcfcfc;
+
+ .icon {
+ color: $link-hover;
+ }
+ }
+
+ a {
+ display: block;
+ padding: ($baseline*0.25) $baseline;
+ font-size: 12px;
+ line-height: 30px;
+
+ .icon {
+ color: $link-color;
+ margin-right: ($baseline*0.25);
+ }
+ }
+ }
+ }
+}
+
+// Custom styling for the list of user threads
+.discussion-user-threads {
+ .discussion-post {
+ padding: $baseline/2;
}
- }
}
.thread-wrapper,
diff --git a/lms/static/sass/shared-v2/_layouts.scss b/lms/static/sass/shared-v2/_layouts.scss
index a54cdd8e73..66b30fb46f 100644
--- a/lms/static/sass/shared-v2/_layouts.scss
+++ b/lms/static/sass/shared-v2/_layouts.scss
@@ -8,6 +8,7 @@
}
.container {
+ @include clearfix();
border: 1px solid $lms-border-color;
background-color: $lms-container-background-color;
padding: $baseline;
diff --git a/lms/urls.py b/lms/urls.py
index 43f49df378..44b1f4147b 100644
--- a/lms/urls.py
+++ b/lms/urls.py
@@ -725,6 +725,12 @@ if settings.FEATURES.get('ENABLE_DISCUSSION_SERVICE'):
),
include('django_comment_client.urls')
),
+ url(
+ r'^courses/{}/discussion/forum/'.format(
+ settings.COURSE_ID_PATTERN,
+ ),
+ include('discussion.urls')
+ ),
url(
r'^notification_prefs/enable/',
'notification_prefs.views.ajax_enable'
diff --git a/setup.py b/setup.py
index b9e2426ea2..08f2637360 100644
--- a/setup.py
+++ b/setup.py
@@ -6,7 +6,7 @@ from setuptools import setup
setup(
name="Open edX",
- version="0.5",
+ version="0.6",
install_requires=["setuptools"],
requires=[],
# NOTE: These are not the names we should be installing. This tree should
@@ -23,7 +23,7 @@ setup(
"ccx = lms.djangoapps.ccx.plugins:CcxCourseTab",
"courseware = lms.djangoapps.courseware.tabs:CoursewareTab",
"course_info = lms.djangoapps.courseware.tabs:CourseInfoTab",
- "discussion = lms.djangoapps.django_comment_client.forum.views:DiscussionTab",
+ "discussion = lms.djangoapps.discussion.plugins:DiscussionTab",
"edxnotes = lms.djangoapps.edxnotes.plugins:EdxNotesTab",
"external_discussion = lms.djangoapps.courseware.tabs:ExternalDiscussionCourseTab",
"external_link = lms.djangoapps.courseware.tabs:ExternalLinkCourseTab",