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
|
from datetime import datetime
|
||||||
|
|
||||||
|
import difflib
|
||||||
|
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models import Max
|
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 True, if the version is the active version of a motion. Else: False."""
|
||||||
return self.active_version.exists()
|
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):
|
class MotionSubmitter(models.Model):
|
||||||
"""Save the submitter of a Motion."""
|
"""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="row-fluid">
|
||||||
<div class="span8">
|
<div class="span8">
|
||||||
{% if motion.active_version.id != motion.version.id %}
|
|
||||||
<span class="label label-warning"><i class="icon-warning-sign icon-white"></i>
|
<span class="label label-warning"><i class="icon-warning-sign icon-white"></i>
|
||||||
{% if motion.version.version_number < motion.last_version.version_number %}
|
{% 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>
|
{% 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 %}
|
{% 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>
|
{% 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 %}
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Text -->
|
<!-- Text -->
|
||||||
<h4>{% trans "Motion text" %}:</h4>
|
<h4>{% trans "Motion text" %}:</h4>
|
||||||
@ -80,84 +80,60 @@
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
<!-- Version history -->
|
<!-- Version history -->
|
||||||
{% for version in motion.versions.all %}
|
{% with versions=motion.versions.all %}
|
||||||
{% if forloop.first %}
|
{% if versions|length > 1 %}
|
||||||
<h4>{% trans "Version history" %}:</h4>
|
{% for version in versions %}
|
||||||
<table class="table table-striped table-bordered">
|
{% if forloop.first %}
|
||||||
<tr>
|
<h4>{% trans "Version history" %}:</h4>
|
||||||
<th></th>
|
<form action="{% url 'motion_version_diff' motion.pk %}" method="get">
|
||||||
<th>{% trans "Version" %}</th>
|
<table class="table table-striped table-bordered">
|
||||||
<th>{% trans "Time" %}</th>
|
<tr>
|
||||||
<th>{% trans "Title" %}</th>
|
<th></th>
|
||||||
<th>{% trans "Text" %}</th>
|
<th>#</th>
|
||||||
<th>{% trans "Reason" %}</th>
|
<th>{% trans "Time" %}</th>
|
||||||
</tr>
|
<th><button class="btn btn-small" type="submit">{% trans 'Difference' %}</button></th>
|
||||||
{% endif %}
|
<th>{% trans "Actions" %}</th>
|
||||||
<tr>
|
</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 %}
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if version.rejected %}
|
<tr {% if version == motion.version %}class="offline"{%endif %}>
|
||||||
<span class="badge badge-important" title="{% trans 'This version is rejected' %}"><i class="icon-ban-circle icon-white"></i></span>
|
<td class="nobr">
|
||||||
{% endif %}
|
{% if version == motion.active_version %}
|
||||||
</td>
|
<span class="badge badge-success" title="{% trans 'This version is authorized' %}"><i class="icon-ok icon-white"></i></span>
|
||||||
<td><a href="{% model_url version %}">{{ version.version_number }}</a></td>
|
{% else %}
|
||||||
<td><i>{{ version.creation_time }}</i></td>
|
{% if perms.motion.can_manage_motion %}
|
||||||
<td>
|
<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>
|
||||||
{% ifchanged %}
|
{% endif %}
|
||||||
<b>{{ version.title }}</b>
|
{% if not version.rejected and version.id > motion.active_version.id and perms.motion.can_manage_motion %}
|
||||||
{% else %}
|
<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>
|
||||||
<i>[{% trans "unchanged" %}]</i>
|
{% endif %}
|
||||||
{% endifchanged %}
|
{% endif %}
|
||||||
</td>
|
{% if version.rejected %}
|
||||||
<td>
|
<span class="badge badge-important" title="{% trans 'This version is rejected' %}"><i class="icon-ban-circle icon-white"></i></span>
|
||||||
{% ifchanged %}
|
{% endif %}
|
||||||
{{ version.text|linebreaks }}
|
</td>
|
||||||
{% else %}
|
<td>{{ version.version_number }}</td>
|
||||||
<i>[{% trans "unchanged" %}]</i>
|
<td><i>{{ version.creation_time }}</i></td>
|
||||||
{% endifchanged %}
|
<td>
|
||||||
</td>
|
<input type="radio" value="{{ version.version_number }}" name="rev1">
|
||||||
<td>
|
<input type="radio" value="{{ version.version_number }}" name="rev2">
|
||||||
{% ifchanged %}
|
</td>
|
||||||
{{ version.reason|linebreaks }}
|
<td>
|
||||||
{% else %}
|
<a href="{% model_url version %}" title="{% trans 'Show version number' %} {{ version.version_number }}" class="btn btn-mini">
|
||||||
<i>[{% trans "unchanged" %}]</i>
|
<i class="icon-search"></i>
|
||||||
{% endifchanged %}
|
</a>
|
||||||
</td>
|
{# TODO: add delete version function #}
|
||||||
</tr>
|
<a href="{% model_url version 'delete' %}" title="{% trans 'Delete version number' %} {{ version.version_number }}" class="btn btn-mini">
|
||||||
{% if forloop.last %}
|
<i class="icon-remove"></i>
|
||||||
</table>
|
</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% if forloop.last %}
|
||||||
|
</table>
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endwith %}
|
||||||
|
|
||||||
<!-- 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 -->
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Log -->
|
<!-- Log -->
|
||||||
{% if perms.motion.can_manage_motion %}
|
{% 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',
|
name='motion_version_reject',
|
||||||
),
|
),
|
||||||
|
|
||||||
|
url(r'^(?P<pk>\d+)/diff/$',
|
||||||
|
'version_diff',
|
||||||
|
name='motion_version_diff',
|
||||||
|
),
|
||||||
|
|
||||||
url(r'^(?P<pk>\d+)/support/$',
|
url(r'^(?P<pk>\d+)/support/$',
|
||||||
'motion_support',
|
'motion_support',
|
||||||
name='motion_support',
|
name='motion_support',
|
||||||
|
@ -230,6 +230,38 @@ class VersionRejectView(GetVersionMixin, SingleObjectMixin, QuestionMixin, Redir
|
|||||||
version_reject = VersionRejectView.as_view()
|
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):
|
class SupportView(SingleObjectMixin, RedirectView):
|
||||||
"""View to support or unsupport a motion.
|
"""View to support or unsupport a motion.
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user