New motion version diff view. Improved version history table in motion detail template.
This commit is contained in:
parent
196ad217b0
commit
a1a11ff53c
@ -15,6 +15,8 @@
|
||||
|
||||
from datetime import datetime
|
||||
|
||||
import difflib
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.db import models
|
||||
from django.db.models import Max
|
||||
@ -496,6 +498,12 @@ class MotionVersion(models.Model):
|
||||
"""Return True, if the version is the active version of a motion. Else: False."""
|
||||
return self.active_version.exists()
|
||||
|
||||
def make_htmldiff(self, rev1, rev2):
|
||||
"""Return string of html diff between two strings (rev1 and rev2)"""
|
||||
|
||||
diff = difflib.HtmlDiff(wrapcolumn=60)
|
||||
return diff.make_table(rev1.splitlines(), rev2.splitlines())
|
||||
|
||||
|
||||
class MotionSubmitter(models.Model):
|
||||
"""Save the submitter of a Motion."""
|
||||
|
41
openslides/motion/static/styles/motion.css
Normal file
41
openslides/motion/static/styles/motion.css
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* OpenSlides motion style
|
||||
*
|
||||
* :copyright: 2013 by OpenSlides team, see AUTHORS.
|
||||
* :license: GNU GPL, see LICENSE for more details.
|
||||
*/
|
||||
|
||||
/* motion version diff table */
|
||||
table.diff, .diff_row {
|
||||
font-size: 12px;
|
||||
width: 100%;
|
||||
border: 0px;
|
||||
}
|
||||
table.diff[rules][rules="groups"] > colgroup, table[rules][rules="groups"] > tfoot, table[rules][rules="groups"] > thead, table[rules][rules="groups"] > tbody {
|
||||
border: none;
|
||||
}
|
||||
table.diff td {
|
||||
padding: 0 !important;
|
||||
border: none;
|
||||
}
|
||||
.diff_header {
|
||||
background-color:#e0e0e0;
|
||||
}
|
||||
td.diff_header {
|
||||
text-align:right;
|
||||
display: none;
|
||||
}
|
||||
.diff_next {
|
||||
background-color:#c0c0c0;
|
||||
display: none;
|
||||
}
|
||||
.diff_add {
|
||||
background-color:#aaffaa;
|
||||
}
|
||||
.diff_chg {
|
||||
background-color:#ffff77;
|
||||
}
|
||||
.diff_sub {
|
||||
background-color:#ffaaaa;
|
||||
}
|
||||
|
@ -56,14 +56,14 @@
|
||||
|
||||
<div class="row-fluid">
|
||||
<div class="span8">
|
||||
{% if motion.active_version.id != motion.version.id %}
|
||||
|
||||
<span class="label label-warning"><i class="icon-warning-sign icon-white"></i>
|
||||
{% if motion.version.version_number < motion.last_version.version_number %}
|
||||
{% trans "This is not the newest version." %}</span> <a href="{% model_url motion.last_version %}">{% trans "Go to version" %} {{ motion.last_version.version_number }}.</a>
|
||||
{% else %}
|
||||
{% trans "This is not the authorized version." %}</span> <a href="{% model_url motion.active_version %}">{% trans "Go to version" %} {{ motion.active_version.version_number }}.</a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
|
||||
<!-- Text -->
|
||||
<h4>{% trans "Motion text" %}:</h4>
|
||||
@ -80,84 +80,60 @@
|
||||
<br>
|
||||
|
||||
<!-- Version history -->
|
||||
{% for version in motion.versions.all %}
|
||||
{% if forloop.first %}
|
||||
<h4>{% trans "Version history" %}:</h4>
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>{% trans "Version" %}</th>
|
||||
<th>{% trans "Time" %}</th>
|
||||
<th>{% trans "Title" %}</th>
|
||||
<th>{% trans "Text" %}</th>
|
||||
<th>{% trans "Reason" %}</th>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tr>
|
||||
<td class="nobr">
|
||||
{% if version == motion.active_version %}
|
||||
<span class="badge badge-success" title="{% trans 'This version is authorized' %}"><i class="icon-ok icon-white"></i></span>
|
||||
{% else %}
|
||||
{% if perms.motion.can_manage_motion %}
|
||||
<a class="btn btn-mini" href="{% url 'motion_version_permit' motion.id version.version_number %}" title="{% trans 'Permit this version' %}"><i class="icon-ok"></i></a>
|
||||
{% endif %}
|
||||
{% if not version.rejected and version.id > motion.active_version.id and perms.motion.can_manage_motion %}
|
||||
<a class="btn btn-mini" href="{% url 'motion_version_reject' motion.id version.version_number %}" title="{% trans 'Reject this version' %}"><i class="icon-ban-circle"></i></a>
|
||||
{% endif %}
|
||||
{% with versions=motion.versions.all %}
|
||||
{% if versions|length > 1 %}
|
||||
{% for version in versions %}
|
||||
{% if forloop.first %}
|
||||
<h4>{% trans "Version history" %}:</h4>
|
||||
<form action="{% url 'motion_version_diff' motion.pk %}" method="get">
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr>
|
||||
<th></th>
|
||||
<th>#</th>
|
||||
<th>{% trans "Time" %}</th>
|
||||
<th><button class="btn btn-small" type="submit">{% trans 'Difference' %}</button></th>
|
||||
<th>{% trans "Actions" %}</th>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if version.rejected %}
|
||||
<span class="badge badge-important" title="{% trans 'This version is rejected' %}"><i class="icon-ban-circle icon-white"></i></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td><a href="{% model_url version %}">{{ version.version_number }}</a></td>
|
||||
<td><i>{{ version.creation_time }}</i></td>
|
||||
<td>
|
||||
{% ifchanged %}
|
||||
<b>{{ version.title }}</b>
|
||||
{% else %}
|
||||
<i>[{% trans "unchanged" %}]</i>
|
||||
{% endifchanged %}
|
||||
</td>
|
||||
<td>
|
||||
{% ifchanged %}
|
||||
{{ version.text|linebreaks }}
|
||||
{% else %}
|
||||
<i>[{% trans "unchanged" %}]</i>
|
||||
{% endifchanged %}
|
||||
</td>
|
||||
<td>
|
||||
{% ifchanged %}
|
||||
{{ version.reason|linebreaks }}
|
||||
{% else %}
|
||||
<i>[{% trans "unchanged" %}]</i>
|
||||
{% endifchanged %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if forloop.last %}
|
||||
</table>
|
||||
<tr {% if version == motion.version %}class="offline"{%endif %}>
|
||||
<td class="nobr">
|
||||
{% if version == motion.active_version %}
|
||||
<span class="badge badge-success" title="{% trans 'This version is authorized' %}"><i class="icon-ok icon-white"></i></span>
|
||||
{% else %}
|
||||
{% if perms.motion.can_manage_motion %}
|
||||
<a class="btn btn-mini" href="{% url 'motion_version_permit' motion.id version.version_number %}" title="{% trans 'Permit this version' %}"><i class="icon-ok"></i></a>
|
||||
{% endif %}
|
||||
{% if not version.rejected and version.id > motion.active_version.id and perms.motion.can_manage_motion %}
|
||||
<a class="btn btn-mini" href="{% url 'motion_version_reject' motion.id version.version_number %}" title="{% trans 'Reject this version' %}"><i class="icon-ban-circle"></i></a>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if version.rejected %}
|
||||
<span class="badge badge-important" title="{% trans 'This version is rejected' %}"><i class="icon-ban-circle icon-white"></i></span>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>{{ version.version_number }}</td>
|
||||
<td><i>{{ version.creation_time }}</i></td>
|
||||
<td>
|
||||
<input type="radio" value="{{ version.version_number }}" name="rev1">
|
||||
<input type="radio" value="{{ version.version_number }}" name="rev2">
|
||||
</td>
|
||||
<td>
|
||||
<a href="{% model_url version %}" title="{% trans 'Show version number' %} {{ version.version_number }}" class="btn btn-mini">
|
||||
<i class="icon-search"></i>
|
||||
</a>
|
||||
{# TODO: add delete version function #}
|
||||
<a href="{% model_url version 'delete' %}" title="{% trans 'Delete version number' %} {{ version.version_number }}" class="btn btn-mini">
|
||||
<i class="icon-remove"></i>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% if forloop.last %}
|
||||
</table>
|
||||
</form>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
||||
<!-- TODO: For testing -->
|
||||
<ol>
|
||||
{% for motion_version in motion.versions.all %}
|
||||
<li>
|
||||
{% if motion_version.id == motion.version.id %}
|
||||
<strong><a href="{% model_url motion_version %}">{{ motion_version }}</a></strong>
|
||||
{% else %}
|
||||
<a href="{% model_url motion_version %}">{{ motion_version }}</a>
|
||||
{% endif %}
|
||||
{% if motion_version.active %}
|
||||
(active)
|
||||
{% endif %}
|
||||
{% if motion_version.rejected %}
|
||||
(rejected)
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ol>
|
||||
<!-- End TODO -->
|
||||
|
||||
{% endwith %}
|
||||
|
||||
<!-- Log -->
|
||||
{% if perms.motion.can_manage_motion %}
|
||||
|
67
openslides/motion/templates/motion/motion_diff.html
Normal file
67
openslides/motion/templates/motion/motion_diff.html
Normal file
@ -0,0 +1,67 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% load tags %}
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
|
||||
{% block title %}{{ block.super }} – {% trans "Motion" %} {{ motion.number }}{% endblock %}
|
||||
|
||||
{% block header %}
|
||||
<link type="text/css" rel="stylesheet" media="all" href="{% static 'styles/motion.css' %}" />
|
||||
{% endblock %}
|
||||
|
||||
|
||||
{% block content %}
|
||||
<h1>
|
||||
{{ motion.title }}
|
||||
<br>
|
||||
<small>
|
||||
{% if motion.number != None %}
|
||||
{% trans "Motion" %} {{ motion.number }},
|
||||
{% else %}
|
||||
<i>[{% trans "no number" %}]</i>,
|
||||
{% endif %}
|
||||
{% trans "Diff view" %}
|
||||
</small>
|
||||
<small class="pull-right">
|
||||
<div class="btn-toolbar">
|
||||
<a href="{% url 'motion_detail' motion.id %}" class="btn btn-mini"><i class="icon-chevron-left"></i> {% trans "Back to motion" %}</a>
|
||||
</div>
|
||||
</small>
|
||||
</h1>
|
||||
|
||||
{% if version_rev1 and version_rev2 %}
|
||||
<table class="table table-striped table-bordered">
|
||||
<tr>
|
||||
<td><b>{% trans "Version" %} {{ version_rev1.version_number }}</b><br>
|
||||
{% trans "created: " %} {{ version_rev1.creation_time }}<br>
|
||||
<h4>{{ version_rev1.title }}</h4>
|
||||
</td>
|
||||
<td><b>{% trans "Version" %} {{ version_rev2.version_number }}</b><br>
|
||||
{% trans "created: " %} {{ version_rev1.creation_time }}<br>
|
||||
<h4>{{ version_rev2.title }}</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- Text -->
|
||||
<tr class="diff_row">
|
||||
{% if not version_rev1.text == version_rev2.text %}
|
||||
<td colspan="2">{{ diff_text|safe }}</td>
|
||||
{% else %}
|
||||
<td>{{ version_rev1.text }}</td>
|
||||
<td>{{ version_rev2.text }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
<!-- Reason -->
|
||||
<tr><td colspan="2"><h4>{% trans "Reason" %}:</h4></td></tr>
|
||||
<tr class="diff_row">
|
||||
{% if not version_rev1.reason == version_rev2.reason %}
|
||||
<td colspan="2">{{ diff_reason|safe }}</td>
|
||||
{% else %}
|
||||
<td>{{ version_rev1.reason }}</td>
|
||||
<td>{{ version_rev2.reason }}</td>
|
||||
{% endif %}
|
||||
</tr>
|
||||
</table>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
@ -55,6 +55,11 @@ urlpatterns = patterns('openslides.motion.views',
|
||||
name='motion_version_reject',
|
||||
),
|
||||
|
||||
url(r'^(?P<pk>\d+)/diff/$',
|
||||
'version_diff',
|
||||
name='motion_version_diff',
|
||||
),
|
||||
|
||||
url(r'^(?P<pk>\d+)/support/$',
|
||||
'motion_support',
|
||||
name='motion_support',
|
||||
|
@ -230,6 +230,38 @@ class VersionRejectView(GetVersionMixin, SingleObjectMixin, QuestionMixin, Redir
|
||||
version_reject = VersionRejectView.as_view()
|
||||
|
||||
|
||||
class VersionDiffView(GetVersionMixin, DetailView):
|
||||
"""Show diff between two versions of a motion."""
|
||||
permission_required = 'motion.can_see_motion'
|
||||
model = Motion
|
||||
template_name = 'motion/motion_diff.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
"""Return the template context with versions and html diff strings."""
|
||||
try:
|
||||
rev1 = int(self.request.GET['rev1'])
|
||||
rev2 = int(self.request.GET['rev2'])
|
||||
version_rev1 = self.object.version.motion.versions.get(version_number=self.request.GET['rev1'])
|
||||
version_rev2 = self.object.version.motion.versions.get(version_number=self.request.GET['rev2'])
|
||||
diff_text = self.object.version.make_htmldiff(version_rev1.text, version_rev2.text)
|
||||
diff_reason = self.object.version.make_htmldiff(version_rev1.reason, version_rev2.reason)
|
||||
except (KeyError, ValueError, MotionVersion.DoesNotExist):
|
||||
messages.error(self.request, _('At least one version number was not valid.'))
|
||||
version_rev1 = None
|
||||
version_rev2 = None
|
||||
diff_text = None
|
||||
diff_reason = None
|
||||
context = super(VersionDiffView, self).get_context_data(**kwargs)
|
||||
context.update({
|
||||
'version_rev1': version_rev1,
|
||||
'version_rev2': version_rev2,
|
||||
'diff_text': diff_text,
|
||||
'diff_reason': diff_reason,
|
||||
})
|
||||
return context
|
||||
|
||||
version_diff = VersionDiffView.as_view()
|
||||
|
||||
class SupportView(SingleObjectMixin, RedirectView):
|
||||
"""View to support or unsupport a motion.
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user