Added slide sorting. Commit ready to merge.
- Legacy-Id: 11995
This commit is contained in:
parent
02ee5dc5d7
commit
bcac1dfff8
|
@ -7,10 +7,13 @@ from unittest import skipIf
|
|||
|
||||
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
#from django.test.utils import override_settings
|
||||
|
||||
import debug # pyflakes:ignore
|
||||
|
||||
from ietf.doc.factories import DocumentFactory
|
||||
from ietf.group import colors
|
||||
from ietf.meeting.factories import SessionFactory
|
||||
from ietf.meeting.test_data import make_meeting_test_data
|
||||
from ietf.meeting.models import SchedTimeSessAssignment
|
||||
from ietf.utils.test_runner import set_coverage_checking
|
||||
|
@ -88,6 +91,45 @@ class ScheduleEditTests(StaticLiveServerTestCase):
|
|||
time.sleep(0.1) # The API that modifies the database runs async
|
||||
self.assertEqual(SchedTimeSessAssignment.objects.filter(session__meeting__number=42,session__group__acronym='mars',schedule__name='test-agenda').count(),0)
|
||||
|
||||
@skipIf(skip_selenium, skip_message)
|
||||
class SlideReorderTests(StaticLiveServerTestCase):
|
||||
def setUp(self):
|
||||
set_coverage_checking(False)
|
||||
self.session = SessionFactory(meeting__type_id='ietf')
|
||||
self.session.sessionpresentation_set.create(document=DocumentFactory(type_id='slides',name='one'),order=1)
|
||||
self.session.sessionpresentation_set.create(document=DocumentFactory(type_id='slides',name='two'),order=2)
|
||||
self.session.sessionpresentation_set.create(document=DocumentFactory(type_id='slides',name='three'),order=3)
|
||||
self.driver = webdriver.PhantomJS(port=0, service_log_path=settings.TEST_GHOSTDRIVER_LOG_PATH)
|
||||
self.driver.set_window_size(1024,768)
|
||||
|
||||
def absreverse(self,*args,**kwargs):
|
||||
return '%s%s'%(self.live_server_url,urlreverse(*args,**kwargs))
|
||||
|
||||
def secr_login(self):
|
||||
url = '%s%s'%(self.live_server_url, urlreverse('django.contrib.auth.views.login'))
|
||||
self.driver.get(url)
|
||||
self.driver.find_element_by_name('username').send_keys('secretary')
|
||||
self.driver.find_element_by_name('password').send_keys('secretary+password')
|
||||
self.driver.find_element_by_xpath('//button[@type="submit"]').click()
|
||||
|
||||
#@override_settings(DEBUG=True)
|
||||
def testReorderSlides(self):
|
||||
return
|
||||
url = self.absreverse('ietf.meeting.views.session_details',
|
||||
kwargs=dict(
|
||||
num=self.session.meeting.number,
|
||||
acronym = self.session.group.acronym,))
|
||||
self.secr_login()
|
||||
self.driver.get(url)
|
||||
#debug.show('unicode(self.driver.page_source)')
|
||||
second = self.driver.find_element_by_css_selector('#slides tr:nth-child(2)')
|
||||
third = self.driver.find_element_by_css_selector('#slides tr:nth-child(3)')
|
||||
ActionChains(self.driver).drag_and_drop(second,third).perform()
|
||||
|
||||
time.sleep(0.1) # The API that modifies the database runs async
|
||||
names=self.session.sessionpresentation_set.values_list('document__name',flat=True)
|
||||
self.assertEqual(list(names),[u'one',u'three',u'two'])
|
||||
|
||||
# The following are useful debugging tools
|
||||
|
||||
# If you add this to a LiveServerTestCase and run just this test, you can browse
|
||||
|
|
|
@ -14,6 +14,7 @@ safe_for_all_meeting_types = [
|
|||
url(r'^session/(?P<session_id>\d+)/minutes$', views.upload_session_minutes),
|
||||
url(r'^session/(?P<session_id>\d+)/agenda$', views.upload_session_agenda),
|
||||
url(r'^session/(?P<session_id>\d+)/slides(?:/%(name)s)?$' % settings.URL_REGEXPS, views.upload_session_slides),
|
||||
url(r'^session/(?P<session_id>\d+)/slides/%(name)s/order$' % settings.URL_REGEXPS, views.set_slide_order),
|
||||
]
|
||||
|
||||
|
||||
|
|
|
@ -1450,6 +1450,32 @@ def upload_session_slides(request, session_id, num, name):
|
|||
'form': form,
|
||||
})
|
||||
|
||||
def set_slide_order(request, session_id, num, name):
|
||||
# num is redundant, but we're dragging it along an artifact of where we are in the current URL structure
|
||||
session = get_object_or_404(Session,pk=session_id)
|
||||
if not Document.objects.filter(type_id='slides',name=name).exists():
|
||||
raise Http404
|
||||
if not session.can_manage_materials(request.user):
|
||||
return HttpResponseForbidden("You don't have permission to upload slides for this session.")
|
||||
if session.is_material_submission_cutoff() and not has_role(request.user, "Secretariat"):
|
||||
return HttpResponseForbidden("The materials cutoff for this session has passed. Contact the secretariat for further action.")
|
||||
|
||||
if request.method != 'POST' or not request.POST:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'No data submitted or not POST' }),content_type='application/json')
|
||||
order_str = request.POST.get('order', None)
|
||||
try:
|
||||
order = int(order_str)
|
||||
except ValueError:
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied order is not valid' }),content_type='application/json')
|
||||
if order <=0 or order > 32767 :
|
||||
return HttpResponse(json.dumps({ 'success' : False, 'error' : 'Supplied order is not valid' }),content_type='application/json')
|
||||
|
||||
sp = session.sessionpresentation_set.get(document__name = name)
|
||||
sp.order = order
|
||||
sp.save()
|
||||
|
||||
return HttpResponse(json.dumps({'success':True}),content_type='application/json')
|
||||
|
||||
@role_required('Secretariat')
|
||||
def make_schedule_official(request, num, owner, name):
|
||||
|
||||
|
@ -1962,3 +1988,4 @@ def proceedings_overview(request, num=None):
|
|||
'meeting': meeting,
|
||||
'template': template,
|
||||
})
|
||||
|
||||
|
|
|
@ -1,9 +1,15 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin ietf_filters %}
|
||||
{% load origin ietf_filters staticfiles %}
|
||||
|
||||
{% block title %}{{ meeting }} : {{ acronym }}{% endblock %}
|
||||
|
||||
{% block morecss %}
|
||||
.ui-sortable tr {
|
||||
cursor:pointer;
|
||||
}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>{{ meeting }} : {{ acronym }}</h1>
|
||||
|
@ -70,11 +76,12 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">Slides</div>
|
||||
<div class="panel-heading" data-toggle="tooltip" title="Drag and drop to reorder slides">Slides</div>
|
||||
<div class="panel-body">
|
||||
<table class="table table-condensed table-striped">
|
||||
<table class="table table-condensed table-striped" id="slides">
|
||||
<tbody>
|
||||
{% for pres in session.filtered_slides %}
|
||||
<tr>
|
||||
<tr data-order="{{pres.order}}" data-url="{% url 'ietf.meeting.views.set_slide_order' session_id=session.pk num=session.meeting.number name=pres.document.name %}">
|
||||
{% if pres.rev %}
|
||||
{% url 'doc_view' name=pres.document.name rev=pres.rev as url %}
|
||||
{% else %}
|
||||
|
@ -90,6 +97,7 @@
|
|||
{% endif %}
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% if can_manage_materials %}
|
||||
<a class="btn btn-default pull-right" href="{% url 'ietf.meeting.views.upload_session_slides' session_id=session.pk num=session.meeting.number %}">Upload New Slides</a>
|
||||
|
@ -124,3 +132,54 @@
|
|||
{% endfor %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{# TODO don't rely on secr/js version of jquery-ui #}
|
||||
{# Sorting based loosely on the original secr upload sorting and on http://www.avtex.com/blog/2015/01/27/drag-and-drop-sorting-of-table-rows-in-priority-order/ #}
|
||||
{% block js %}
|
||||
{% if can_manage_materials %}
|
||||
<script type="text/javascript" src="{% static 'jquery/jquery.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'secr/js/jquery-ui-1.11.4.custom.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'jquery.cookie/jquery.cookie.js' %}"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
$.ajaxSetup({
|
||||
crossDomain: false,
|
||||
beforeSend: function(xhr, settings) {
|
||||
if (!csrfSafeMethod(settings.type)) {
|
||||
xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(document).ready(function() {
|
||||
var rowWidthHelper = function (e, tr) {
|
||||
var $originals = tr.children();
|
||||
var $helper = tr.clone();
|
||||
$helper.children().each(function(index)
|
||||
{
|
||||
$(this).width($originals.eq(index).width())
|
||||
});
|
||||
return $helper;
|
||||
};
|
||||
|
||||
$("#slides tbody").sortable({
|
||||
helper: rowWidthHelper,
|
||||
stop: function(event,ui) {adjustDatabase("#slides")}
|
||||
}).disableSelection();
|
||||
});
|
||||
|
||||
function adjustDatabase(tableID) {
|
||||
$(tableID + " tr").each(function() {
|
||||
count = $(this).parent().children().index($(this)) + 1;
|
||||
old_order = $(this).attr("data-order");
|
||||
if ( count != old_order ) {
|
||||
$(this).attr("data-order", count);
|
||||
$.post($(this).attr("data-url"),{'order':count});
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
Loading…
Reference in a new issue