diff --git a/CHANGELOG b/CHANGELOG index 5d9895ea1..915486123 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -52,12 +52,14 @@ Motions: - Added DOCX export with docxtemplater. - Changed label of former state "commited a bill" to "refered to committee". - New csv import layout and using Papa Parse for parsing the csv. +- Number of ballots printed can now be set in config. Elections: - Added options to calculate percentages on different bases. - Added calculation for required majority. - Candidates are now sortable. - Removed unused assignment config to publish winner election results only. +- Number of ballots printed can now be set in config. Users: - Added new matrix-interface for managing groups and their permissions. diff --git a/openslides/assignments/static/js/assignments/pdf.js b/openslides/assignments/static/js/assignments/pdf.js index f73c95e20..d27f36c48 100644 --- a/openslides/assignments/static/js/assignments/pdf.js +++ b/openslides/assignments/static/js/assignments/pdf.js @@ -268,8 +268,9 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf']) '$filter', 'gettextCatalog', 'PDFLayout', - function($filter, gettextCatalog, PDFLayout) { - + 'Config', + 'User', + function($filter, gettextCatalog, PDFLayout, Config, User) { var createInstance = function(scope, poll, pollNumber) { // page title @@ -367,58 +368,104 @@ angular.module('OpenSlidesApp.assignments.pdf', ['OpenSlidesApp.core.pdf']) }; }; - var createTableBody = function(numberOfRows, sheetend) { + var createTableBody = function(numberOfRows, sheetend, maxballots) { + var ballotstoprint = numberOfRows * 2; + if (Number.isInteger(maxballots) && maxballots > 0 && maxballots < ballotstoprint) { + ballotstoprint = maxballots; + } var tableBody = []; - for (var i = 0; i < numberOfRows; i++) { + while (ballotstoprint > 1){ tableBody.push([createSection(sheetend), createSection(sheetend)]); + ballotstoprint -= 2; + } + if (ballotstoprint == 1) { + tableBody.push([createSection(sheetend), '']); } return tableBody; }; var createContentTable = function() { - - var tableBody = []; + // first, determine how many ballots we need + var amount; + var amount_method = Config.get('assignments_pdf_ballot_papers_selection').value; + switch (amount_method) { + case 'NUMBER_OF_ALL_PARTICIPANTS': + amount = User.getAll().length; + break; + case 'NUMBER_OF_DELEGATES': + //TODO: assumption that DELEGATES is always group id 2. This may not be true + var group_id = 2; + amount = User.filter({where: {'groups_id': {contains:group_id} }}).length; + break; + case 'CUSTOM_NUMBER': + amount = Config.get('assignments_pdf_ballot_papers_number').value; + break; + default: + // should not happen. + amount = 0; + } + var tabledContent = []; + var rowsperpage; var sheetend; - if (poll.pollmethod == 'votes') { if (poll.options.length <= 4) { sheetend = 105; - tableBody = createTableBody(4, sheetend); + rowsperpage = 4; } else if (poll.options.length <= 8) { sheetend = 140; - tableBody = tableBody = createTableBody(3, sheetend); + rowsperpage = 3; } else if (poll.options.length <= 12) { sheetend = 210; - tableBody = tableBody = createTableBody(2, sheetend); + rowsperpage = 2; } else { //works untill ~30 people sheetend = 418; - tableBody = createTableBody(1, sheetend); + rowsperpage = 1; } } else { if (poll.options.length <= 2) { sheetend = 105; - tableBody = createTableBody(4, sheetend); + rowsperpage = 4; } else if (poll.options.length <= 4) { sheetend = 140; - tableBody = createTableBody(3, sheetend); + rowsperpage = 3; } else if (poll.options.length <= 6) { sheetend = 210; - tableBody = createTableBody(2, sheetend); + rowsperpage = 2; } else { sheetend = 418; - tableBody = createTableBody(1, sheetend); + rowsperpage = 1; } } - - return [{ - table: { - headerRows: 1, - widths: ['50%', '50%'], - body: tableBody - }, - layout: PDFLayout.getBallotLayoutLines() - }]; + var page_entries = rowsperpage * 2; + var fullpages = Math.floor(amount / page_entries); + for (var i=0; i < fullpages; i++) { + tabledContent.push({ + table: { + headerRows: 1, + widths: ['50%', '50%'], + body: createTableBody(rowsperpage, sheetend), + pageBreak: 'after' + }, + layout: PDFLayout.getBallotLayoutLines(), + rowsperpage: rowsperpage + }); + } + // fill the last page only partially + var lastpage_ballots = amount - (fullpages * page_entries); + if (lastpage_ballots < page_entries && lastpage_ballots > 0){ + var partialpage = createTableBody(rowsperpage, sheetend, lastpage_ballots); + tabledContent.push({ + table: { + headerRows: 1, + widths: ['50%', '50%'], + body: partialpage + }, + layout: PDFLayout.getBallotLayoutLines(), + rowsperpage: rowsperpage + }); + } + return tabledContent; }; var getContent = function() { diff --git a/openslides/core/static/js/core/pdf.js b/openslides/core/static/js/core/pdf.js index 6e06394de..4351df837 100644 --- a/openslides/core/static/js/core/pdf.js +++ b/openslides/core/static/js/core/pdf.js @@ -102,13 +102,33 @@ angular.module('OpenSlidesApp.core.pdf', []) PDFLayout.getBallotLayoutLines = function() { return { hLineWidth: function(i, node) { - return (i === 0 || i === node.table.body.length) ? 0 : 0.5; + if (i === 0){ + return 0; + } else if (i === node.table.body.length) { + if (node.rowsperpage && node.rowsperpage > i) { + return 0.5; + } else { + return 0; + } + } else { + return 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'; + if (i === 0){ + return 'none'; + } else if (i === node.table.body.length) { + if (node.rowsperpage && node.rowsperpage > i) { + return 'gray'; + } else { + return 'none'; + } + } else { + return 'gray'; + } }, vLineColor: function(i, node) { return (i === 0 || i === node.table.widths.length) ? 'none' : 'gray'; diff --git a/openslides/motions/static/js/motions/pdf.js b/openslides/motions/static/js/motions/pdf.js index 2ee5fe0ed..75f2847bb 100644 --- a/openslides/motions/static/js/motions/pdf.js +++ b/openslides/motions/static/js/motions/pdf.js @@ -330,7 +330,9 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf']) .factory('PollContentProvider', [ 'PDFLayout', - function(PDFLayout) { + 'Config', + 'User', + function(PDFLayout, Config, User) { /** * Generates a content provider for polls * @constructor @@ -367,21 +369,66 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf']) * @function * @param {string} id - if of poll */ - var getContent = function() { - return [{ - table: { - headerRows: 1, - widths: ['*', '*'], - body: [ - [createSection(), createSection()], - [createSection(), createSection()], - [createSection(), createSection()], - [createSection(), createSection()] - ], - }, - layout: PDFLayout.getBallotLayoutLines() - }]; + var content = []; + var amount; + var amount_method = Config.get('motions_pdf_ballot_papers_selection').value; + switch (amount_method) { + case 'NUMBER_OF_ALL_PARTICIPANTS': + amount = User.getAll().length; + break; + case 'NUMBER_OF_DELEGATES': + //TODO: assumption that DELEGATES is always group id 2. This may not be true + var group_id = 2; + amount = User.filter({where: {'groups_id': {contains:group_id} }}).length; + break; + case 'CUSTOM_NUMBER': + amount = Config.get('motions_pdf_ballot_papers_number').value; + break; + default: + // should not happen. + amount = 0; + } + var fullpages = Math.floor(amount / 8); + + for (var i=0; i < fullpages; i++) { + content.push({ + table: { + headerRows: 1, + widths: ['*', '*'], + body: [ + [createSection(), createSection()], + [createSection(), createSection()], + [createSection(), createSection()], + [createSection(), createSection()] + ], + pageBreak: 'after' + }, + layout: PDFLayout.getBallotLayoutLines(), + rowsperpage: 4 + }); + } + amount = amount - (fullpages * 8); + if (amount > 0) { + var partialpagebody = []; + while (amount > 1) { + partialpagebody.push([createSection(), createSection()]); + amount -=2; + } + if (amount == 1) { + partialpagebody.push([createSection(), '']); + } + content.push({ + table: { + headerRows: 1, + widths: ['50%', '50%'], + body: partialpagebody + }, + layout: PDFLayout.getBallotLayoutLines(), + rowsperpage: 4 + }); + } + return content; }; return {