Commit e304d71c by David Ormsbee

Merge pull request #1059 from MITx/feature/tom/dashboard-carousel

Add a carousel to display news on the student dashboard
parents b6218518 ac806f6e
......@@ -69,20 +69,6 @@ def index(request, extra_context={}, user=None):
extra_context is used to allow immediate display of certain modal windows, eg signup,
as used by external_auth.
'''
feed_data = cache.get("students_index_rss_feed_data")
if feed_data == None:
if hasattr(settings, 'RSS_URL'):
feed_data = urllib.urlopen(settings.RSS_URL).read()
else:
feed_data = render_to_string("feed.rss", None)
cache.set("students_index_rss_feed_data", feed_data, settings.RSS_TIMEOUT)
feed = feedparser.parse(feed_data)
entries = feed['entries'][0:3]
for entry in entries:
soup = BeautifulSoup(entry.description)
entry.image = soup.img['src'] if soup.img else None
entry.summary = soup.getText()
# The course selection work is done in courseware.courses.
domain = settings.MITX_FEATURES.get('FORCE_UNIVERSITY_DOMAIN') # normally False
......@@ -90,7 +76,11 @@ def index(request, extra_context={}, user=None):
domain = request.META.get('HTTP_HOST')
universities = get_courses_by_university(None,
domain=domain)
context = {'universities': universities, 'entries': entries}
# Get the 3 most recent news
top_news = _get_news(top=3)
context = {'universities': universities, 'news': top_news}
context.update(extra_context)
return render_to_response('index.html', context)
......@@ -230,12 +220,16 @@ def dashboard(request):
cert_statuses = { course.id: cert_info(request.user, course) for course in courses}
# Get the 3 most recent news
top_news = _get_news(top=3)
context = {'courses': courses,
'message': message,
'staff_access': staff_access,
'errored_courses': errored_courses,
'show_courseware_links_for' : show_courseware_links_for,
'cert_statuses': cert_statuses,
'news': top_news,
}
return render_to_response('dashboard.html', context)
......@@ -883,3 +877,24 @@ def test_center_login(request):
return redirect('/courses/MITx/6.002x/2012_Fall/courseware/Final_Exam/Final_Exam_Fall_2012/')
else:
return HttpResponseForbidden()
def _get_news(top=None):
"Return the n top news items on settings.RSS_URL"
feed_data = cache.get("students_index_rss_feed_data")
if feed_data == None:
if hasattr(settings, 'RSS_URL'):
feed_data = urllib.urlopen(settings.RSS_URL).read()
else:
feed_data = render_to_string("feed.rss", None)
cache.set("students_index_rss_feed_data", feed_data, settings.RSS_TIMEOUT)
feed = feedparser.parse(feed_data)
entries = feed['entries'][0:top] # all entries if top is None
for entry in entries:
soup = BeautifulSoup(entry.description)
entry.image = soup.img['src'] if soup.img else None
entry.summary = soup.getText()
return entries
import csv
import json
import logging
import urllib
import itertools
import StringIO
from functools import partial
......@@ -12,7 +8,7 @@ from django.core.context_processors import csrf
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
from django.http import Http404, HttpResponse
from django.http import Http404
from django.shortcuts import redirect
from mitxmako.shortcuts import render_to_response, render_to_string
#from django.views.decorators.csrf import ensure_csrf_cookie
......@@ -25,15 +21,11 @@ from courseware.courses import (get_course_with_access, get_courses_by_universit
import courseware.tabs as tabs
from courseware.models import StudentModuleCache
from module_render import toc_for_course, get_module, get_instance_module
from student.models import UserProfile
from multicourse import multicourse_settings
from django_comment_client.utils import get_discussion_title
from student.models import UserTestGroup, CourseEnrollment
from util.cache import cache, cache_if_anonymous
from xmodule.course_module import CourseDescriptor
from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
from xmodule.modulestore.exceptions import InvalidLocationError, ItemNotFoundError, NoPathToItem
......@@ -78,7 +70,7 @@ def courses(request):
'''
universities = get_courses_by_university(request.user,
domain=request.META.get('HTTP_HOST'))
return render_to_response("courses.html", {'universities': universities})
return render_to_response("courseware/courses.html", {'universities': universities})
def render_accordion(request, course, chapter, section):
......@@ -97,7 +89,7 @@ def render_accordion(request, course, chapter, section):
context = dict([('toc', toc),
('course_id', course.id),
('csrf', csrf(request)['csrf_token'])] + template_imports.items())
return render_to_string('accordion.html', context)
return render_to_string('courseware/accordion.html', context)
def get_current_child(xmodule):
......@@ -407,7 +399,7 @@ def course_about(request, course_id):
show_courseware_link = (has_access(request.user, course, 'load') or
settings.MITX_FEATURES.get('ENABLE_LMS_MIGRATION'))
return render_to_response('portal/course_about.html',
return render_to_response('courseware/course_about.html',
{'course': course,
'registered': registered,
'course_target': course_target,
......@@ -449,7 +441,7 @@ def render_notifications(request, course, notifications):
'get_discussion_title': partial(get_discussion_title, request=request, course=course),
'course': course,
}
return render_to_string('notifications.html', context)
return render_to_string('courseware/notifications.html', context)
@login_required
def news(request, course_id):
......@@ -462,7 +454,7 @@ def news(request, course_id):
'content': render_notifications(request, course, notifications),
}
return render_to_response('news.html', context)
return render_to_response('courseware/news.html', context)
@login_required
@cache_control(no_cache=True, no_store=True, must_revalidate=True)
......
......@@ -98,7 +98,7 @@
&.email-icon {
@include background-image(url('../images/portal-icons/email-icon.png'));
}
&.name-icon {
@include background-image(url('../images/portal-icons/course-info-icon.png'));
}
......@@ -124,6 +124,103 @@
}
}
}
.news-carousel {
@include clearfix;
margin: 30px 10px 0;
border: 1px solid rgb(200,200,200);
background: rgb(252,252,252);
@include box-shadow(inset 0 0 3px 0 rgba(0,0,0, 0.15));
* {
font-family: $sans-serif;
}
header {
@include clearfix;
height: 50px;
}
.page-dots {
float: right;
margin: 18px 15px 0 0;
li {
float: left;
margin-left: 6px;
}
}
.page-dot {
display: block;
width: 11px;
height: 11px;
border-radius: 11px;
background: $light-gray;
&:hover {
background: #ccc;
}
&.current {
background: $blue;
}
}
h4 {
float: left;
margin-left: 15px;
font-size: 15px;
line-height: 48px;
font-weight: 700;
text-transform: uppercase;
}
.pages {
position: relative;
}
.page {
display: none;
position: absolute;
top: 0;
left: 0;
&:first-child {
display: block;
}
}
section {
padding: 0 10px;
}
.news-image {
height: 180px;
margin-bottom: 15px;
img {
width: 100%;
border: 1px solid $light-gray;
}
}
h5 {
margin-bottom: 8px;
margin-left: 5px;
a {
font-size: 16px;
font-weight: 700;
}
}
.excerpt {
margin-left: 5px;
font-size: 13px;
padding-bottom: 40px;
}
}
}
.my-courses {
......@@ -325,7 +422,7 @@
p {
color: #222;
span {
font-weight: bold;
}
......@@ -392,7 +489,7 @@
font-family: "Open Sans", Verdana, Geneva, sans-serif;
background: #fffcf0;
border: 1px solid #ccc;
.message-copy {
margin: 0;
......
<%inherit file="main.html" />
<%inherit file="../main.html" />
<%namespace name='static' file='static_content.html'/>
<%namespace name='static' file='../static_content.html'/>
<%block name="title"><title>Courses</title></%block>
......@@ -22,17 +22,17 @@
<section class="courses">
<section class='university-column'>
%for course in universities['MITx']:
<%include file="course.html" args="course=course" />
<%include file="../course.html" args="course=course" />
%endfor
</section>
<section class='university-column'>
%for course in universities['HarvardX']:
<%include file="course.html" args="course=course" />
<%include file="../course.html" args="course=course" />
%endfor
</section>
<section class='university-column last'>
%for course in universities['BerkeleyX']:
<%include file="course.html" args="course=course" />
<%include file="../course.html" args="course=course" />
%endfor
</section>
</section>
......
<%inherit file="main.html" />
<%namespace name='static' file='static_content.html'/>
<%namespace name='static' file='../static_content.html'/>
<%block name="bodyclass">courseware news</%block>
<%block name="title"><title>News – MITx 6.002x</title></%block>
......@@ -10,7 +10,7 @@
<%block name="js_extra">
</%block>
<%include file="/courseware/course_navigation.html" args="active_page='news'" />
<%include file="course_navigation.html" args="active_page='news'" />
<section class="container">
<div class="course-wrapper">
......
......@@ -5,7 +5,7 @@ def url_for_thread(discussion_id, thread_id):
return reverse('django_comment_client.forum.views.single_thread', args=[course.id, discussion_id, thread_id])
%>
<%
<%
def url_for_comment(discussion_id, thread_id, comment_id):
return url_for_thread(discussion_id, thread_id) + "#" + comment_id
%>
......@@ -15,7 +15,7 @@ def url_for_discussion(discussion_id):
return reverse('django_comment_client.forum.views.forum_form_discussion', args=[course.id, discussion_id])
%>
<%
<%
def discussion_title(discussion_id):
return get_discussion_title(discussion_id=discussion_id)
%>
......@@ -59,18 +59,18 @@ def url_for_user(user_id): #TODO
<%def name="render_notification(notification)">
<div class="notification">
% if notification['notification_type'] == 'post_reply':
${render_user_link(notification)} posted a ${render_comment_link(notification)}
${render_user_link(notification)} posted a ${render_comment_link(notification)}
to the thread ${render_thread_link(notification)} in discussion ${render_discussion_link(notification)}
% elif notification['notification_type'] == 'post_topic':
${render_user_link(notification)} posted a new thread ${render_thread_link(notification)}
in discussion ${render_discussion_link(notification)}
% elif notification['notification_type'] == 'at_user':
${render_user(info)} mentioned you in
${render_user(info)} mentioned you in
% if notification['info']['content_type'] == 'thread':
the thread ${render_thread_link(notification)}
in discussion ${render_discussion_link(notification)}
% else:
${render_comment_link(notification)}
${render_comment_link(notification)}
to the thread ${render_thread_link(notification)} in discussion ${render_discussion_link(notification)}
% endif
% endif
......
......@@ -14,6 +14,45 @@
<script type="text/javascript">
(function() {
var carouselPageHeight = 0;
var carouselIndex = 0;
var carouselDelay = 5000;
var carouselPages = $('.news-carousel .page').length;
$('.news-carousel .page').each(function() {
carouselPageHeight = Math.max($(this).outerHeight(), carouselPageHeight);
});
$('.news-carousel .pages').css('height', carouselPageHeight);
$('.news-carousel .page-dot').bind('click', setCarouselPage);
var carouselTimer = setInterval(nextCarouselPage, carouselDelay);
function nextCarouselPage() {
carouselIndex = carouselIndex + 1 < carouselPages ? carouselIndex + 1 : 0;
setCarouselPage(null, carouselIndex);
}
function setCarouselPage(event, index) {
var $pageToShow;
var transitionSpeed;
$('.news-carousel .page-dots').find('.current').removeClass('current');
if(event) {
clearInterval(carouselTimer);
carouselTimer = setInterval(nextCarouselPage, carouselDelay);
transitionSpeed = 250;
$pageToShow = $('.news-carousel .page').eq(index);
$(this).addClass('current');
} else {
transitionSpeed = 750;
$pageToShow = $('.news-carousel .page').eq(index);
$('.news-carousel .page-dot').eq(index).addClass('current');
}
$pageToShow.fadeIn(transitionSpeed);
$('.news-carousel .page').not($pageToShow).fadeOut(transitionSpeed);
}
$(".unenroll").click(function(event) {
$("#unenroll_course_id").val( $(event.target).data("course-id") );
$("#unenroll_course_number").text( $(event.target).data("course-number") );
......@@ -107,6 +146,39 @@
</li>
</ul>
</section>
%if news:
<article class="news-carousel">
<header>
<h4>edX News</h4>
<nav class="page-dots">
<ol>
<li><a href="#" class="page-dot current"></a></li>
<li><a href="#" class="page-dot"></a></li>
<li><a href="#" class="page-dot"></a></li>
</ol>
</nav>
</header>
<div class="pages">
% for entry in news:
<section class="page">
%if entry.image:
<div class="news-image">
<a href="${entry.link}"><img src="${entry.image}" /></a>
</div>
%endif
<h5><a href="${entry.link}">${entry.title}</a></h5>
<div class="excerpt">
%if entry.summary:
<p>${entry.summary}</p>
%endif
<p><a href="${entry.link}">Learn More ›</a></p>
</div>
</section>
%endfor
</div>
</article>
%endif
</section>
<section class="my-courses">
......@@ -181,7 +253,7 @@
<p class="message-copy">You did not complete the necessary requirements for
completion of this course.</p>
% endif
% if cert_status['show_disabled_download_button'] or cert_status['show_download_url'] or cert_status['show_survey_button']:
<ul class="actions">
% if cert_status['show_disabled_download_button']:
......@@ -193,7 +265,7 @@
title="This link will open/download a PDF document">
Download Your PDF Certificate</a></li>
% endif
% if cert_status['show_survey_button']:
<li class="action"><a class="cta" href="${cert_status['survey_url']}">
Complete our course feedback survey</a></li>
......
......@@ -13,7 +13,7 @@
<updated>2012-11-12T14:00:00-07:00</updated>
<link type="text/html" rel="alternate" href="${reverse('press/gates-foundation-announcement')}"/>
<title>edX and Massachusetts Community Colleges join in Gates-Funded educational initiative</title>
<content type="html">&lt;img src=&quot;${static.url('images/press/mass_seal_240x180.png')}&quot; /&gt;
<content type="html">&lt;img src=&quot;${static.url('images/press/releases/mass_seal_240x180.png')}&quot; /&gt;
&lt;p&gt;&lt;/p&gt;</content>
</entry>
<entry>
......@@ -22,7 +22,7 @@
<updated>2012-10-14T14:00:00-07:00</updated>
<link type="text/html" rel="alternate" href="${reverse('press/ut-joins-edx')}"/>
<title>The University of Texas System joins edX</title>
<content type="html">&lt;img src=&quot;${static.url('images/press/uts-seal_109x84.jpg')}&quot; /&gt;
<content type="html">&lt;img src=&quot;${static.url('images/press/releases/utsys-seal_240x180.png')}&quot; /&gt;
&lt;p&gt;Nine universities and six health institutions&lt;/p&gt;</content>
</entry>
<!-- <entry> -->
......@@ -31,7 +31,7 @@
<!-- <updated>2012-09-25T14:00:00-07:00</updated> -->
<!-- <link type="text/html" rel="alternate" href="${reverse('press/elsevier-collaborates-with-edx')}"/> -->
<!-- <title>Elsevier collaborates with edX</title> -->
<!-- <content type="html">&lt;img src=&quot;${static.url('images/press/foundations-of-analog-109x84.jpg')}&quot; /&gt; -->
<!-- <content type="html">&lt;img src=&quot;${static.url('images/press/releases/foundations-of-analog_240x180.jpg')}&quot; /&gt; -->
<!-- &lt;p&gt;Free course textbook made available to edX students&lt;/p&gt;</content> -->
<!-- </entry> -->
<entry>
......@@ -39,8 +39,8 @@
<published>2012-09-06T14:00:00-07:00</published>
<updated>2012-09-06T14:00:00-07:00</updated>
<link type="text/html" rel="alternate" href="${reverse('press/edX-announces-proctored-exam-testing')}"/>
<title>EdX to offer learners option of taking proctored final exam</title>
<content type="html">&lt;img src=&quot;${static.url('images/press/diploma-109x84.jpg')}&quot; /&gt;</content>
<title>edX to offer learners option of taking proctored final exam</title>
<content type="html">&lt;img src=&quot;${static.url('images/press/releases/diploma_240x180.jpg')}&quot; /&gt;</content>
</entry>
<entry>
<id>tag:www.edx.org,2012:Post/3</id>
......@@ -48,7 +48,7 @@
<updated>2012-07-16T14:08:12-07:00</updated>
<link type="text/html" rel="alternate" href="${reverse('press/uc-berkeley-joins-edx')}"/>
<title>UC Berkeley joins edX</title>
<content type="html">&lt;img src=&quot;${static.url('images/press/edx-109x84.png')}&quot; /&gt;
<content type="html">&lt;img src=&quot;${static.url('images/press/releases/edx-logo_240x180.png')}&quot; /&gt;
&lt;p&gt;edX broadens course offerings&lt;/p&gt;</content>
</entry>
<entry>
......@@ -57,7 +57,7 @@
<updated>2012-07-16T14:08:12-07:00</updated>
<link type="text/html" rel="alternate" href="http://edxonline.tumblr.com/post/27589840852/opening-doors-for-exceptional-students-6-002x-in"/>
<title>Opening Doors For Exceptional Students: 6.002x in Mongolia</title>
<content type="html">&lt;img src=&quot;${static.url('images/press/tumblr_tumbnail_opening_doors_mongolia.jpg')}&quot; /&gt;</content>
<content type="html">&lt;img src=&quot;${static.url('images/press/releases/tumblr-mongolia_240x180.jpg')}&quot; /&gt;</content>
</entry>
<entry>
<id>tag:www.edx.org,2012:Post/1</id>
......@@ -65,6 +65,6 @@
<updated>2012-07-16T14:08:12-07:00</updated>
<link type="text/html" rel="alternate" href="http://edxonline.tumblr.com/post/27589835076/beyond-the-circuits-a-students-experience-with-6-002x"/>
<title>Brazilian teen blogs about his 6.002x experience</title>
<content type="html">&lt;img src=&quot;${static.url('images/press/tumblr_tumbnail_brazilian_teen.jpg')}&quot; /&gt;</content>
<content type="html">&lt;img src=&quot;${static.url('images/press/releases/tumblr-brazilian-teen_240x180.jpg')}&quot; /&gt;</content>
</entry>
</feed>
......@@ -111,7 +111,7 @@
</header>
<section class="news">
<section class="blog-posts">
%for entry in entries:
%for entry in news:
<article>
%if entry.image:
<a href="${entry.link}" class="post-graphics" target="_blank"><img src="${entry.image}" /></a>
......
......@@ -27,7 +27,7 @@
<p>Students who enroll in edX's course <a href="https://www.edx.org/courses/HarvardX/PH207x/2012_Fall/about">PHW207x: Health in Numbers </a>, taught by Professor Marcello Pagano of Harvard's School of Public Health, will have access to an online version of the course textbook, <a href="http://www.cengage.com/search/productOverview.do?Ntt=Principles+of+Biostatistics%7C%7C1294593750742656302174876073224090273&amp;N=16&amp;Ntk=all%7C%7CP_EPI">Principles of Biostatistics, 2nd Edition</a>, written by Marcello Pagano and Kimberlee Gauvreau and published by Cengage Learning. Cengage Learning’s instructional design services will also work with edX to migrate the print pedagogy from the textbook into the on-line course, creating the best scope and sequence for effective student learning.</p>
<figure>
<img src="${static.url('images/press/cengage_book_327x400.jpg')}" />
<img src="${static.url('images/press/releases/cengage_book_327x400.jpg')}" />
</figure>
<p>&ldquo;edX students worldwide will benefit from both Professor Pagano's in-class lectures and his classic Cengage Learning textbook in biostatics,&rdquo; said Anant Agarwal, President of edX. &ldquo;We are very grateful for Cengage's commitment to helping edX learners throughout the world.&rdquo;</p>
......
......@@ -30,7 +30,7 @@
<p>The free version of the textbook was also available in the spring offering of MIT&rsquo;s 6.002x, before the creation of edX.</p>
<figure>
<img src="${static.url('images/press/elsevier_page_sample_680x660.png')}" />
<img src="${static.url('images/press/releases/elsevier_page_sample_680x660.png')}" />
<figcaption>A page view from the online version of <a href="http://store.elsevier.com/product.jsp?isbn=9781558607354">Foundations of Analog and Digital Electronic Circuits</a> made available to students taking edX&rsquo;s course <a href="https://www.edx.org/courses/MITx/6.002x/2012_Fall/about">6.002X: Circuits and Electronics</a></figcaption>
</figure>
......
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