New temporal field for editing the final version of a motion.

This commit is contained in:
FinnStutzenstein 2018-07-13 10:08:18 +02:00
parent 15e4832d40
commit e073084f74
12 changed files with 258 additions and 22 deletions

View File

@ -15,9 +15,13 @@ Motions:
- New feature to customize workflows and states [#3772]. - New feature to customize workflows and states [#3772].
- New config options to show logos on the right side in PDF [#3768]. - New config options to show logos on the right side in PDF [#3768].
- New table of contents with page numbers and categories in PDF [#3766]. - New table of contents with page numbers and categories in PDF [#3766].
- Updated pdfMake to 0.1.37 [#3766]. - New teporal field "modified final version" where the final version can
be edited [#3781].
Core:
- Python 3.4 is not supported anymore [#3777]. - Python 3.4 is not supported anymore [#3777].
- Support Python 3.7. - Support Python 3.7.
- Updated pdfMake to 0.1.37 [#3766].
Version 2.2 (2018-06-06) Version 2.2 (2018-06-06)

View File

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.10.8 on 2018-07-13 08:02
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('motions', '0008_auto_20180702_1128'),
]
operations = [
migrations.AddField(
model_name='motionversion',
name='modified_final_version',
field=models.TextField(blank=True, null=True),
),
]

View File

@ -214,9 +214,10 @@ class Motion(RESTModelMixin, models.Model):
* Else the given version is used. * Else the given version is used.
To create and use a new version object, you have to set it via the To create and use a new version object, you have to set it via the
use_version argument. You have to set the title, text/amendment_paragraphs and reason into use_version argument. You have to set the title, text/amendment_paragraphs,
this version object before giving it to this save method. The properties modified final version and reason into this version object before giving it
motion.title, motion.text, motion.amendment_paragraphs and motion.reason will be ignored. to this save method. The properties motion.title, motion.text,
motion.amendment_paragraphs, motion.modified_final_version and motion.reason will be ignored.
text and amendment_paragraphs are mutually exclusive; if both are given, text and amendment_paragraphs are mutually exclusive; if both are given,
amendment_paragraphs takes precedence. amendment_paragraphs takes precedence.
@ -264,8 +265,8 @@ class Motion(RESTModelMixin, models.Model):
return return
elif use_version is None: elif use_version is None:
use_version = self.get_last_version() use_version = self.get_last_version()
# Save title, text, amendment paragraphs and reason into the version object. # Save title, text, amendment paragraphs, modified final version and reason into the version object.
for attr in ['title', 'text', 'amendment_paragraphs', 'reason']: for attr in ['title', 'text', 'amendment_paragraphs', 'modified_final_version', 'reason']:
_attr = '_%s' % attr _attr = '_%s' % attr
data = getattr(self, _attr, None) data = getattr(self, _attr, None)
if data is not None: if data is not None:
@ -318,7 +319,8 @@ class Motion(RESTModelMixin, models.Model):
""" """
Compare the version with the last version of the motion. Compare the version with the last version of the motion.
Returns True if the version data (title, text, reason) is different, Returns True if the version data (title, text, amendment_paragraphs,
modified_final_version, reason) is different,
else returns False. else returns False.
""" """
if not self.versions.exists(): if not self.versions.exists():
@ -326,7 +328,7 @@ class Motion(RESTModelMixin, models.Model):
return True return True
last_version = self.get_last_version() last_version = self.get_last_version()
for attr in ['title', 'text', 'amendment_paragraphs', 'reason']: for attr in ['title', 'text', 'amendment_paragraphs', 'modified_final_version', 'reason']:
if getattr(last_version, attr) != getattr(version, attr): if getattr(last_version, attr) != getattr(version, attr):
return True return True
return False return False
@ -494,6 +496,32 @@ class Motion(RESTModelMixin, models.Model):
Is saved in a MotionVersion object. Is saved in a MotionVersion object.
""" """
def get_modified_final_version(self):
"""
Get the modified_final_version of the motion.
Simular to get_title().
"""
try:
return self._modified_final_version
except AttributeError:
return self.get_active_version().modified_final_version
def set_modified_final_version(self, modified_final_version):
"""
Set the modified_final_version of the motion.
Simular to set_title().
"""
self._modified_final_version = modified_final_version
modified_final_version = property(get_modified_final_version, set_modified_final_version)
"""
The modified_final_version for the motion.
Is saved in a MotionVersion object.
"""
def get_reason(self): def get_reason(self):
""" """
Get the reason of the motion. Get the reason of the motion.
@ -525,8 +553,9 @@ class Motion(RESTModelMixin, models.Model):
Return a version object, not saved in the database. Return a version object, not saved in the database.
The version data of the new version object is populated with the data The version data of the new version object is populated with the data
set via motion.title, motion.text, motion.amendment_paragraphs and motion.reason if these data are set via motion.title, motion.text, motion.amendment_paragraphs,
not given as keyword arguments. If the data is not set in the motion motion.modified_final_version and motion.reason if these data are not
given as keyword arguments. If the data is not set in the motion
attributes, it is populated with the data from the last version attributes, it is populated with the data from the last version
object if such object exists. object if such object exists.
""" """
@ -539,7 +568,7 @@ class Motion(RESTModelMixin, models.Model):
last_version = self.get_last_version() last_version = self.get_last_version()
else: else:
last_version = None last_version = None
for attr in ['title', 'text', 'amendment_paragraphs', 'reason']: for attr in ['title', 'text', 'amendment_paragraphs', 'modified_final_version', 'reason']:
if attr in kwargs: if attr in kwargs:
continue continue
_attr = '_%s' % attr _attr = '_%s' % attr
@ -840,6 +869,9 @@ class MotionVersion(RESTModelMixin, models.Model):
amendment_paragraphs and text are mutually exclusive. amendment_paragraphs and text are mutually exclusive.
""" """
modified_final_version = models.TextField(null=True, blank=True)
"""A field to copy in the final version of the motion and edit it there."""
reason = models.TextField(null=True, blank=True) reason = models.TextField(null=True, blank=True)
"""The reason for a motion.""" """The reason for a motion."""

View File

@ -317,6 +317,7 @@ class MotionVersionSerializer(ModelSerializer):
'title', 'title',
'text', 'text',
'amendment_paragraphs', 'amendment_paragraphs',
'modified_final_version',
'reason',) 'reason',)
@ -369,6 +370,7 @@ class MotionSerializer(ModelSerializer):
comments = MotionCommentsJSONSerializerField(required=False) comments = MotionCommentsJSONSerializerField(required=False)
log_messages = MotionLogSerializer(many=True, read_only=True) log_messages = MotionLogSerializer(many=True, read_only=True)
polls = MotionPollSerializer(many=True, read_only=True) polls = MotionPollSerializer(many=True, read_only=True)
modified_final_version = CharField(allow_blank=True, required=False, write_only=True)
reason = CharField(allow_blank=True, required=False, write_only=True) reason = CharField(allow_blank=True, required=False, write_only=True)
state_required_permission_to_see = SerializerMethodField() state_required_permission_to_see = SerializerMethodField()
text = CharField(write_only=True, allow_blank=True) text = CharField(write_only=True, allow_blank=True)
@ -392,6 +394,7 @@ class MotionSerializer(ModelSerializer):
'title', 'title',
'text', 'text',
'amendment_paragraphs', 'amendment_paragraphs',
'modified_final_version',
'reason', 'reason',
'versions', 'versions',
'active_version', 'active_version',
@ -419,6 +422,9 @@ class MotionSerializer(ModelSerializer):
if 'text'in data: if 'text'in data:
data['text'] = validate_html(data['text']) data['text'] = validate_html(data['text'])
if 'modified_final_version' in data:
data['modified_final_version'] = validate_html(data['modified_final_version'])
if 'reason' in data: if 'reason' in data:
data['reason'] = validate_html(data['reason']) data['reason'] = validate_html(data['reason'])
@ -451,6 +457,7 @@ class MotionSerializer(ModelSerializer):
motion.title = validated_data['title'] motion.title = validated_data['title']
motion.text = validated_data['text'] motion.text = validated_data['text']
motion.amendment_paragraphs = validated_data.get('amendment_paragraphs') motion.amendment_paragraphs = validated_data.get('amendment_paragraphs')
motion.modified_final_version = validated_data.get('modified_final_version', '')
motion.reason = validated_data.get('reason', '') motion.reason = validated_data.get('reason', '')
motion.identifier = validated_data.get('identifier') motion.identifier = validated_data.get('identifier')
motion.category = validated_data.get('category') motion.category = validated_data.get('category')
@ -489,8 +496,8 @@ class MotionSerializer(ModelSerializer):
else: else:
version = motion.get_last_version() version = motion.get_last_version()
# Title, text, reason. # Title, text, reason, ...
for key in ('title', 'text', 'amendment_paragraphs', 'reason'): for key in ('title', 'text', 'amendment_paragraphs', 'modified_final_version', 'reason'):
if key in validated_data.keys(): if key in validated_data.keys():
setattr(version, key, validated_data[key]) setattr(version, key, validated_data[key])

View File

@ -322,7 +322,8 @@ angular.module('OpenSlidesApp.motions', [
if (titleChange) { if (titleChange) {
if (changeRecommendationMode === "changed") { if (changeRecommendationMode === "changed") {
title = titleChange.text; title = titleChange.text;
} else if (changeRecommendationMode === 'agreed' && !titleChange.rejected) { } else if ((changeRecommendationMode === 'agreed' ||
changeRecommendationMode === 'modified_agreed') && !titleChange.rejected) {
title = titleChange.text; title = titleChange.text;
} else { } else {
title = this.getTitle(); title = this.getTitle();
@ -349,6 +350,12 @@ angular.module('OpenSlidesApp.motions', [
return lineNumberingService.insertLineNumbers(html, lineLength, highlight, callback); return lineNumberingService.insertLineNumbers(html, lineLength, highlight, callback);
}, },
getModifiedFinalVersionWithLineBreaks: function (versionId) {
var lineLength = Config.get('motions_line_length').value,
html = this.getVersion(versionId).modified_final_version;
return lineNumberingService.insertLineNumbers(html, lineLength);
},
getTextBetweenChanges: function (versionId, change1, change2, highlight) { getTextBetweenChanges: function (versionId, change1, change2, highlight) {
var line_from = (change1 ? change1.line_to : 1), var line_from = (change1 ? change1.line_to : 1),
line_to = (change2 ? change2.line_from : null); line_to = (change2 ? change2.line_from : null);
@ -490,7 +497,7 @@ angular.module('OpenSlidesApp.motions', [
}, },
getTextByMode: function(mode, versionId, highlight, lineBreaks) { getTextByMode: function(mode, versionId, highlight, lineBreaks) {
/* /*
* @param mode ['original', 'diff', 'changed', 'agreed'] * @param mode ['original', 'diff', 'changed', 'agreed', 'modified_agreed']
* @param versionId [if undefined, active_version will be used] * @param versionId [if undefined, active_version will be used]
* @param highlight [the line number to highlight] * @param highlight [the line number to highlight]
* @param lineBreaks [if line numbers / breaks should be included in the result] * @param lineBreaks [if line numbers / breaks should be included in the result]
@ -547,6 +554,17 @@ angular.module('OpenSlidesApp.motions', [
case 'agreed': case 'agreed':
text = this.getTextWithAgreedChanges(versionId, highlight, lineBreaks); text = this.getTextWithAgreedChanges(versionId, highlight, lineBreaks);
break; break;
case 'modified_agreed':
text = this.getModifiedFinalVersion(versionId);
if (text) {
// Insert line numbers
var lineLength = Config.get('motions_line_length').value;
text = lineNumberingService.insertLineNumbers(text, lineLength);
} else {
// Use the agreed version as fallback
text = this.getTextByMode('agreed', versionId, highlight, lineBreaks);
}
break;
} }
return text; return text;
}, },
@ -855,6 +873,17 @@ angular.module('OpenSlidesApp.motions', [
setTextStrippingLineBreaks: function (text) { setTextStrippingLineBreaks: function (text) {
this.text = lineNumberingService.stripLineNumbers(text); this.text = lineNumberingService.stripLineNumbers(text);
}, },
setModifiedFinalVersionStrippingLineBreaks: function (html) {
this.modified_final_version = lineNumberingService.stripLineNumbers(html);
},
// Copies to final version to the modified_final_version field
copyModifiedFinalVersionStrippingLineBreaks: function () {
var finalVersion = this.getTextByMode('agreed');
this.setModifiedFinalVersionStrippingLineBreaks(finalVersion);
},
getModifiedFinalVersion: function (versionId) {
return this.getVersion(versionId).modified_final_version;
},
getReason: function (versionId) { getReason: function (versionId) {
return this.getVersion(versionId).reason; return this.getVersion(versionId).reason;
}, },
@ -1457,6 +1486,7 @@ angular.module('OpenSlidesApp.motions', [
// Properties that are guaranteed to be constant // Properties that are guaranteed to be constant
this._change_object = { this._change_object = {
"type": "recommendation", "type": "recommendation",
"other_description": recommendation.other_description,
"id": "recommendation-" + recommendation.id, "id": "recommendation-" + recommendation.id,
"original": recommendation, "original": recommendation,
"saveStatus": function () { "saveStatus": function () {

View File

@ -472,6 +472,54 @@ angular.module('OpenSlidesApp.motions.motionservices', ['OpenSlidesApp.motions',
}); });
}; };
obj.copyToModifiedFinalVersion = function (motion, version) {
if (!motion.isAllowed('update')) {
throw 'No permission to update motion';
}
motion.copyModifiedFinalVersionStrippingLineBreaks();
Motion.inject(motion);
// save change motion object on server
Motion.save(motion, {method: 'PATCH'}).then(null, function (error) {
// save error: revert all changes by restore
// (refresh) original motion object from server
Motion.refresh(motion);
var message = '';
for (var e in error.data) {
message += e + ': ' + error.data[e] + ' ';
}
$scope.alert = {type: 'danger', msg: message, show: true};
});
};
obj.deleteModifiedFinalVersion = function (motion, version) {
if (!motion.isAllowed('update')) {
throw 'No permission to update motion';
}
if (!motion.getModifiedFinalVersion(version)) {
return;
}
motion.modified_final_version = '';
Motion.inject(motion);
// save change motion object on server
Motion.save(motion, {method: 'PATCH'}).then(function (success) {
$scope.viewChangeRecommendations.mode = 'agreed';
}, function (error) {
// save error: revert all changes by restore
// (refresh) original motion object from server
Motion.refresh(motion);
var message = '';
for (var e in error.data) {
message += e + ': ' + error.data[e] + ' ';
}
$scope.alert = {type: 'danger', msg: message, show: true};
});
};
obj.newVersionIncludingChanges = function (motion, version) { obj.newVersionIncludingChanges = function (motion, version) {
if (!motion.isAllowed('update')) { if (!motion.isAllowed('update')) {
throw 'No permission to update motion'; throw 'No permission to update motion';

View File

@ -252,7 +252,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
} }
// summary of change recommendations (for motion diff version only) // summary of change recommendations (for motion diff version only)
if (params.changeRecommendationMode === "diff" && motion.changeRecommendations.length) { if (params.changeRecommendationMode === 'diff' && motion.changeRecommendations.length) {
var columnLineNumbers = []; var columnLineNumbers = [];
var columnChangeType = []; var columnChangeType = [];
angular.forEach(_.orderBy(motion.changeRecommendations, ['line_from']), function(change) { angular.forEach(_.orderBy(motion.changeRecommendations, ['line_from']), function(change) {

View File

@ -938,7 +938,7 @@ angular.module('OpenSlidesApp.motions.site', [
{name: gettextCatalog.getString('Original version'), value: 'original'}, {name: gettextCatalog.getString('Original version'), value: 'original'},
{name: gettextCatalog.getString('Changed version'), value: 'changed'}, {name: gettextCatalog.getString('Changed version'), value: 'changed'},
{name: gettextCatalog.getString('Diff version'), value: 'diff'}, {name: gettextCatalog.getString('Diff version'), value: 'diff'},
{name: gettextCatalog.getString('Final version'), value: 'agreed'}, {name: gettextCatalog.getString('Final version'), value: 'modified_agreed'},
], ],
}, },
hideExpression: "model.format !== 'pdf'", hideExpression: "model.format !== 'pdf'",
@ -952,7 +952,7 @@ angular.module('OpenSlidesApp.motions.site', [
{name: gettextCatalog.getString('Original version'), value: 'original'}, {name: gettextCatalog.getString('Original version'), value: 'original'},
{name: gettextCatalog.getString('Changed version'), value: 'changed'}, {name: gettextCatalog.getString('Changed version'), value: 'changed'},
{name: gettextCatalog.getString('Diff version'), value: 'diff', disabled: true}, {name: gettextCatalog.getString('Diff version'), value: 'diff', disabled: true},
{name: gettextCatalog.getString('Final version'), value: 'agreed'}, {name: gettextCatalog.getString('Final version'), value: 'modified_agreed'},
], ],
}, },
hideExpression: "model.format === 'pdf'", hideExpression: "model.format === 'pdf'",
@ -1078,6 +1078,11 @@ angular.module('OpenSlidesApp.motions.site', [
}, },
includeComments: {}, includeComments: {},
}); });
// Always change the mode from agreed to modified_agreed. If a motion does not have a modified
// final version, the agreed will be taken.
if ($scope.params.changeRecommendationMode === 'agreed') {
$scope.params.changeRecommendationMode = 'modified_agreed';
}
$scope.motions = motions; $scope.motions = motions;
$scope.singleMotion = singleMotion; $scope.singleMotion = singleMotion;
@ -1614,10 +1619,16 @@ angular.module('OpenSlidesApp.motions.site', [
label: 'Diff version'}, label: 'Diff version'},
{mode: 'agreed', {mode: 'agreed',
label: 'Final version'}, label: 'Final version'},
{mode: 'modified_agreed',
label: 'Modified final version'},
]; ];
var motionDefaultTextMode = Config.get('motions_recommendation_text_mode').value; var motionDefaultRecommendationTextMode = Config.get('motions_recommendation_text_mode').value;
// Change to the modified final version, if exists
if (motionDefaultRecommendationTextMode === 'agreed' && motion.getModifiedFinalVersion()) {
motionDefaultRecommendationTextMode = 'modified_agreed';
}
$scope.projectionMode = _.find($scope.projectionModes, function (mode) { $scope.projectionMode = _.find($scope.projectionModes, function (mode) {
return mode.mode == motionDefaultTextMode; return mode.mode == motionDefaultRecommendationTextMode;
}); });
if (motion.isProjected().length) { if (motion.isProjected().length) {
var modeMapping = motion.isProjectedWithMode(); var modeMapping = motion.isProjectedWithMode();
@ -1919,6 +1930,17 @@ angular.module('OpenSlidesApp.motions.site', [
Config.get('motions_allow_disable_versioning').value); Config.get('motions_allow_disable_versioning').value);
} }
); );
$scope.modifiedFinalVersionInlineEditing = MotionInlineEditing.createInstance($scope, motion,
'view-modified-agreed-inline-editor', true, Editor.getOptions('inline'),
function (obj) {
return motion.getModifiedFinalVersionWithLineBreaks($scope.version);
},
function (obj) {
motion.setModifiedFinalVersionStrippingLineBreaks(obj.editor.getData());
motion.disable_versioning = (obj.trivialChange &&
Config.get('motions_allow_disable_versioning').value);
}
);
// Wrapper functions for $scope.inlineEditing, to warn other users. // Wrapper functions for $scope.inlineEditing, to warn other users.
var editingStoppedCallback; var editingStoppedCallback;
$scope.enableMotionInlineEditing = function () { $scope.enableMotionInlineEditing = function () {
@ -1978,7 +2000,7 @@ angular.module('OpenSlidesApp.motions.site', [
// Change recommendation and amendment viewing // Change recommendation and amendment viewing
$scope.viewChangeRecommendations = ChangeRecommendationView; $scope.viewChangeRecommendations = ChangeRecommendationView;
$scope.viewChangeRecommendations.initSite($scope, motion, Config.get('motions_recommendation_text_mode').value); $scope.viewChangeRecommendations.initSite($scope, motion, motionDefaultRecommendationTextMode);
// PDF creating functions // PDF creating functions
$scope.pdfExport = function () { $scope.pdfExport = function () {
@ -2083,6 +2105,7 @@ angular.module('OpenSlidesApp.motions.site', [
function ($scope, MotionChangeRecommendation, ChangeRecommendationTextForm, diffService, change, ErrorMessage) { function ($scope, MotionChangeRecommendation, ChangeRecommendationTextForm, diffService, change, ErrorMessage) {
$scope.alert = {}; $scope.alert = {};
$scope.model = angular.copy(change); $scope.model = angular.copy(change);
$scope.model._change_object = undefined;
// get all form fields // get all form fields
$scope.formFields = ChangeRecommendationTextForm.getFormFields(change.line_from, change.line_to); $scope.formFields = ChangeRecommendationTextForm.getFormFields(change.line_from, change.line_to);

View File

@ -555,6 +555,15 @@
<div ng-bind-html="motion.getTextByMode('agreed', version, highlight) | trusted" <div ng-bind-html="motion.getTextByMode('agreed', version, highlight) | trusted"
class="motion-text motion-text-changed line-numbers-{{ lineNumberMode }}"></div> class="motion-text motion-text-changed line-numbers-{{ lineNumberMode }}"></div>
<div style="text-align: right;" ng-if="(change_recommendations | filter:{motion_version_id:version}:true).length > 0">
<button class="btn btn-default"
ng-bootbox-confirm="{{ 'Do you want to copy the final version to the modified final version field?' | translate }}"
ng-bootbox-confirm-action="viewChangeRecommendations.copyToModifiedFinalVersion(motion, version)">
<i class="fa fa-file-text"></i>
<translate>Copy to modified final version</translate>
</button>
</div>
<div style="text-align: right;" ng-if="motion.state.versioning && (change_recommendations | filter:{motion_version_id:version}:true).length > 0"> <div style="text-align: right;" ng-if="motion.state.versioning && (change_recommendations | filter:{motion_version_id:version}:true).length > 0">
<button class="btn btn-default" <button class="btn btn-default"
ng-bootbox-confirm="{{ 'Do you want to create a new version of this motion based on this changes?' | translate }}" ng-bootbox-confirm="{{ 'Do you want to create a new version of this motion based on this changes?' | translate }}"
@ -564,6 +573,10 @@
</button> </button>
</div> </div>
</div> </div>
<!-- modified agreed view -->
<ng-include src="'static/templates/motions/motion-detail/view-modified-agreed.html'"></ng-include>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<div class="motion-toolbar"> <div class="motion-toolbar">
<!-- inline editing --> <!-- inline editing for original mode -->
<div class="pull-right inline-editing-activator" <div class="pull-right inline-editing-activator"
ng-if="motion.isAllowed('update') && version == motion.getVersion(-1).id && viewChangeRecommendations.mode == 'original'"> ng-if="motion.isAllowed('update') && version == motion.getVersion(-1).id && viewChangeRecommendations.mode == 'original'">
<button ng-if="!inlineEditing.active && !has_proposed_changes" ng-click="enableMotionInlineEditing()" <button ng-if="!inlineEditing.active && !has_proposed_changes" ng-click="enableMotionInlineEditing()"
@ -19,6 +19,23 @@
</button> </button>
</div> </div>
<!-- inline editing for modified agreed view -->
<div class="pull-right inline-editing-activator"
ng-if="motion.isAllowed('update') && version == motion.getVersion(-1).id && viewChangeRecommendations.mode == 'modified_agreed'">
<button ng-if="!modifiedFinalVersionInlineEditing.active"
ng-click="modifiedFinalVersionInlineEditing.enable()"
class="btn btn-sm btn-default">
<i class="fa fa-pencil-square-o"></i>
<translate>Inline editing</translate>
</button>
<button ng-if="modifiedFinalVersionInlineEditing.active"
ng-click="modifiedFinalVersionInlineEditing.disable()"
class="btn btn-sm btn-default">
<i class="fa fa-times-circle"></i>
<translate>Inline editing</translate>
</button>
</div>
<div class="toolbar-left {{ lineNumberMode }}"> <div class="toolbar-left {{ lineNumberMode }}">
<ng-include src="'static/templates/motions/motion-detail/toolbar-line-numbering.html'"></ng-include> <ng-include src="'static/templates/motions/motion-detail/toolbar-line-numbering.html'"></ng-include>
@ -86,6 +103,14 @@
ng-checked="viewChangeRecommendations.mode == 'agreed'"> ng-checked="viewChangeRecommendations.mode == 'agreed'">
<translate>Final version</translate> <translate>Final version</translate>
</label> </label>
<label class="btn btn-sm btn-default" ng-if="motion.getModifiedFinalVersion()"
ng-class="{active: (viewChangeRecommendations.mode == 'modified_agreed')}"
ng-click="viewChangeRecommendations.mode = 'modified_agreed'">
<input type="radio" name="viewChangeRecommendations.mode" value="modified_agreed"
ng-model="viewChangeRecommendations.mode"
ng-checked="viewChangeRecommendations.mode == 'modified_agreed'">
<translate>Modified final version</translate>
</label>
</div> </div>
<!-- change recommendations for resonsive size small/extra small (dropdown) --> <!-- change recommendations for resonsive size small/extra small (dropdown) -->

View File

@ -0,0 +1,28 @@
<!-- Modified agreed view -->
<div ng-if="viewChangeRecommendations.mode == 'modified_agreed'">
<div id="view-modified-agreed-inline-editor" ng-bind-html="motion.getModifiedFinalVersionWithLineBreaks(version) | trusted"
class="motion-text motion-text-original line-numbers-{{ lineNumberMode }}"
contenteditable="{{ modifiedFinalVersionInlineEditing.isEditable }}">
</div>
<div style="text-align: right;">
<button class="btn btn-default btn-danger"
ng-bootbox-confirm="{{ 'Do you want to delete the modified final version?' | translate }}"
ng-bootbox-confirm-action="viewChangeRecommendations.deleteModifiedFinalVersion(motion, version)">
<i class="fa fa-trash"></i>
<translate>Delete modified final version</translate>
</button>
</div>
<div class="motion-save-toolbar" ng-class="{ 'visible': modifiedFinalVersionInlineEditing.active && modifiedFinalVersionInlineEditing.changed }">
<div class="changed-hint" translate>The modified final version have been changed.</div>
<button type="button" ng-click="modifiedFinalVersionInlineEditing.save()" class="btn btn-primary" translate>
Save
</button>
<button type="button" ng-click="modifiedFinalVersionInlineEditing.revert()" class="btn btn-default" translate>
Revert
</button>
<label ng-if="motion.state.versioning && config('motions_allow_disable_versioning')">
<input type="checkbox" ng-model="modifiedFinalVersionInlineEditing.trivialChange" value="1">
<span translate>Trivial change</span>
</label>
</div>
</div>

View File

@ -140,6 +140,12 @@
class="motion-text motion-text-changed line-numbers-{{ config('motions_default_line_numbering') }}"></div> class="motion-text motion-text-changed line-numbers-{{ config('motions_default_line_numbering') }}"></div>
</div> </div>
<!-- Modified agreed View -->
<div ng-if="mode == 'modified_agreed'">
<div ng-bind-html="motion.getTextByMode('modified_agreed', null, line) | trusted"
class="motion-text motion-text-changed line-numbers-{{ config('motions_default_line_numbering') }}"></div>
</div>
<!-- Reason --> <!-- Reason -->
<div ng-if="motion.getReason() && !config('motions_disable_reason_on_projector')"> <div ng-if="motion.getReason() && !config('motions_disable_reason_on_projector')">
<h3 translate>Reason</h3> <h3 translate>Reason</h3>