Commit 62fa253a by E. Kolpakov Committed by Jonathan Piacenti

Backported edx-platform hosted discussion XBlock to edx-solutions (part 2)

parent 8c934284
......@@ -55,14 +55,7 @@ class DiscussionXBlock(XBlock):
"""
:return: int course id
"""
# TODO really implement this
# pylint: disable=no-member
if hasattr(self, 'xmodule_runtime'):
if hasattr(self.xmodule_runtime.course_id, 'to_deprecated_string'):
return self.xmodule_runtime.course_id.to_deprecated_string()
else:
return self.xmodule_runtime.course_id
return 'foo'
return unicode(self.location.course_key)
def student_view(self, context=None): # pylint: disable=unused-argument
""" Renders student view for LMS and Studio """
......@@ -78,7 +71,7 @@ class DiscussionXBlock(XBlock):
""" Renders student view for LMS """
fragment = Fragment()
discussion_service = self.xmodule_runtime.service(self, 'discussion') # pylint: disable=no-member
context = discussion_service.get_inline_template_context(self.discussion_id)
context = discussion_service.get_inline_template_context()
context['discussion_id'] = self.discussion_id
fragment.add_content(render_mako_template('discussion/_discussion_inline.html', context))
......@@ -174,6 +167,12 @@ class DiscussionCourseXBlock(XBlock):
context = discussion_service.get_course_template_context()
context['enable_new_post_btn'] = True
for url in get_js_urls():
fragment.add_javascript_url(url)
for url in get_css_urls():
fragment.add_css_url(url)
fragment.add_content(render_mako_template('discussion/_discussion_course.html', context))
fragment.add_javascript(render_template('static/js/discussion_course.js', {
......@@ -182,12 +181,6 @@ class DiscussionCourseXBlock(XBlock):
fragment.add_content(render_mustache_templates())
for url in get_js_urls():
fragment.add_javascript_url(url)
for url in get_css_urls():
fragment.add_css_url(url)
fragment.initialize_js('DiscussionCourseBlock')
return fragment
......
......@@ -5,7 +5,7 @@ function DiscussionInlineBlock(runtime, element) {
var testUrl = runtime.handlerUrl(element, 'test');
if (testUrl.match(/^(http|https):\/\//)) {
var hostname = testUrl.match(/^(.*:\/\/[a-z\-.]+)\//)[1];
var hostname = testUrl.match(/^(.*:\/\/[a-z0-9:\-.]+)\//)[1];
DiscussionUtil.setBaseUrl(hostname);
}
......
......@@ -9,6 +9,7 @@ from django.conf import settings
from mako.template import Template as MakoTemplate
JS_URLS = [
# VENDOR
'js/vendor/URI.min.js',
......@@ -17,6 +18,7 @@ JS_URLS = [
'js/vendor/underscore-min.js',
'js/vendor/backbone-min.js',
'js/vendor/mustache.js',
'js/vendor/mathjax-MathJax-c9db6ac/MathJax.js?config=TeX-MML-AM_HTMLorMML-full',
'xblock/discussion/js/vendor/split.js',
'xblock/discussion/js/vendor/i18n.js',
......@@ -28,10 +30,16 @@ JS_URLS = [
]
CSS_URLS = [
# 'xblock/discussion/css/discussion-app.css',
'xblock/discussion/css/vendor/font-awesome.css'
'xblock/discussion/css/vendor/font-awesome.css',
'sass/discussion-forum.css',
]
main_js = u'coffee/src/discussion/main.js'
all_js = set(rooted_glob(settings.COMMON_ROOT / 'static', 'coffee/src/discussion/**/*.js'))
all_js.remove(main_js)
discussion_js = sorted(all_js) + [main_js]
def load_resource(resource_path):
"""
......@@ -47,7 +55,7 @@ def render_template(template_path, context=None):
"""
template_str = load_resource(template_path)
template = Template(template_str)
return template.render(Context(context if context else {}))
return template.render(Context(context or {}))
def render_mako_template(template_path, context=None):
......@@ -67,7 +75,7 @@ def render_mustache_templates():
def read_file(file_name):
""" Reads file and decodes it's content """
return open(mustache_dir + '/' + file_name, "r").read().decode('utf-8')
return (mustache_dir / file_name).text("utf-8")
def template_id_from_file_name(file_name):
""" Generates template_id from file name """
......@@ -121,7 +129,7 @@ def load_scenarios_from_path(scenarios_path):
def get_js_urls():
""" Returns a list of all additional javascript files """
return [asset_to_static_url(path) for path in JS_URLS]
return [asset_to_static_url(path) for path in JS_URLS + discussion_js]
def get_css_urls():
......
......@@ -1585,14 +1585,15 @@ class DiscussionService(object):
Returns the context to render the course-level discussion templates.
"""
# for some reason pylint reports courseware.access, courseware.courses and django_comment_client.forum.views
# pylint: disable=import-error
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
from django_comment_client.forum.views import get_threads, make_course_settings
import django_comment_client.utils as utils
from openedx.core.djangoapps.course_groups.cohorts import (
is_course_cohorted,
......@@ -1604,7 +1605,7 @@ class DiscussionService(object):
escapedict = {'"': '"'}
request = HttpRequest()
user = self.runtime.user
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
......@@ -1623,6 +1624,8 @@ class DiscussionService(object):
cohorts = get_course_cohorts(course_id)
cohorted_commentables = get_cohorted_commentables(course_id)
course_settings = make_course_settings(course)
context = {
'course': course,
'course_id': course_id,
......@@ -1637,22 +1640,25 @@ class DiscussionService(object):
'is_moderator': has_permission(user, "see_all_cohorts", course_id),
'cohorts': cohorts,
'user_cohort': user_cohort_id,
'sort_preference': user_info['default_sort_key'],
'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)
'has_permission_to_openclose_thread': has_permission(user, "openclose_thread", course_id),
'course_settings': saxutils.escape(json.dumps(course_settings), escapedict),
}
return context
def get_inline_template_context(self, discussion_id):
def get_inline_template_context(self):
"""
Returns the context to render inline discussion templates.
"""
import lms.lib.comment_client as cc
# for some reason pylint reports courseware.access, courseware.courses and django_comment_client.forum.views
# pylint: disable=import-error
from django.conf import settings
from courseware.courses import get_course_with_access
from courseware.access import has_access
from django_comment_client.permissions import has_permission
......@@ -1669,6 +1675,8 @@ class DiscussionService(object):
has_access(user, 'staff', course)
context = {
'user': user,
'settings': settings,
'course': course,
'category_map': category_map,
'is_moderator': is_moderator,
......@@ -1682,7 +1690,7 @@ class DiscussionService(object):
return context
class ModuleSystem(MetricsMixin,ConfigurableFragmentWrapper, Runtime): # pylint: disable=abstract-method
class ModuleSystem(MetricsMixin, ConfigurableFragmentWrapper, Runtime): # pylint: disable=abstract-method
"""
This is an abstraction such that x_modules can function independent
of the courseware (e.g. import into other types of courseware, LMS,
......
......@@ -20,7 +20,9 @@ class @DiscussionSpecHelper
)
@makeEventSpy = () ->
jasmine.createSpyObj('event', ['preventDefault', 'target'])
obj = jasmine.createSpyObj('event', ['preventDefault'])
obj.target = document.createElement('div');
obj
@makeCourseSettings = (is_cohorted=true) ->
new DiscussionCourseSettings(
......
......@@ -96,7 +96,9 @@ describe "NewPostView", ->
@view.render()
expectedGroupId = null
DiscussionSpecHelper.makeAjaxSpy(
(params) -> expect(params.data.group_id).toEqual(expectedGroupId)
(params) =>
expect(params.data.group_id).toEqual(expectedGroupId)
@view.$(".forum-new-post-form").removeAttr("disabled")
)
_.each(
......
......@@ -13,11 +13,15 @@ $ ->
class @DiscussionUtil
@baseUrl = '';
@wmdEditors: {}
@getTemplate: (id) ->
$("script##{id}").html()
@setBaseUrl: (baseUrl) ->
@baseUrl = baseUrl
@setUser: (user) ->
@user = user
......@@ -54,7 +58,7 @@ class @DiscussionUtil
.click -> handler(this)
@urlFor: (name, param, param1, param2) ->
{
@baseUrl + {
follow_discussion : "/courses/#{$$course_id}/discussion/#{param}/follow"
unfollow_discussion : "/courses/#{$$course_id}/discussion/#{param}/unfollow"
create_thread : "/courses/#{$$course_id}/discussion/#{param}/threads/create"
......@@ -141,20 +145,22 @@ class @DiscussionUtil
return deferred.promise()
params["url"] = URI(params["url"]).addSearch ajax: 1
params["beforeSend"] = ->
if $elem
$elem.attr("disabled", "disabled")
if params["$loading"]
if params["loadingCallback"]?
params["loadingCallback"].apply(params["$loading"])
else
params["$loading"].loading(params["takeFocus"])
if !params["error"]
params["error"] = =>
@discussionAlert(
gettext("Sorry"),
gettext("We had some trouble processing your request. Please ensure you have copied any unsaved work and then reload the page.")
)
# important difference - can't use beforeSend as it's used in jquery.xblock to set up xhr parameters
if $elem
$elem.attr("disabled", "disabled")
if params["$loading"]
if params["loadingCallback"]?
params["loadingCallback"].apply(params["$loading"])
else
params["$loading"].loading(params["takeFocus"])
request = $.ajax(params).always ->
if $elem
$elem.removeAttr("disabled")
......
../../templates/js/discussion
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* This file is dynamically generated and ignored by Git.
* DO NOT MAKE CHANGES HERE. Instead, go edit its template:
* /edx/app/edxapp/edx-platform/lms/static/sass/discussion-forum.scss.mako
*/
// lms - css application architecture (platform)
// ====================
// libs and resets *do not edit*
@import 'bourbon/bourbon'; // lib - bourbon
// BASE *default edX offerings*
// ====================
// base - utilities
@import 'base/variables';
@import 'base/mixins';
// base - assets
@import 'base/font_face';
@import 'base/extends';
// base - elements
@import 'elements/typography';
@import 'elements/controls';
// shared
@import 'shared/modal';
// applications
@import "discussion/utilities/variables";
@import "discussion/mixins";
@import 'discussion/discussion'; // Process old file after definitions but before everything else
@import "discussion/elements/actions";
@import "discussion/elements/editor";
@import "discussion/elements/labels";
@import "discussion/elements/navigation";
@import "discussion/views/thread";
@import "discussion/views/create-edit-post";
@import "discussion/views/response";
@import 'discussion/utilities/developer';
@import 'discussion/utilities/shame';
## NOTE: This Sass infrastructure is redundant, but needed in order to address an IE9 rule limit within CSS - http://blogs.msdn.com/b/ieinternals/archive/2011/05/14/10164546.aspx
// lms - css application architecture (platform)
// ====================
// libs and resets *do not edit*
@import 'bourbon/bourbon'; // lib - bourbon
// BASE *default edX offerings*
// ====================
// base - utilities
@import 'base/variables';
@import 'base/mixins';
## THEMING
## -------
## Set up this file to import an edX theme library if the environment
## indicates that a theme should be used. The assumption is that the
## theme resides outside of this main edX repository, in a directory
## called themes/<theme-name>/, with its base Sass file in
## themes/<theme-name>/static/sass/_<theme-name>.scss. That one entry
## point can be used to @import in as many other things as needed.
% if env["FEATURES"].get("USE_CUSTOM_THEME", False):
// import theme's Sass overrides
@import '${env.get('THEME_NAME')}';
% endif
// base - assets
@import 'base/font_face';
@import 'base/extends';
// base - elements
@import 'elements/typography';
@import 'elements/controls';
// shared
@import 'shared/modal';
// applications
@import "discussion/utilities/variables";
@import "discussion/mixins";
@import 'discussion/discussion'; // Process old file after definitions but before everything else
@import "discussion/elements/actions";
@import "discussion/elements/editor";
@import "discussion/elements/labels";
@import "discussion/elements/navigation";
@import "discussion/views/thread";
@import "discussion/views/create-edit-post";
@import "discussion/views/response";
@import 'discussion/utilities/developer';
@import 'discussion/utilities/shame';
// discussion - elements - labels
// ====================
body.discussion, .discussion-module, .discussion-body {
body.discussion, .discussion-module, .discussion-body, .discussion-course {
.post-label-pinned {
@include forum-post-label($forum-color-pinned);
}
......
......@@ -8,6 +8,31 @@
width: 31%;
border: 1px solid #aaa;
border-radius: 3px;
div.discussion-course, div.content-wrapper {
section.discussion {
div.forum-nav {
@include box-sizing(border-box);
float: left;
position: relative;
width: 31%;
border: 1px solid #aaa;
border-radius: 3px;
ul, ol {
list-style: none;
padding-left: 0;
li.forum-nav-thread {
margin-bottom: 0;
}
&.forum-nav-browse-submenu {
padding-left: $baseline;
list-style: none;
}
}
}
}
}
// ------
......@@ -99,10 +124,7 @@
list-style: none;
}
.forum-nav-browse-submenu {
padding-left: $baseline;
list-style: none;
}
.forum-nav-browse-title {
display: block;
......
......@@ -17,7 +17,7 @@
// provisional styling for "search alerts" (messages boxes that appear in the sidebar below the search
// input field with notices pertaining to the search result).
// --------------------
body.discussion {
body.discussion, .discussion-course, div.discussion-body {
.forum-nav {
......
......@@ -4,7 +4,7 @@
// UI: form structure
.forum-new-post-form,
.edit-post-form {
@include clearfix();
@include clearfix;
box-sizing: border-box;
margin: 0;
border-radius: 3px;
......@@ -46,7 +46,7 @@
.field-help {
@include box-sizing(border-box);
display: inline-block;
@include padding-left($baseline);
padding-left: ($baseline);
width: 50%;
font-size: 12px;
}
......@@ -71,7 +71,7 @@
@include white-button;
@extend %cont-truncated;
z-index: 1000;
padding: 0 $baseline 0 ($baseline*0.75);
padding: 0 $baseline 0 ($baseline*.75);
height: 40px;
font-size: 14px;
line-height: 36px;
......@@ -101,7 +101,7 @@
line-height: 36px;
.icon {
margin-right: ($baseline/4);
margin-right: 5px;
}
}
......@@ -131,7 +131,7 @@
.post-option {
@include box-sizing(border-box);
display: inline-block;
@include margin-right($baseline);
margin-right: ($baseline);
border: 1px solid transparent;
border-radius: 3px;
padding: ($baseline/2);
......@@ -208,10 +208,10 @@
.topic-menu-wrapper {
@include box-sizing(border-box);
@extend %ui-depth4;
position: absolute;
top: 40px;
left: 0;
z-index: 9999;
border: 1px solid $gray-l3;
width: 100%;
background: $white;
......
......@@ -2,7 +2,7 @@
// ====================
// general thread layout
body.discussion, .discussion-module {
body.discussion, .discussion-module, div.discussion-course {
// post layout
.discussion-post {
......@@ -124,7 +124,7 @@ body.discussion, .discussion-module {
background-color: $white;
}
body.discussion, .discussion-thread.expanded {
body.discussion, .discussion-thread.expanded, div.discussion-course {
.forum-thread-main-wrapper {
box-shadow: 0 1px 3px $shadow;
}
......
......@@ -44,6 +44,8 @@ ${page_title_breadcrumbs(course_name())}
<%block name="nav_skip">${"#seq_content" if section_title else "#course-content"}</%block>
<%include file="../discussion/_js_head_dependencies.html" />
% if show_chat:
<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,
......
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