Merge pull request #2534 from tsiegleauq/electionsListPdfMake
Creates the Election documents using PdfMake
This commit is contained in:
commit
b08ca4be02
446
openslides/assignments/static/js/assignments/pdf.js
Normal file
446
openslides/assignments/static/js/assignments/pdf.js
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
(function () {
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf'])
|
||||||
|
|
||||||
|
.factory('AssignmentContentProvider', [
|
||||||
|
'gettextCatalog',
|
||||||
|
'PdfPredefinedFunctions',
|
||||||
|
function(gettextCatalog, PdfPredefinedFunctions) {
|
||||||
|
|
||||||
|
var createInstance = function(scope, polls) {
|
||||||
|
|
||||||
|
//use the Predefined Functions to create the title
|
||||||
|
var title = PdfPredefinedFunctions.createTitle(
|
||||||
|
gettextCatalog.getString("Election") + ": " + scope.assignment.title);
|
||||||
|
|
||||||
|
//create the preamble
|
||||||
|
var createPreamble = function() {
|
||||||
|
var preambleText = gettextCatalog.getString("Number of posts to be elected") + ": ";
|
||||||
|
var memberNumber = ""+scope.assignment.open_posts;
|
||||||
|
var preamble = {
|
||||||
|
text: [
|
||||||
|
{
|
||||||
|
text: preambleText,
|
||||||
|
bold: true,
|
||||||
|
style: 'textItem'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: memberNumber,
|
||||||
|
style: 'textItem'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
return preamble;
|
||||||
|
};
|
||||||
|
|
||||||
|
//adds the description if present in the assignment
|
||||||
|
var createDescription = function() {
|
||||||
|
if (scope.assignment.description) {
|
||||||
|
var descriptionText = gettextCatalog.getString("Description") + ":";
|
||||||
|
var description = [
|
||||||
|
{
|
||||||
|
text: descriptionText,
|
||||||
|
bold: true,
|
||||||
|
style: 'textItem'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: scope.assignment.description,
|
||||||
|
style: 'textItem',
|
||||||
|
margin: [10, 0, 0, 0]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
return description;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//creates the candidate list in columns if the assignment phase is 'voting'
|
||||||
|
var createCandidateList = function() {
|
||||||
|
if (scope.assignment.phase != 2) {
|
||||||
|
var candidatesText = gettextCatalog.getString("Candidates") + ": ";
|
||||||
|
var userList = [];
|
||||||
|
|
||||||
|
angular.forEach(scope.assignment.assignment_related_users, function(assignmentsRelatedUser) {
|
||||||
|
userList.push({
|
||||||
|
text: assignmentsRelatedUser.user.get_full_name(),
|
||||||
|
margin: [0, 0, 0, 10],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
var cadidateList = {
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
text: candidatesText,
|
||||||
|
bold: true,
|
||||||
|
width: "25%",
|
||||||
|
style: 'textItem'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ol: userList,
|
||||||
|
style: 'textItem'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
return cadidateList;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//handles the case if a candidate is elected or not
|
||||||
|
var electedCandidateLine = function(candidateName, pollOption, pollTableBody) {
|
||||||
|
if (pollOption.is_elected) {
|
||||||
|
return {
|
||||||
|
text: candidateName + "*",
|
||||||
|
bold: true,
|
||||||
|
style: PdfPredefinedFunctions.flipTableRowStyle(pollTableBody.length)
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
text: candidateName,
|
||||||
|
style: PdfPredefinedFunctions.flipTableRowStyle(pollTableBody.length)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//creates the pull result table
|
||||||
|
var createPollResultTable = function() {
|
||||||
|
var resultBody = [];
|
||||||
|
angular.forEach(polls, function(poll, pollIndex) {
|
||||||
|
if (poll.published) {
|
||||||
|
var voteNrTotal = poll.votescast;
|
||||||
|
var voteNrValid = poll.votesvalid;
|
||||||
|
var voteNrInVal = poll.votesinvalid;
|
||||||
|
var pollTableBody = [];
|
||||||
|
|
||||||
|
resultBody.push({
|
||||||
|
text: gettextCatalog.getString("Ballot") + " " + (pollIndex+1),
|
||||||
|
bold: true,
|
||||||
|
style: 'textItem',
|
||||||
|
margin: [0,15,0,0]
|
||||||
|
});
|
||||||
|
|
||||||
|
pollTableBody.push([
|
||||||
|
{
|
||||||
|
text: gettextCatalog.getString("Candidates"),
|
||||||
|
style: 'tableHeader',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: gettextCatalog.getString("Votes"),
|
||||||
|
style: 'tableHeader',
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
|
||||||
|
angular.forEach(poll.options, function(pollOption, optionIndex) {
|
||||||
|
var candidateName = pollOption.candidate.get_full_name();
|
||||||
|
var votes = pollOption.getVotes(); // 0 = yes, 1 = no, 2 = abstain
|
||||||
|
var candidateLine;
|
||||||
|
|
||||||
|
if (poll.pollmethod == 'votes') {
|
||||||
|
pollTableBody.push([
|
||||||
|
electedCandidateLine(candidateName, pollOption, pollTableBody),
|
||||||
|
{
|
||||||
|
text: votes[0].value + " " + votes[0].percentStr,
|
||||||
|
style: PdfPredefinedFunctions.flipTableRowStyle(pollTableBody.length)
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
} else if (poll.pollmethod == 'yn') {
|
||||||
|
pollTableBody.push([
|
||||||
|
{
|
||||||
|
text: candidateName,
|
||||||
|
style: PdfPredefinedFunctions.flipTableRowStyle(pollTableBody.length)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: [
|
||||||
|
{
|
||||||
|
text: votes[0].label + ": " + votes[0].value + " " + votes[0].percentStr + "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: votes[1].label + ": " + votes[1].value + " " + votes[1].percentStr
|
||||||
|
}
|
||||||
|
],
|
||||||
|
style: PdfPredefinedFunctions.flipTableRowStyle(pollTableBody.length)
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
} else if (poll.pollmethod == 'yna') {
|
||||||
|
pollTableBody.push([
|
||||||
|
{
|
||||||
|
text: candidateName,
|
||||||
|
style: PdfPredefinedFunctions.flipTableRowStyle(pollTableBody.length)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: [
|
||||||
|
{
|
||||||
|
text: votes[0].label + ": " + votes[0].value + " " + votes[0].percentStr + "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: votes[1].label + ": " + votes[1].value + " " + votes[1].percentStr + "\n"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: votes[2].label + ": " + votes[2].value + " " + votes[2].percentStr
|
||||||
|
}
|
||||||
|
],
|
||||||
|
style: PdfPredefinedFunctions.flipTableRowStyle(pollTableBody.length)
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//it is technically possible to make a single push-statement
|
||||||
|
//however, the flipTableRowStyle-function needs the current table size
|
||||||
|
if (voteNrValid) {
|
||||||
|
pollTableBody.push([
|
||||||
|
{
|
||||||
|
text: gettextCatalog.getString("Valid ballots"),
|
||||||
|
style: 'tableConclude'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: ""+voteNrValid,
|
||||||
|
style: 'tableConclude'
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (voteNrInVal) {
|
||||||
|
pollTableBody.push([
|
||||||
|
{
|
||||||
|
text: gettextCatalog.getString("Invalid ballots"),
|
||||||
|
style: 'tableConclude'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: ""+voteNrInVal,
|
||||||
|
style: 'tableConclude'
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (voteNrTotal) {
|
||||||
|
pollTableBody.push([
|
||||||
|
{
|
||||||
|
text: gettextCatalog.getString("Casted ballots"),
|
||||||
|
style: 'tableConclude'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: ""+voteNrTotal,
|
||||||
|
style: 'tableConclude'
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var resultTableJsonSting = {
|
||||||
|
table: {
|
||||||
|
widths: ['64%','33%'],
|
||||||
|
headerRows: 1,
|
||||||
|
body: pollTableBody,
|
||||||
|
},
|
||||||
|
layout: 'headerLineOnly',
|
||||||
|
};
|
||||||
|
|
||||||
|
resultBody.push(resultTableJsonSting);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//Add the Legend to the result body
|
||||||
|
resultBody.push({
|
||||||
|
text: "* = " + gettextCatalog.getString("is elected"),
|
||||||
|
margin: [0,5,0,0],
|
||||||
|
});
|
||||||
|
|
||||||
|
return resultBody;
|
||||||
|
};
|
||||||
|
|
||||||
|
var getContent = function() {
|
||||||
|
return [
|
||||||
|
title,
|
||||||
|
createPreamble(),
|
||||||
|
createDescription(),
|
||||||
|
createCandidateList(),
|
||||||
|
createPollResultTable()
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
getContent: getContent
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
createInstance: createInstance
|
||||||
|
};
|
||||||
|
}])
|
||||||
|
|
||||||
|
.factory('BallotContentProvider', [
|
||||||
|
'gettextCatalog',
|
||||||
|
'PdfPredefinedFunctions',
|
||||||
|
function(gettextCatalog, PdfPredefinedFunctions) {
|
||||||
|
|
||||||
|
var createInstance = function(scope, poll, pollNumber) {
|
||||||
|
|
||||||
|
// use the Predefined Functions to create the title
|
||||||
|
var createTitle = function() {
|
||||||
|
return {
|
||||||
|
text: gettextCatalog.getString("Election") + ": " + scope.assignment.title,
|
||||||
|
style: 'title',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//function to create the poll hint
|
||||||
|
var createPollHint = function() {
|
||||||
|
return {
|
||||||
|
text: gettextCatalog.getString("Ballot") + " " + pollNumber + ": " + poll.description,
|
||||||
|
style: 'description',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
//function to create the selection entries
|
||||||
|
var createYNBallotEntry = function(decision) {
|
||||||
|
var YNColumn = [
|
||||||
|
{
|
||||||
|
width: "auto",
|
||||||
|
stack: [
|
||||||
|
PdfPredefinedFunctions.createBallotEntry(gettextCatalog.getString("Yes"))
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
width: "auto",
|
||||||
|
stack: [
|
||||||
|
PdfPredefinedFunctions.createBallotEntry(gettextCatalog.getString("No"))
|
||||||
|
]
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (poll.pollmethod == 'yna') {
|
||||||
|
YNColumn.push({
|
||||||
|
width: "auto",
|
||||||
|
stack: [
|
||||||
|
PdfPredefinedFunctions.createBallotEntry(gettextCatalog.getString("Abstain"))
|
||||||
|
]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: decision,
|
||||||
|
margin: [40, 10, 0, 0],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
columns: YNColumn
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
var createSelectionField = function() {
|
||||||
|
var candidateBallotList = [];
|
||||||
|
|
||||||
|
if (poll.pollmethod == 'votes') {
|
||||||
|
angular.forEach(poll.options, function(option) {
|
||||||
|
var candidate = option.candidate.get_full_name();
|
||||||
|
candidateBallotList.push(PdfPredefinedFunctions.createBallotEntry(candidate));
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
angular.forEach(poll.options, function(option) {
|
||||||
|
var candidate = option.candidate.get_full_name();
|
||||||
|
candidateBallotList.push(createYNBallotEntry(candidate));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return candidateBallotList;
|
||||||
|
};
|
||||||
|
|
||||||
|
var createSection = function(marginTop) {
|
||||||
|
|
||||||
|
// since it is not possible to give a column a fixed height, we draw an "empty" column
|
||||||
|
// with a one px width and a fixed top-margin
|
||||||
|
|
||||||
|
return {
|
||||||
|
columns : [
|
||||||
|
{
|
||||||
|
width: 1,
|
||||||
|
margin: [0,marginTop],
|
||||||
|
text: ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
width: '*',
|
||||||
|
stack: [
|
||||||
|
createTitle(),
|
||||||
|
createPollHint(),
|
||||||
|
createSelectionField(),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var createTableBody = function(numberOfRows, sheetend) {
|
||||||
|
var tableBody = [];
|
||||||
|
for (var i = 0; i < numberOfRows; i++) {
|
||||||
|
tableBody.push([createSection(sheetend), createSection(sheetend)]);
|
||||||
|
}
|
||||||
|
return tableBody;
|
||||||
|
};
|
||||||
|
|
||||||
|
var createContentTable = function() {
|
||||||
|
|
||||||
|
var tableBody = [];
|
||||||
|
var sheetend;
|
||||||
|
|
||||||
|
if (poll.pollmethod == 'votes') {
|
||||||
|
if (poll.options.length <= 4) {
|
||||||
|
sheetend = 105;
|
||||||
|
tableBody = createTableBody(4, sheetend);
|
||||||
|
} else if (poll.options.length <= 8) {
|
||||||
|
sheetend = 140;
|
||||||
|
tableBody = tableBody = createTableBody(3, sheetend);
|
||||||
|
} else if (poll.options.length <= 12) {
|
||||||
|
sheetend = 210;
|
||||||
|
tableBody = tableBody = createTableBody(2, sheetend);
|
||||||
|
}
|
||||||
|
else { //works untill ~30 people
|
||||||
|
sheetend = 418;
|
||||||
|
tableBody = createTableBody(1, sheetend);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (poll.options.length <= 2) {
|
||||||
|
sheetend = 105;
|
||||||
|
tableBody = createTableBody(4, sheetend);
|
||||||
|
} else if (poll.options.length <= 4) {
|
||||||
|
sheetend = 140;
|
||||||
|
tableBody = createTableBody(3, sheetend);
|
||||||
|
} else if (poll.options.length <= 6) {
|
||||||
|
sheetend = 210;
|
||||||
|
tableBody = createTableBody(2, sheetend);
|
||||||
|
} else {
|
||||||
|
sheetend = 418;
|
||||||
|
tableBody = createTableBody(1, sheetend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [{
|
||||||
|
table: {
|
||||||
|
headerRows: 1,
|
||||||
|
widths: ['50%', '50%'],
|
||||||
|
body: tableBody
|
||||||
|
},
|
||||||
|
layout: PdfPredefinedFunctions.getBallotLayoutLines()
|
||||||
|
}];
|
||||||
|
};
|
||||||
|
|
||||||
|
var getContent = function() {
|
||||||
|
return createContentTable();
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
getContent: getContent
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
createInstance: createInstance
|
||||||
|
};
|
||||||
|
|
||||||
|
}]);
|
||||||
|
|
||||||
|
}());
|
@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
|
angular.module('OpenSlidesApp.assignments.site', [
|
||||||
|
'OpenSlidesApp.assignments',
|
||||||
|
'OpenSlidesApp.core.pdf',
|
||||||
|
'OpenSlidesApp.assignments.pdf'
|
||||||
|
])
|
||||||
|
|
||||||
.config([
|
.config([
|
||||||
'mainMenuProvider',
|
'mainMenuProvider',
|
||||||
@ -351,8 +355,14 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
|
|||||||
'phases',
|
'phases',
|
||||||
'Projector',
|
'Projector',
|
||||||
'ProjectionDefault',
|
'ProjectionDefault',
|
||||||
|
'AssignmentContentProvider',
|
||||||
|
'BallotContentProvider',
|
||||||
|
'PdfMakeDocumentProvider',
|
||||||
|
'PdfMakeBallotPaperProvider',
|
||||||
|
'gettextCatalog',
|
||||||
function($scope, $http, filterFilter, gettext, ngDialog, AssignmentForm, operator, Assignment, User,
|
function($scope, $http, filterFilter, gettext, ngDialog, AssignmentForm, operator, Assignment, User,
|
||||||
assignment, phases, Projector, ProjectionDefault) {
|
assignment, phases, Projector, ProjectionDefault, AssignmentContentProvider, BallotContentProvider,
|
||||||
|
PdfMakeDocumentProvider, PdfMakeBallotPaperProvider, gettextCatalog) {
|
||||||
User.bindAll({}, $scope, 'users');
|
User.bindAll({}, $scope, 'users');
|
||||||
Assignment.bindOne(assignment.id, $scope, 'assignment');
|
Assignment.bindOne(assignment.id, $scope, 'assignment');
|
||||||
Assignment.loadRelations(assignment, 'agenda_item');
|
Assignment.loadRelations(assignment, 'agenda_item');
|
||||||
@ -512,6 +522,30 @@ angular.module('OpenSlidesApp.assignments.site', ['OpenSlidesApp.assignments'])
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//creates the document as pdf
|
||||||
|
$scope.makePDF_singleAssignment = function() {
|
||||||
|
var filename = gettextCatalog.getString("Election") + " " + $scope.assignment.title + ".pdf";
|
||||||
|
var assignmentContentProvider = AssignmentContentProvider.createInstance($scope, assignment.polls);
|
||||||
|
var documentProvider = PdfMakeDocumentProvider.createInstance(assignmentContentProvider);
|
||||||
|
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
//creates the ballotpaper as pdf
|
||||||
|
$scope.makePDF_assignmentpoll = function(pollID) {
|
||||||
|
var thePoll;
|
||||||
|
var pollNumber;
|
||||||
|
angular.forEach(assignment.polls, function(poll, pollIndex) {
|
||||||
|
if (poll.id == pollID) {
|
||||||
|
thePoll = poll;
|
||||||
|
pollNumber = pollIndex+1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var filename = gettextCatalog.getString("Ballot") + " " + pollNumber + " " + $scope.assignment.title + ".pdf";
|
||||||
|
var ballotContentProvider = BallotContentProvider.createInstance($scope, thePoll, pollNumber);
|
||||||
|
var documentProvider = PdfMakeBallotPaperProvider.createInstance(ballotContentProvider);
|
||||||
|
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
||||||
|
};
|
||||||
|
|
||||||
// Just mark some vote value strings for translation.
|
// Just mark some vote value strings for translation.
|
||||||
gettext('Yes');
|
gettext('Yes');
|
||||||
gettext('No');
|
gettext('No');
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<i class="fa fa-pencil"></i>
|
<i class="fa fa-pencil"></i>
|
||||||
</a>
|
</a>
|
||||||
<!-- pdf -->
|
<!-- pdf -->
|
||||||
<a ui-sref="assignments_single_pdf({pk: assignment.id})" target="_blank" class="btn btn-default btn-sm">
|
<a ng-click="makePDF_singleAssignment()" target="_blank" class="btn btn-default btn-sm">
|
||||||
<i class="fa fa-file-pdf-o fa-lg"></i>
|
<i class="fa fa-file-pdf-o fa-lg"></i>
|
||||||
<translate>PDF</translate>
|
<translate>PDF</translate>
|
||||||
</a>
|
</a>
|
||||||
@ -143,8 +143,7 @@
|
|||||||
<!-- angular requires to open the link in new tab with "target='_blank'".
|
<!-- angular requires to open the link in new tab with "target='_blank'".
|
||||||
Otherwise the pdf url can't be open in same window; angular redirects to "/". -->
|
Otherwise the pdf url can't be open in same window; angular redirects to "/". -->
|
||||||
<!-- PDF -->
|
<!-- PDF -->
|
||||||
<a ui-sref="assignmentpoll_pdf({poll_pk: poll.id})" target="_blank"
|
<a ng-click="makePDF_assignmentpoll(poll.id)" target="_blank" class="btn btn-default btn-sm">
|
||||||
class="btn btn-default btn-sm">
|
|
||||||
<i class="fa fa-file-pdf-o"></i>
|
<i class="fa fa-file-pdf-o"></i>
|
||||||
<translate>Print ballot paper</translate>
|
<translate>Print ballot paper</translate>
|
||||||
</a>
|
</a>
|
||||||
|
@ -7,6 +7,10 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
.factory('PdfPredefinedFunctions', [
|
.factory('PdfPredefinedFunctions', [
|
||||||
function() {
|
function() {
|
||||||
var PdfPredefinedFunctions = {};
|
var PdfPredefinedFunctions = {};
|
||||||
|
var BallotCircleDimensions = {
|
||||||
|
yDistance: 6,
|
||||||
|
size: 8
|
||||||
|
};
|
||||||
|
|
||||||
PdfPredefinedFunctions.createTitle = function(titleString) {
|
PdfPredefinedFunctions.createTitle = function(titleString) {
|
||||||
return {
|
return {
|
||||||
@ -15,6 +19,62 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
PdfPredefinedFunctions.flipTableRowStyle = function(currentTableSize) {
|
||||||
|
if (currentTableSize % 2 === 0) {
|
||||||
|
return "tableEven";
|
||||||
|
} else {
|
||||||
|
return "tableOdd";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//draws a circle
|
||||||
|
PdfPredefinedFunctions.drawCircle = function(y, size) {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
type: 'ellipse',
|
||||||
|
x: 0,
|
||||||
|
y: y,
|
||||||
|
lineColor: 'black',
|
||||||
|
r1: size,
|
||||||
|
r2: size
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
//Returns an entry in the ballot with a circle to draw into
|
||||||
|
PdfPredefinedFunctions.createBallotEntry = function(decision) {
|
||||||
|
return {
|
||||||
|
margin: [40+BallotCircleDimensions.size, 10, 0, 0],
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
width: 15,
|
||||||
|
canvas: PdfPredefinedFunctions.drawCircle(BallotCircleDimensions.yDistance, BallotCircleDimensions.size)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
width: "auto",
|
||||||
|
text: decision
|
||||||
|
}
|
||||||
|
],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
PdfPredefinedFunctions.getBallotLayoutLines = function() {
|
||||||
|
return {
|
||||||
|
hLineWidth: function(i, node) {
|
||||||
|
return (i === 0 || i === node.table.body.length) ? 0 : 0.5;
|
||||||
|
},
|
||||||
|
vLineWidth: function(i, node) {
|
||||||
|
return (i === 0 || i === node.table.widths.length) ? 0 : 0.5;
|
||||||
|
},
|
||||||
|
hLineColor: function(i, node) {
|
||||||
|
return (i === 0 || i === node.table.body.length) ? 'none' : 'gray';
|
||||||
|
},
|
||||||
|
vLineColor: function(i, node) {
|
||||||
|
return (i === 0 || i === node.table.widths.length) ? 'none' : 'gray';
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
return PdfPredefinedFunctions;
|
return PdfPredefinedFunctions;
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
@ -113,6 +173,10 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
margin: [0,0,0,20],
|
margin: [0,0,0,20],
|
||||||
bold: true
|
bold: true
|
||||||
},
|
},
|
||||||
|
textItem: {
|
||||||
|
fontSize: 11,
|
||||||
|
margin: [0,7]
|
||||||
|
},
|
||||||
heading: {
|
heading: {
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
margin: [0,0,0,10],
|
margin: [0,0,0,10],
|
||||||
@ -131,13 +195,66 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
margin: [0,5]
|
margin: [0,5]
|
||||||
},
|
},
|
||||||
tableHeader: {
|
tableHeader: {
|
||||||
bold: true
|
bold: true,
|
||||||
|
fillColor: 'white'
|
||||||
},
|
},
|
||||||
tableEven: {
|
tableEven: {
|
||||||
fillColor: 'white'
|
fillColor: 'white'
|
||||||
},
|
},
|
||||||
tableOdd: {
|
tableOdd: {
|
||||||
fillColor: '#e7e7e7'
|
fillColor: '#eee'
|
||||||
|
},
|
||||||
|
tableConclude: {
|
||||||
|
fillColor: '#ddd',
|
||||||
|
bold: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
getDocument: getDocument
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
createInstance: createInstance
|
||||||
|
};
|
||||||
|
}
|
||||||
|
])
|
||||||
|
|
||||||
|
.factory('PdfMakeBallotPaperProvider', [
|
||||||
|
'gettextCatalog',
|
||||||
|
'Config',
|
||||||
|
function(gettextCatalog, Config) {
|
||||||
|
/**
|
||||||
|
* Provides the global Document
|
||||||
|
* @constructor
|
||||||
|
* @param {object} contentProvider - Object with on method `getContent`, which returns an array for content
|
||||||
|
* @param {string} defaultFont - Default font for the document
|
||||||
|
*/
|
||||||
|
var createInstance = function(contentProvider, defaultFont) {
|
||||||
|
/**
|
||||||
|
* Generates the document(definition) for pdfMake
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
var getDocument = function() {
|
||||||
|
var content = contentProvider.getContent();
|
||||||
|
return {
|
||||||
|
pageSize: 'A4',
|
||||||
|
pageMargins: [0, 0, 0, 0],
|
||||||
|
defaultStyle: {
|
||||||
|
font: defaultFont,
|
||||||
|
fontSize: 10
|
||||||
|
},
|
||||||
|
content: content,
|
||||||
|
styles: {
|
||||||
|
title: {
|
||||||
|
fontSize: 14,
|
||||||
|
bold: true,
|
||||||
|
margin: [30, 30, 0, 0]
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
fontSize: 11,
|
||||||
|
margin: [30, 0, 0, 0]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -10,12 +10,13 @@ angular.module('OpenSlidesApp.motions.motionservices', ['OpenSlidesApp.motions',
|
|||||||
'User',
|
'User',
|
||||||
'PdfMakeConverter',
|
'PdfMakeConverter',
|
||||||
'PdfMakeDocumentProvider',
|
'PdfMakeDocumentProvider',
|
||||||
|
'PdfMakeBallotPaperProvider',
|
||||||
'MotionContentProvider',
|
'MotionContentProvider',
|
||||||
'PollContentProvider',
|
'PollContentProvider',
|
||||||
'gettextCatalog',
|
'gettextCatalog',
|
||||||
'$http',
|
'$http',
|
||||||
function (HTMLValidizer, Motion, User, PdfMakeConverter, PdfMakeDocumentProvider, MotionContentProvider,
|
function (HTMLValidizer, Motion, User, PdfMakeConverter, PdfMakeDocumentProvider, PdfMakeBallotPaperProvider,
|
||||||
PollContentProvider, gettextCatalog, $http) {
|
MotionContentProvider, PollContentProvider, gettextCatalog, $http) {
|
||||||
var obj = {};
|
var obj = {};
|
||||||
|
|
||||||
var $scope;
|
var $scope;
|
||||||
@ -39,12 +40,12 @@ angular.module('OpenSlidesApp.motions.motionservices', ['OpenSlidesApp.motions',
|
|||||||
|
|
||||||
//make PDF for polls
|
//make PDF for polls
|
||||||
obj.createPoll = function() {
|
obj.createPoll = function() {
|
||||||
var id = $scope.motion.identifier.replace(" ", ""),
|
var id = $scope.motion.identifier.replace(" ", "");
|
||||||
title = $scope.motion.getTitle($scope.version),
|
var title = $scope.motion.getTitle($scope.version);
|
||||||
filename = gettextCatalog.getString("Motion") + "-" + id + "-" + gettextCatalog.getString("ballot-paper") + ".pdf",
|
var filename = gettextCatalog.getString("Motion") + "-" + id + "-" + gettextCatalog.getString("ballot-paper") + ".pdf";
|
||||||
content = PollContentProvider.createInstance(title, id, gettextCatalog);
|
var pollContentProvider = PollContentProvider.createInstance(title, id, gettextCatalog);
|
||||||
|
var documentProvider = PdfMakeBallotPaperProvider.createInstance(pollContentProvider);
|
||||||
pdfMake.createPdf(content).download(filename);
|
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
obj.init = function (_scope) {
|
obj.init = function (_scope) {
|
||||||
|
@ -184,7 +184,9 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
|
|
||||||
.factory('PollContentProvider', function() {
|
.factory('PollContentProvider', [
|
||||||
|
'PdfPredefinedFunctions',
|
||||||
|
function(PdfPredefinedFunctions) {
|
||||||
/**
|
/**
|
||||||
* Generates a content provider for polls
|
* Generates a content provider for polls
|
||||||
* @constructor
|
* @constructor
|
||||||
@ -194,82 +196,23 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
*/
|
*/
|
||||||
var createInstance = function(title, id, gettextCatalog) {
|
var createInstance = function(title, id, gettextCatalog) {
|
||||||
|
|
||||||
//left and top margin for a single sheet
|
|
||||||
var space = {
|
|
||||||
left: 30,
|
|
||||||
top: 30,
|
|
||||||
bottom: 10
|
|
||||||
},
|
|
||||||
//size and position of the signing circle
|
|
||||||
circle = {
|
|
||||||
yDistance: 6,
|
|
||||||
size: 8
|
|
||||||
},
|
|
||||||
//margin for the decision
|
|
||||||
singleItemMargin = 10,
|
|
||||||
//space between circle and dicision
|
|
||||||
columnwidth = 20,
|
|
||||||
//defines the space under a single sheet
|
|
||||||
sheetend = 65,
|
|
||||||
//defines the used fontsize
|
|
||||||
fontSize = 14;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* draws a single circle
|
|
||||||
* @function
|
|
||||||
* @param {int} y - the relative y coordinate
|
|
||||||
* @param {int} size - size of the circle in px
|
|
||||||
*/
|
|
||||||
var drawCircle = function(y, size) {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
type: 'ellipse',
|
|
||||||
x: 0,
|
|
||||||
y: y,
|
|
||||||
lineColor: 'black',
|
|
||||||
r1: size,
|
|
||||||
r2: size
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an entry in the ballot with a circle to draw into
|
|
||||||
* @function
|
|
||||||
* @param {string} decision - the name of an entry to decide between, e.g. 'yes' or 'no'
|
|
||||||
*/
|
|
||||||
var createBallotEntry = function(decision) {
|
|
||||||
return {
|
|
||||||
margin: [space.left+circle.size, singleItemMargin, 0, 0],
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
width: columnwidth,
|
|
||||||
canvas: drawCircle(circle.yDistance, circle.size)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: decision
|
|
||||||
}
|
|
||||||
],
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a single section on the ballot paper
|
* Returns a single section on the ballot paper
|
||||||
* @function
|
* @function
|
||||||
*/
|
*/
|
||||||
var createSection = function() {
|
var createSection = function() {
|
||||||
|
var sheetend = 75;
|
||||||
return {
|
return {
|
||||||
stack: [{
|
stack: [{
|
||||||
text: gettextCatalog.getString("Motion") + " " + id,
|
text: gettextCatalog.getString("Motion") + " " + id,
|
||||||
style: 'header',
|
style: 'title',
|
||||||
margin: [space.left, space.top, 0, 0]
|
|
||||||
}, {
|
}, {
|
||||||
text: title,
|
text: title,
|
||||||
margin: [space.left, 0, 0, space.bottom]
|
style: 'description'
|
||||||
},
|
},
|
||||||
createBallotEntry(gettextCatalog.getString("Yes")),
|
PdfPredefinedFunctions.createBallotEntry(gettextCatalog.getString("Yes")),
|
||||||
createBallotEntry(gettextCatalog.getString("No")),
|
PdfPredefinedFunctions.createBallotEntry(gettextCatalog.getString("No")),
|
||||||
createBallotEntry(gettextCatalog.getString("Abstain")),
|
PdfPredefinedFunctions.createBallotEntry(gettextCatalog.getString("Abstain")),
|
||||||
],
|
],
|
||||||
margin: [0, 0, 0, sheetend]
|
margin: [0, 0, 0, sheetend]
|
||||||
};
|
};
|
||||||
@ -280,8 +223,9 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
* @function
|
* @function
|
||||||
* @param {string} id - if of poll
|
* @param {string} id - if of poll
|
||||||
*/
|
*/
|
||||||
return {
|
|
||||||
content: [{
|
var getContent = function() {
|
||||||
|
return [{
|
||||||
table: {
|
table: {
|
||||||
headerRows: 1,
|
headerRows: 1,
|
||||||
widths: ['*', '*'],
|
widths: ['*', '*'],
|
||||||
@ -292,27 +236,18 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
[createSection(), createSection()]
|
[createSection(), createSection()]
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
layout: {
|
layout: PdfPredefinedFunctions.getBallotLayoutLines()
|
||||||
hLineWidth: function() {return 0.5;},
|
}];
|
||||||
vLineWidth: function() {return 0.5;},
|
};
|
||||||
hLineColor: function() {return 'gray';},
|
|
||||||
vLineColor: function() {return 'gray';},
|
return {
|
||||||
}
|
getContent: getContent,
|
||||||
}],
|
|
||||||
pageSize: 'A4',
|
|
||||||
pageMargins: [0, 0, 0, 0],
|
|
||||||
styles: {
|
|
||||||
header: {
|
|
||||||
fontSize: fontSize,
|
|
||||||
bold: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
createInstance: createInstance
|
createInstance: createInstance
|
||||||
};
|
};
|
||||||
})
|
}])
|
||||||
|
|
||||||
.factory('MotionCatalogContentProvider', [
|
.factory('MotionCatalogContentProvider', [
|
||||||
'gettextCatalog',
|
'gettextCatalog',
|
||||||
|
@ -20,14 +20,6 @@ angular.module('OpenSlidesApp.users.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
|
|
||||||
angular.forEach(userList, function (user, counter) {
|
angular.forEach(userList, function (user, counter) {
|
||||||
|
|
||||||
//check if the row is even or odd
|
|
||||||
var rowStyle = [];
|
|
||||||
if (counter % 2 === 0) {
|
|
||||||
rowStyle = 'tableEven';
|
|
||||||
} else {
|
|
||||||
rowStyle = 'tableOdd';
|
|
||||||
}
|
|
||||||
|
|
||||||
//parse for the group names
|
//parse for the group names
|
||||||
var userGroups = [];
|
var userGroups = [];
|
||||||
angular.forEach(user.groups_id, function (id) {
|
angular.forEach(user.groups_id, function (id) {
|
||||||
@ -43,19 +35,19 @@ angular.module('OpenSlidesApp.users.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
var userJsonObj = [
|
var userJsonObj = [
|
||||||
{
|
{
|
||||||
text: "" + (counter+1),
|
text: "" + (counter+1),
|
||||||
style: rowStyle
|
style: PdfPredefinedFunctions.flipTableRowStyle(userJsonList.length)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: user.short_name,
|
text: user.short_name,
|
||||||
style: rowStyle
|
style: PdfPredefinedFunctions.flipTableRowStyle(userJsonList.length)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: user.structure_level,
|
text: user.structure_level,
|
||||||
style: rowStyle
|
style: PdfPredefinedFunctions.flipTableRowStyle(userJsonList.length)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: userGroups.join(" "),
|
text: userGroups.join(" "),
|
||||||
style: rowStyle
|
style: PdfPredefinedFunctions.flipTableRowStyle(userJsonList.length)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
userJsonList.push(userJsonObj);
|
userJsonList.push(userJsonObj);
|
||||||
|
Loading…
Reference in New Issue
Block a user