Merge pull request #3494 from FinnStutzenstein/Exportdialog
Extended exportdialog
This commit is contained in:
commit
44b0f14f65
@ -788,8 +788,9 @@ angular.module('OpenSlidesApp.core.site', [
|
||||
overwriteOk: true,
|
||||
});
|
||||
formlyConfig.setType({
|
||||
name: 'select-radio',
|
||||
templateUrl: 'static/templates/core/select-radio.html',
|
||||
name: 'checkbox-buttons',
|
||||
templateUrl: 'static/templates/core/checkbox-buttons.html',
|
||||
overwriteOk: true,
|
||||
});
|
||||
formlyConfig.setType({
|
||||
name: 'select-single',
|
||||
|
14
openslides/core/static/templates/core/checkbox-buttons.html
Normal file
14
openslides/core/static/templates/core/checkbox-buttons.html
Normal file
@ -0,0 +1,14 @@
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<label class="control-label" ng-if="to.label">
|
||||
{{ to.label }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<label ng-repeat="option in to.options" class="btn btn-default btn-sm" uib-btn-checkbox
|
||||
ng-model="model[options.key][option.id]"
|
||||
ng-disabled="option.disabled">
|
||||
{{ option.name | translate }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
@ -1,6 +1,17 @@
|
||||
<div class="btn-group" data-toggle="buttons">
|
||||
<label ng-repeat="(key, option) in to.options" ng-click="model[options.key] = option.value;"
|
||||
class="btn btn-default btn-sm" ng-class="{active: (model[options.key] == option.value)}">
|
||||
<input type="radio" tabindex="0" ng-value="option.value" ng-model="model[options.key]">{{option.name}}
|
||||
<div class="form-group">
|
||||
<div ng-if="to.label">
|
||||
<label class="control-label">
|
||||
{{ to.label | translate }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<label ng-repeat="option in to.options" class="btn btn-default btn-sm"
|
||||
ng-class="{active: (model[options.key] === option.value)}"
|
||||
ng-disabled="option.disabled">
|
||||
<input type="radio" ng-value="option.value"
|
||||
ng-model="model[options.key]" ng-checked="model[options.key] === option.value"
|
||||
ng-disabled="option.disabled" ng-change="to.change(option.value)">
|
||||
{{ option.name | translate }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,17 +0,0 @@
|
||||
<div class="form-group">
|
||||
<div>
|
||||
<label class="control-label" ng-if="to.label">
|
||||
{{ to.label }}
|
||||
</label>
|
||||
</div>
|
||||
<div class="btn-group">
|
||||
<label ng-repeat="option in to.options" class="btn btn-default btn-sm"
|
||||
ng-class="{active: (model[options.key] === option.value)}"
|
||||
ng-disabled="option.disabled">
|
||||
<input type="radio" name="select-radio-{{ options.key }}" ng-value="option.value"
|
||||
ng-model="model[options.key]" ng-checked="model[options.key] === option.value"
|
||||
ng-disabled="option.disabled" ng-change="to.change(option.value)">
|
||||
{{ option.name | translate }}
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
@ -10,8 +10,30 @@ angular.module('OpenSlidesApp.motions.csv', [])
|
||||
'CsvDownload',
|
||||
'lineNumberingService',
|
||||
function (gettextCatalog, Config, CsvDownload, lineNumberingService) {
|
||||
var makeHeaderline = function () {
|
||||
var headerline = ['Identifier', 'Title', 'Text', 'Reason', 'Submitter', 'Category', 'Origin'];
|
||||
var makeHeaderline = function (params) {
|
||||
var headerline = ['Identifier', 'Title'];
|
||||
if (params.include.text) {
|
||||
headerline.push('Text');
|
||||
}
|
||||
if (params.include.reason) {
|
||||
headerline.push('Reason');
|
||||
}
|
||||
if (params.include.submitters) {
|
||||
headerline.push('Submitter');
|
||||
}
|
||||
headerline.push('Category');
|
||||
if (params.include.origin) {
|
||||
headerline.push('Origin');
|
||||
}
|
||||
if (params.include.motionBlock) {
|
||||
headerline.push('Motion block');
|
||||
}
|
||||
if (params.include.state) {
|
||||
headerline.push('State');
|
||||
}
|
||||
if (params.include.recommendation) {
|
||||
headerline.push('Recommendation');
|
||||
}
|
||||
return _.map(headerline, function (entry) {
|
||||
return gettextCatalog.getString(entry);
|
||||
});
|
||||
@ -24,41 +46,89 @@ angular.module('OpenSlidesApp.motions.csv', [])
|
||||
_.defaults(params, {
|
||||
filename: 'motions-export.csv',
|
||||
changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
|
||||
includeReason: true,
|
||||
include: {
|
||||
text: true,
|
||||
reason: true,
|
||||
submitters: true,
|
||||
origin: true,
|
||||
motionBlock: true,
|
||||
state: true,
|
||||
recommendation: true,
|
||||
},
|
||||
});
|
||||
if (!_.includes(['original', 'changed', 'agreed'], params.changeRecommendationMode)) {
|
||||
params.changeRecommendationMode = 'original';
|
||||
}
|
||||
|
||||
var csvRows = [
|
||||
makeHeaderline()
|
||||
makeHeaderline(params)
|
||||
];
|
||||
_.forEach(motions, function (motion) {
|
||||
var text = motion.getTextByMode(params.changeRecommendationMode, null, null, false);
|
||||
var row = [];
|
||||
// Identifier and title
|
||||
row.push('"' + motion.identifier !== null ? motion.identifier : '' + '"');
|
||||
row.push('"' + motion.getTitle() + '"');
|
||||
row.push('"' + text + '"');
|
||||
if (params.includeReason) {
|
||||
row.push('"' + motion.getReason() + '"');
|
||||
} else {
|
||||
row.push('""');
|
||||
|
||||
// Text
|
||||
if (params.include.text) {
|
||||
row.push('"' + text + '"');
|
||||
}
|
||||
var submitter = motion.submitters[0] ? motion.submitters[0].get_full_name() : '';
|
||||
row.push('"' + submitter + '"');
|
||||
|
||||
// Reason
|
||||
if (params.include.reason) {
|
||||
row.push('"' + motion.getReason() + '"');
|
||||
}
|
||||
|
||||
// Submitters
|
||||
if (params.include.submitters) {
|
||||
var submitters = motion.submitters[0] ? motion.submitters[0].get_full_name() : '';
|
||||
row.push('"' + submitters + '"');
|
||||
}
|
||||
|
||||
// Category
|
||||
var category = motion.category ? motion.category.name : '';
|
||||
row.push('"' + category + '"');
|
||||
row.push('"' + motion.origin + '"');
|
||||
|
||||
// Origin
|
||||
if (params.include.origin) {
|
||||
row.push('"' + motion.origin + '"');
|
||||
}
|
||||
|
||||
// Motion block
|
||||
if (params.include.motionBlock) {
|
||||
var blockTitle = motion.motionBlock ? motion.motionBlock.title : '';
|
||||
row.push('"' + blockTitle + '"');
|
||||
}
|
||||
|
||||
// State
|
||||
if (params.include.state) {
|
||||
row.push('"' + motion.getStateName() + '"');
|
||||
}
|
||||
|
||||
// Recommendation
|
||||
if (params.include.recommendation) {
|
||||
row.push('"' + motion.getRecommendationName() + '"');
|
||||
}
|
||||
|
||||
csvRows.push(row);
|
||||
});
|
||||
CsvDownload(csvRows, 'motions-export.csv');
|
||||
},
|
||||
downloadExample: function () {
|
||||
var csvRows = [makeHeaderline(),
|
||||
var csvRows = [makeHeaderline({ include: {
|
||||
text: true,
|
||||
reason: true,
|
||||
submitters: true,
|
||||
origin: true,
|
||||
motionBlock: true,
|
||||
state: true,
|
||||
recommendation: true,
|
||||
}}),
|
||||
// example entries
|
||||
['A1', 'Title 1', 'Text 1', 'Reason 1', 'Submitter A', 'Category A', 'Last Year Conference A'],
|
||||
['B1', 'Title 2', 'Text 2', 'Reason 2', 'Submitter B', 'Category B', ''],
|
||||
['' , 'Title 3', 'Text 3', '', '', '', ''],
|
||||
['A1', 'Title 1', 'Text 1', 'Reason 1', 'Submitter A', 'Category A', 'Last Year Conference A', 'Block A', 'permitted', ''],
|
||||
['B1', 'Title 2', 'Text 2', 'Reason 2', 'Submitter B', 'Category B', '', 'Block A', 'accepted', 'Acceptance'],
|
||||
['' , 'Title 3', 'Text 3', '', '', '', '', '', '', ''],
|
||||
];
|
||||
CsvDownload(csvRows, 'motions-example.csv');
|
||||
},
|
||||
|
@ -97,9 +97,9 @@ angular.module('OpenSlidesApp.motions.docx', ['OpenSlidesApp.core.docx'])
|
||||
var sequential_enabled = Config.get('motions_export_sequential_number').value;
|
||||
// promises for create the actual motion data
|
||||
var promises = _.map(motions, function (motion) {
|
||||
var text = motion.getTextByMode(params.changeRecommendationMode, null, null, false);
|
||||
var reason = params.includeReason ? motion.getReason() : '';
|
||||
var comments = params.includeComments ? getMotionComments(motion) : [];
|
||||
var text = params.include.text ? motion.getTextByMode(params.changeRecommendationMode, null, null, false) : '';
|
||||
var reason = params.include.reason ? motion.getReason() : '';
|
||||
var comments = getMotionComments(motion, params.includeComments);
|
||||
|
||||
// Data for one motions. Must include translations, ...
|
||||
var motionData = {
|
||||
@ -115,9 +115,9 @@ angular.module('OpenSlidesApp.motions.docx', ['OpenSlidesApp.core.docx'])
|
||||
id: motion.id,
|
||||
identifier: motion.identifier,
|
||||
title: motion.getTitle(),
|
||||
submitters: _.map(motion.submitters, function (submitter) {
|
||||
submitters: params.include.submitters ? _.map(motion.submitters, function (submitter) {
|
||||
return submitter.get_full_name();
|
||||
}).join(', '),
|
||||
}).join(', ') : '',
|
||||
status: motion.getStateName(),
|
||||
// Miscellaneous stuff
|
||||
preamble: gettextCatalog.getString(Config.get('motions_preamble').value),
|
||||
@ -154,13 +154,13 @@ angular.module('OpenSlidesApp.motions.docx', ['OpenSlidesApp.core.docx'])
|
||||
});
|
||||
};
|
||||
|
||||
var getMotionComments = function (motion) {
|
||||
var getMotionComments = function (motion, fieldsIncluded) {
|
||||
var fields = MotionComment.getNoSpecialCommentsFields();
|
||||
var comments = [];
|
||||
_.forEach(fields, function (field, id) {
|
||||
if (motion.comments[id]) {
|
||||
var title = gettextCatalog.getString('Comment') + ' ' + field.name;
|
||||
if (!field.public) {
|
||||
_.forEach(fieldsIncluded, function (ok, id) {
|
||||
if (ok && motion.comments[id]) {
|
||||
var title = fields[id].name;
|
||||
if (!fields[id].public) {
|
||||
title += ' (' + gettextCatalog.getString('internal') + ')';
|
||||
}
|
||||
var comment = motion.comments[id];
|
||||
@ -179,14 +179,16 @@ angular.module('OpenSlidesApp.motions.docx', ['OpenSlidesApp.core.docx'])
|
||||
return {
|
||||
export: function (motions, params) {
|
||||
converter = Html2DocxConverter.createInstance();
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
params = _.clone(params || {}); // Clone this to avoid sideeffects.
|
||||
_.defaults(params, {
|
||||
filename: 'motions-export.docx',
|
||||
changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
|
||||
includeReason: true,
|
||||
includeComments: false,
|
||||
include: {
|
||||
text: true,
|
||||
reason: true,
|
||||
submitters: true,
|
||||
},
|
||||
includeComments: {},
|
||||
});
|
||||
if (!_.includes(['original', 'changed', 'agreed'], params.changeRecommendationMode)) {
|
||||
params.changeRecommendationMode = 'original';
|
||||
|
@ -23,24 +23,36 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
var createInstance = function(motion, motionVersion, changeRecommendationMode,
|
||||
changeRecommendations, lineNumberMode, includeReason, includeComments) {
|
||||
var createInstance = function(motion, motionVersion, params) {
|
||||
params = _.clone(params || {}); // Clone this to avoid sideeffects.
|
||||
_.defaults(params, {
|
||||
changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
|
||||
lineNumberMode: Config.get('motions_default_line_numbering').value,
|
||||
include: {
|
||||
text: true,
|
||||
reason: true,
|
||||
state: true,
|
||||
submitters: true,
|
||||
votingresult: true,
|
||||
motionBlock: true,
|
||||
origin: true,
|
||||
recommendation: true,
|
||||
},
|
||||
includeComments: {},
|
||||
});
|
||||
|
||||
var converter;
|
||||
|
||||
// Query all image sources from motion text and reason
|
||||
var getImageSources = function () {
|
||||
var text = motion.getTextByMode(changeRecommendationMode, null);
|
||||
var text = motion.getTextByMode(params.changeRecommendationMode, null);
|
||||
var reason = motion.getReason();
|
||||
var comments = '';
|
||||
if (includeComments) {
|
||||
var fields = MotionComment.getNoSpecialCommentsFields();
|
||||
_.forEach(fields, function (field, id) {
|
||||
if (motion.comments[id]) {
|
||||
comments += HTMLValidizer.validize(motion.comments[id]);
|
||||
}
|
||||
});
|
||||
}
|
||||
_.forEach(params.includeComments, function (ok, id) {
|
||||
if (ok && motion.comments[id]) {
|
||||
comments += HTMLValidizer.validize(motion.comments[id]);
|
||||
}
|
||||
});
|
||||
var content = HTMLValidizer.validize(text) + HTMLValidizer.validize(motion.getReason()) + comments;
|
||||
var map = Function.prototype.call.bind([].map);
|
||||
return map($(content).find('img'), function(element) {
|
||||
@ -77,31 +89,35 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
var submitters = _.map(motion.submitters, function (submitter) {
|
||||
return submitter.get_full_name();
|
||||
}).join(', ');
|
||||
metaTableBody.push([
|
||||
{
|
||||
text: gettextCatalog.getString('Submitters') + ':',
|
||||
style: ['bold', 'grey'],
|
||||
},
|
||||
{
|
||||
text: submitters,
|
||||
style: 'grey'
|
||||
}
|
||||
]);
|
||||
if (params.include.submitters) {
|
||||
metaTableBody.push([
|
||||
{
|
||||
text: gettextCatalog.getString('Submitters') + ':',
|
||||
style: ['bold', 'grey'],
|
||||
},
|
||||
{
|
||||
text: submitters,
|
||||
style: 'grey'
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// state
|
||||
metaTableBody.push([
|
||||
{
|
||||
text: gettextCatalog.getString('State') + ':',
|
||||
style: ['bold', 'grey']
|
||||
},
|
||||
{
|
||||
text: motion.getStateName(),
|
||||
style: 'grey'
|
||||
}
|
||||
]);
|
||||
if (params.include.state) {
|
||||
metaTableBody.push([
|
||||
{
|
||||
text: gettextCatalog.getString('State') + ':',
|
||||
style: ['bold', 'grey']
|
||||
},
|
||||
{
|
||||
text: motion.getStateName(),
|
||||
style: 'grey'
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// recommendation
|
||||
if (motion.getRecommendationName()) {
|
||||
if (params.include.recommendation && motion.getRecommendationName()) {
|
||||
metaTableBody.push([
|
||||
{
|
||||
text: Config.get('motions_recommendations_by').value + ':',
|
||||
@ -128,7 +144,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
}
|
||||
|
||||
// motion block
|
||||
if (motion.motionBlock) {
|
||||
if (params.include.motionBlock && motion.motionBlock) {
|
||||
metaTableBody.push([
|
||||
{
|
||||
text: gettextCatalog.getString('Motion block') + ':',
|
||||
@ -139,8 +155,22 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// origin
|
||||
if (params.include.origin && motion.origin) {
|
||||
metaTableBody.push([
|
||||
{
|
||||
text: gettextCatalog.getString('Origin') + ':',
|
||||
style: ['bold', 'grey'] },
|
||||
{
|
||||
text: motion.origin,
|
||||
style: 'grey'
|
||||
}
|
||||
]);
|
||||
}
|
||||
|
||||
// voting result
|
||||
if (motion.polls.length > 0 && motion.polls[0].has_votes) {
|
||||
if (params.include.votingresult && motion.polls.length > 0 && motion.polls[0].has_votes) {
|
||||
var column1 = [];
|
||||
var column2 = [];
|
||||
var column3 = [];
|
||||
@ -219,10 +249,10 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
}
|
||||
|
||||
// summary of change recommendations (for motion diff version only)
|
||||
if (changeRecommendationMode == "diff" && changeRecommendations.length) {
|
||||
if (params.changeRecommendationMode == "diff" && motion.changeRecommendations.length) {
|
||||
var columnLineNumbers = [];
|
||||
var columnChangeType = [];
|
||||
angular.forEach(_.orderBy(changeRecommendations, ['line_from']), function(change) {
|
||||
angular.forEach(_.orderBy(motion.changeRecommendations, ['line_from']), function(change) {
|
||||
// line numbers column
|
||||
var line;
|
||||
if (change.line_from >= change.line_to - 1) {
|
||||
@ -264,47 +294,57 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
]);
|
||||
}
|
||||
|
||||
// build table
|
||||
// Used placeholder for 'layout' functions whiche are
|
||||
// replaced by lineWitdh/lineColor function in pfd-worker.js.
|
||||
// TODO: Remove placeholder and us static values for LineWidth and LineColor
|
||||
// if pdfmake has fixed this.
|
||||
var metaTableJsonString = {
|
||||
table: {
|
||||
widths: ['35%','65%'],
|
||||
body: metaTableBody,
|
||||
},
|
||||
margin: [0, 0, 0, 20],
|
||||
layout: '{{motion-placeholder-to-insert-functions-here}}'
|
||||
};
|
||||
return metaTableJsonString;
|
||||
if (metaTableBody.length) {
|
||||
// build table
|
||||
// Used placeholder for 'layout' functions whiche are
|
||||
// replaced by lineWitdh/lineColor function in pfd-worker.js.
|
||||
// TODO: Remove placeholder and us static values for LineWidth and LineColor
|
||||
// if pdfmake has fixed this.
|
||||
var metaTable = {
|
||||
table: {
|
||||
widths: ['35%','65%'],
|
||||
body: metaTableBody,
|
||||
},
|
||||
margin: [0, 0, 0, 20],
|
||||
layout: '{{motion-placeholder-to-insert-functions-here}}'
|
||||
};
|
||||
return metaTable;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
// motion title
|
||||
var motionTitle = function() {
|
||||
return [{
|
||||
text: motion.getTitle(motionVersion),
|
||||
style: 'heading3'
|
||||
}];
|
||||
if (params.include.text) {
|
||||
return [{
|
||||
text: motion.getTitle(motionVersion),
|
||||
style: 'heading3'
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
// motion preamble
|
||||
var motionPreamble = function () {
|
||||
return {
|
||||
text: Config.translate(Config.get('motions_preamble').value),
|
||||
margin: [0, 10, 0, 0]
|
||||
};
|
||||
if (params.include.text) {
|
||||
return {
|
||||
text: Config.translate(Config.get('motions_preamble').value),
|
||||
margin: [0, 10, 0, 0]
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// motion text (with line-numbers)
|
||||
var motionText = function() {
|
||||
var motionTextContent = motion.getTextByMode(changeRecommendationMode, motionVersion);
|
||||
return converter.convertHTML(motionTextContent, lineNumberMode);
|
||||
if (params.include.text) {
|
||||
var motionTextContent = motion.getTextByMode(params.changeRecommendationMode, motionVersion);
|
||||
return converter.convertHTML(motionTextContent, params.lineNumberMode);
|
||||
}
|
||||
};
|
||||
|
||||
// motion reason heading
|
||||
var motionReason = function() {
|
||||
if (includeReason) {
|
||||
if (params.include.reason) {
|
||||
var reason = [];
|
||||
if (motion.getReason(motionVersion)) {
|
||||
reason.push({
|
||||
@ -327,13 +367,13 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
|
||||
// motion comments handling
|
||||
var motionComments = function () {
|
||||
if (includeComments) {
|
||||
if (_.keys(params.includeComments).length !== 0) {
|
||||
var fields = MotionComment.getNoSpecialCommentsFields();
|
||||
var comments = [];
|
||||
_.forEach(fields, function (field, id) {
|
||||
if (motion.comments[id]) {
|
||||
var title = field.name;
|
||||
if (!field.public) {
|
||||
_.forEach(params.includeComments, function (ok, id) {
|
||||
if (ok && motion.comments[id]) {
|
||||
var title = fields[id].name;
|
||||
if (!fields[id].public) {
|
||||
title += ' (' + gettextCatalog.getString('internal') + ')';
|
||||
}
|
||||
comments.push({
|
||||
@ -895,13 +935,6 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
return {
|
||||
getDocumentProvider: function (motions, params, singleMotion) {
|
||||
params = _.clone(params || {}); // Clone this to avoid sideeffects.
|
||||
_.defaults(params, {
|
||||
filename: gettextCatalog.getString('motions') + '.pdf',
|
||||
changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
|
||||
lineNumberMode: Config.get('motions_default_line_numbering').value,
|
||||
includeReason: true,
|
||||
includeComments: false,
|
||||
});
|
||||
|
||||
if (singleMotion) {
|
||||
_.defaults(params, {
|
||||
@ -927,9 +960,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
var motionContentProviderPromises = _.map(motions, function (motion) {
|
||||
var version = (singleMotion ? params.version : motion.active_version);
|
||||
return MotionContentProvider.createInstance(
|
||||
motion, version, params.changeRecommendationMode,
|
||||
motion.changeRecommendations, params.lineNumberMode,
|
||||
params.includeReason, params.includeComments
|
||||
motion, version, params
|
||||
).then(function (contentProvider) {
|
||||
motionContentProviderArray.push(contentProvider);
|
||||
});
|
||||
|
@ -242,7 +242,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
key: 'type',
|
||||
type: 'radio-buttons',
|
||||
templateOptions: {
|
||||
name: 'type',
|
||||
label: 'Type',
|
||||
options: [
|
||||
{name: gettextCatalog.getString('Replacement'), value: 0},
|
||||
{name: gettextCatalog.getString('Insertion'), value: 1},
|
||||
@ -618,7 +618,9 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
'operator',
|
||||
'gettextCatalog',
|
||||
'Config',
|
||||
function (operator, gettextCatalog, Config) {
|
||||
'MotionComment',
|
||||
function (operator, gettextCatalog, Config, MotionComment) {
|
||||
var noSpecialCommentsFields = MotionComment.getNoSpecialCommentsFields();
|
||||
return {
|
||||
getDialog: function (motions, params, singleMotion) {
|
||||
return {
|
||||
@ -634,14 +636,46 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
},
|
||||
};
|
||||
},
|
||||
getFormFields: function (singleMotion, formatChangeCallback) {
|
||||
getFormFields: function (singleMotion, motions, formatChangeCallback) {
|
||||
var fields = [];
|
||||
var commentsAvailable = Config.get('motions_comments').value.length !== 0;
|
||||
var commentsAvailable = _.keys(noSpecialCommentsFields).length !== 0;
|
||||
var getMetaInformationOptions = function (disabled) {
|
||||
if (!disabled) {
|
||||
disabled = {};
|
||||
}
|
||||
var options = [
|
||||
{name: gettextCatalog.getString('State'), id: 'state', disabled: disabled.state},
|
||||
{name: gettextCatalog.getString('Submitters'), id: 'submitters', disabled: disabled.submitters},
|
||||
{name: gettextCatalog.getString('Voting result'), id: 'votingresult', disabled: disabled.votingResult}
|
||||
];
|
||||
if (_.some(motions, function (motion) { return motion.motionBlock; })) {
|
||||
options.push({
|
||||
name: gettextCatalog.getString('Motion block'),
|
||||
id: 'motionBlock',
|
||||
disabled: disabled.motionBlock,
|
||||
});
|
||||
}
|
||||
if (_.some(motions, function (motion) { return motion.origin; })) {
|
||||
options.push({
|
||||
name: gettextCatalog.getString('Origin'),
|
||||
id: 'origin',
|
||||
disabled: disabled.origin,
|
||||
});
|
||||
}
|
||||
if (Config.get('motions_recommendations_by').value) {
|
||||
options.push({
|
||||
name: gettextCatalog.getString('Recommendation'),
|
||||
id: 'recommendation',
|
||||
disabled: disabled.recommendation
|
||||
});
|
||||
}
|
||||
return options;
|
||||
};
|
||||
if (!singleMotion) {
|
||||
fields = [
|
||||
{
|
||||
key: 'format',
|
||||
type: 'select-radio',
|
||||
type: 'radio-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Format'),
|
||||
options: [
|
||||
@ -658,7 +692,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
fields.push.apply(fields, [
|
||||
{
|
||||
key: 'lineNumberMode',
|
||||
type: 'select-radio',
|
||||
type: 'radio-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Line numbering'),
|
||||
options: [
|
||||
@ -671,7 +705,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
},
|
||||
{
|
||||
key: 'lineNumberMode',
|
||||
type: 'select-radio',
|
||||
type: 'radio-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Line numbering'),
|
||||
options: [
|
||||
@ -684,7 +718,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
},
|
||||
{
|
||||
key: 'changeRecommendationMode',
|
||||
type: 'select-radio',
|
||||
type: 'radio-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Change recommendations'),
|
||||
options: [
|
||||
@ -698,7 +732,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
},
|
||||
{
|
||||
key: 'changeRecommendationMode',
|
||||
type: 'select-radio',
|
||||
type: 'radio-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Change recommendations'),
|
||||
options: [
|
||||
@ -711,27 +745,62 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
hideExpression: "model.format === 'pdf'",
|
||||
},
|
||||
{
|
||||
key: 'includeReason',
|
||||
type: 'select-radio',
|
||||
key: 'include',
|
||||
type: 'checkbox-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Reason'),
|
||||
label: gettextCatalog.getString('Content'),
|
||||
options: [
|
||||
{name: gettextCatalog.getString('Yes'), value: true},
|
||||
{name: gettextCatalog.getString('No'), value: false},
|
||||
{name: gettextCatalog.getString('Text'), id: 'text'},
|
||||
{name: gettextCatalog.getString('Reason'), id: 'reason'},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 'include',
|
||||
type: 'checkbox-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Metainformation'),
|
||||
options: getMetaInformationOptions(),
|
||||
},
|
||||
hideExpression: "model.format !== 'pdf'",
|
||||
},
|
||||
{
|
||||
key: 'include',
|
||||
type: 'checkbox-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Metainformation'),
|
||||
options: getMetaInformationOptions({votingResult: true}),
|
||||
},
|
||||
hideExpression: "model.format !== 'csv'",
|
||||
},
|
||||
{
|
||||
key: 'include',
|
||||
type: 'checkbox-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Metainformation'),
|
||||
options: getMetaInformationOptions({
|
||||
state: true,
|
||||
votingResult: true,
|
||||
motionBlock: true,
|
||||
origin: true,
|
||||
recommendation: true,
|
||||
}),
|
||||
},
|
||||
hideExpression: "model.format !== 'docx'",
|
||||
},
|
||||
]);
|
||||
if (commentsAvailable) {
|
||||
fields.push({
|
||||
key: 'includeComments',
|
||||
type: 'select-radio',
|
||||
type: 'checkbox-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('Comments'),
|
||||
options: [
|
||||
{name: gettextCatalog.getString('Yes'), value: true},
|
||||
{name: gettextCatalog.getString('No'), value: false},
|
||||
],
|
||||
options: _.map(noSpecialCommentsFields, function (field, id) {
|
||||
return {
|
||||
name: gettextCatalog.getString(field.name),
|
||||
id: id,
|
||||
};
|
||||
}),
|
||||
},
|
||||
hideExpression: "model.format === 'csv'",
|
||||
});
|
||||
@ -740,7 +809,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
if (!singleMotion) {
|
||||
fields.push({
|
||||
key: 'pdfFormat',
|
||||
type: 'select-radio',
|
||||
type: 'radio-buttons',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('PDF format'),
|
||||
options: [
|
||||
@ -769,9 +838,27 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
'singleMotion',
|
||||
function ($scope, Config, MotionExportForm, MotionPdfExport, MotionCsvExport,
|
||||
MotionDocxExport, motions, params, singleMotion) {
|
||||
$scope.formFields = MotionExportForm.getFormFields(singleMotion, function () {
|
||||
$scope.params.changeRecommendationMode = 'original';
|
||||
$scope.params.lineNumberMode = 'none';
|
||||
$scope.formFields = MotionExportForm.getFormFields(singleMotion, motions, function () {
|
||||
if ($scope.params.format !== 'pdf') {
|
||||
$scope.params.changeRecommendationMode = 'original';
|
||||
$scope.params.lineNumberMode = 'none';
|
||||
$scope.params.include.votingresult = false;
|
||||
}
|
||||
if ($scope.params.format === 'docx') {
|
||||
$scope.params.include.state = false;
|
||||
$scope.params.include.motionBlock = false;
|
||||
$scope.params.include.origin = false;
|
||||
$scope.params.include.recommendation = false;
|
||||
} else {
|
||||
$scope.params.include.state = true;
|
||||
$scope.params.include.motionBlock = true;
|
||||
$scope.params.include.origin = true;
|
||||
$scope.params.include.recommendation = true;
|
||||
}
|
||||
if ($scope.params.format === 'pdf') {
|
||||
$scope.params.include.state = true;
|
||||
$scope.params.include.votingresult = true;
|
||||
}
|
||||
});
|
||||
$scope.params = params || {};
|
||||
_.defaults($scope.params, {
|
||||
@ -779,8 +866,17 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
pdfFormat: 'pdf',
|
||||
changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
|
||||
lineNumberMode: Config.get('motions_default_line_numbering').value,
|
||||
includeReason: true,
|
||||
includeComments: false,
|
||||
include: {
|
||||
text: true,
|
||||
reason: true,
|
||||
state: true,
|
||||
submitters: true,
|
||||
votingresult: true,
|
||||
motionBlock: true,
|
||||
origin: true,
|
||||
recommendation: true,
|
||||
},
|
||||
includeComments: {},
|
||||
});
|
||||
$scope.motions = motions;
|
||||
$scope.singleMotion = singleMotion;
|
||||
@ -1973,9 +2069,10 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
'gettext',
|
||||
'Category',
|
||||
'Motion',
|
||||
'MotionBlock',
|
||||
'User',
|
||||
'MotionCsvExport',
|
||||
function($scope, $q, gettext, Category, Motion, User, MotionCsvExport) {
|
||||
function($scope, $q, gettext, Category, Motion, MotionBlock, User, MotionCsvExport) {
|
||||
// set initial data for csv import
|
||||
$scope.motions = [];
|
||||
|
||||
@ -1988,7 +2085,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
},
|
||||
};
|
||||
|
||||
var FIELDS = ['identifier', 'title', 'text', 'reason', 'submitter', 'category', 'origin'];
|
||||
var FIELDS = ['identifier', 'title', 'text', 'reason', 'submitter', 'category', 'origin', 'motionBlock'];
|
||||
$scope.motions = [];
|
||||
$scope.onCsvChange = function (csv) {
|
||||
$scope.motions = [];
|
||||
@ -2030,37 +2127,42 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
motion.reason = '<p>' + motion.reason + '</p>';
|
||||
}
|
||||
// submitter
|
||||
if (motion.submitter) {
|
||||
if (motion.submitter !== '') {
|
||||
// All user objects are already loaded via the resolve statement from ui-router.
|
||||
var users = User.getAll();
|
||||
angular.forEach(users, function (user) {
|
||||
if (user.short_name == motion.submitter.trim()) {
|
||||
motion.submitters_id = [user.id];
|
||||
motion.submitter = User.get(user.id).full_name;
|
||||
}
|
||||
});
|
||||
if (motion.submitter && motion.submitter !== '') {
|
||||
angular.forEach(User.getAll(), function (user) {
|
||||
if (user.short_name == motion.submitter.trim()) {
|
||||
motion.submitters_id = [user.id];
|
||||
motion.submitter = user.full_name;
|
||||
}
|
||||
});
|
||||
if (!motion.submitters_id) {
|
||||
motion.submitter_create = gettext('New participant will be created.');
|
||||
}
|
||||
}
|
||||
if (motion.submitter && motion.submitter !== '' && !motion.submitters_id) {
|
||||
motion.submitter_create = gettext('New participant will be created.');
|
||||
}
|
||||
// category
|
||||
if (motion.category) {
|
||||
if (motion.category !== '') {
|
||||
// All categore objects are already loaded via the resolve statement from ui-router.
|
||||
var categories = Category.getAll();
|
||||
angular.forEach(categories, function (category) {
|
||||
// search for existing category
|
||||
if (category.name == motion.category) {
|
||||
motion.category_id = category.id;
|
||||
motion.category = Category.get(category.id).name;
|
||||
}
|
||||
});
|
||||
if (motion.category && motion.category !== '') {
|
||||
angular.forEach(Category.getAll(), function (category) {
|
||||
// search for existing category
|
||||
if (category.name == motion.category.trim()) {
|
||||
motion.category_id = category.id;
|
||||
motion.category = category.name;
|
||||
}
|
||||
});
|
||||
if (!motion.category_id) {
|
||||
motion.category_create = gettext('New category will be created.');
|
||||
}
|
||||
}
|
||||
if (motion.category && motion.category !== '' && !motion.category_id) {
|
||||
motion.category_create = gettext('New category will be created.');
|
||||
// Motion block
|
||||
if (motion.motionBlock && motion.motionBlock !== '') {
|
||||
angular.forEach(MotionBlock.getAll(), function (block) {
|
||||
// search for existing block
|
||||
if (block.title == motion.motionBlock.trim()) {
|
||||
motion.motion_block_id = block.id;
|
||||
motion.motionBlock = block.title;
|
||||
}
|
||||
});
|
||||
if (!motion.motion_block_id) {
|
||||
motion.motionBlock_create = gettext('New motion block will be created.');
|
||||
}
|
||||
}
|
||||
|
||||
$scope.motions.push(motion);
|
||||
@ -2092,10 +2194,12 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
// Reset counters
|
||||
$scope.usersCreated = 0;
|
||||
$scope.categoriesCreated = 0;
|
||||
$scope.motionBlocksCreated = 0;
|
||||
|
||||
var importedUsers = [];
|
||||
var importedCategories = [];
|
||||
// collect users and categories
|
||||
var importedMotionBlocks = [];
|
||||
// collect users, categories and motion blocks
|
||||
angular.forEach($scope.motions, function (motion) {
|
||||
if (motion.selected && !motion.importerror) {
|
||||
// collect user if not exists
|
||||
@ -2116,10 +2220,17 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
};
|
||||
importedCategories.push(category);
|
||||
}
|
||||
// collect motion block if not exists
|
||||
if (!motion.motion_block_id && motion.motionBlock) {
|
||||
var motionBlock = {
|
||||
title: motion.motionBlock,
|
||||
};
|
||||
importedMotionBlocks.push(motionBlock);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// unique users and categories
|
||||
// unique users, categories and motion blocks
|
||||
var importedUsersUnique = _.uniqWith(importedUsers, function (u1, u2) {
|
||||
return u1.first_name == u2.first_name &&
|
||||
u1.last_name == u2.last_name;
|
||||
@ -2127,12 +2238,15 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
var importedCategoriesUnique = _.uniqWith(importedCategories, function (c1, c2) {
|
||||
return c1.name == c2.name;
|
||||
});
|
||||
var importedMotionBlocksUnique = _.uniqWith(importedMotionBlocks, function (c1, c2) {
|
||||
return c1.title == c2.title;
|
||||
});
|
||||
|
||||
// Promises for users and categories
|
||||
var createPromises = [];
|
||||
|
||||
// create users and categories
|
||||
importedUsersUnique.forEach(function (user) {
|
||||
_.forEach(importedUsersUnique, function (user) {
|
||||
createPromises.push(User.create(user).then(
|
||||
function (success) {
|
||||
user.id = success.id;
|
||||
@ -2140,7 +2254,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
}
|
||||
));
|
||||
});
|
||||
importedCategoriesUnique.forEach(function (category) {
|
||||
_.forEach(importedCategoriesUnique, function (category) {
|
||||
createPromises.push(Category.create(category).then(
|
||||
function (success) {
|
||||
category.id = success.id;
|
||||
@ -2148,6 +2262,14 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
}
|
||||
));
|
||||
});
|
||||
_.forEach(importedMotionBlocksUnique, function (motionBlock) {
|
||||
createPromises.push(MotionBlock.create(motionBlock).then(
|
||||
function (success) {
|
||||
motionBlock.id = success.id;
|
||||
$scope.motionBlocksCreated++;
|
||||
}
|
||||
));
|
||||
});
|
||||
|
||||
// wait for users and categories to create
|
||||
$q.all(createPromises).then( function() {
|
||||
@ -2160,7 +2282,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
var last_name = motion.submitter.substr(index+1);
|
||||
|
||||
// search for user, set id.
|
||||
importedUsersUnique.forEach(function (user) {
|
||||
_.forEach(importedUsersUnique, function (user) {
|
||||
if (user.first_name == first_name &&
|
||||
user.last_name == last_name) {
|
||||
motion.submitters_id = [user.id];
|
||||
@ -2172,12 +2294,24 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
var name = motion.category;
|
||||
|
||||
// search for category, set id.
|
||||
importedCategoriesUnique.forEach(function (category) {
|
||||
_.forEach(importedCategoriesUnique, function (category) {
|
||||
if (category.name == name) {
|
||||
motion.category_id = category.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
// add motion block
|
||||
if (!motion.motion_block_id && motion.motionBlock) {
|
||||
var title = motion.motionBlock;
|
||||
|
||||
// search for motion block
|
||||
_.forEach(importedMotionBlocksUnique, function (motionBlock) {
|
||||
if (motionBlock.title == title) {
|
||||
motion.motion_block_id = motionBlock.id;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// finally create motion
|
||||
Motion.create(motion).then(
|
||||
|
@ -25,9 +25,11 @@
|
||||
<translate>Reason</translate>,
|
||||
<translate>Submitter</translate>,
|
||||
<translate>Category</translate>,
|
||||
<translate>Origin</translate>
|
||||
<translate>Origin</translate>,
|
||||
<translate>Motion block</translate>
|
||||
</code>
|
||||
<li translate>Identifier, reason, submitter, category and origin are optional and may be empty.
|
||||
<li translate>Identifier, reason, submitter, category, origin and motion block are optional and may be empty.
|
||||
<li translate>Additional columns after the required ones may be present and won't affect the import.
|
||||
<li translate>Only double quotes are accepted as text delimiter (no single quotes).
|
||||
<li><a id="downloadLink" href="" ng-click="downloadCSVExample()" translate>Download CSV example file</a>
|
||||
</ul>
|
||||
@ -46,7 +48,8 @@
|
||||
<th translate>Reason
|
||||
<th translate>Submitter
|
||||
<th translate>Category
|
||||
<th translate>Origin</th>
|
||||
<th translate>Origin
|
||||
<th translate>Motion block
|
||||
<tbody ng-repeat="motion in motions">
|
||||
<tr>
|
||||
<td class="minimum"
|
||||
@ -93,6 +96,11 @@
|
||||
</span>
|
||||
{{ motion.category }}
|
||||
<td>{{ motion.origin | limitTo:30 }}{{ motion.origin.length > 30 ? '...' : '' }}
|
||||
<td ng-class="{ 'text-warning': motion.motionBlock_create }">
|
||||
<span ng-if="motion.motionBlock_create" title="{{ motion.motionBlock_create | translate }}">
|
||||
<i class="fa fa-plus-circle"></i>
|
||||
</span>
|
||||
{{ motion.motionBlock }}
|
||||
</table>
|
||||
</div>
|
||||
|
||||
@ -113,7 +121,8 @@
|
||||
{{ motionsImported.length }}
|
||||
<translate>motions were successfully imported.</translate>
|
||||
(<translate>Users created</translate>: {{ usersCreated }},
|
||||
<translate>Categories created</translate>: {{ categoriesCreated }})
|
||||
<translate>Categories created</translate>: {{ categoriesCreated }},
|
||||
<translate>Motion blocks created</translate>: {{ motionBlocksCreated }})
|
||||
</div>
|
||||
|
||||
<div class="spacer">
|
||||
|
Loading…
Reference in New Issue
Block a user