Merge pull request #3766 from tsiegleauq/Toc-Page-Numbers
Add page numbers categories in motion TOC
This commit is contained in:
commit
2da894b517
|
@ -14,6 +14,8 @@ Motions:
|
||||||
and list views for amendments) [#3637].
|
and list views for amendments) [#3637].
|
||||||
- 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].
|
||||||
|
- Updated pdfMake to 0.1.37 [#3766].
|
||||||
|
|
||||||
|
|
||||||
Version 2.2 (2018-06-06)
|
Version 2.2 (2018-06-06)
|
||||||
|
@ -173,7 +175,7 @@ Agenda:
|
||||||
as a slide or an overlay.
|
as a slide or an overlay.
|
||||||
- Manage speakers on the current list of speakers view.
|
- Manage speakers on the current list of speakers view.
|
||||||
- List of speakers for hidden items is always visible.
|
- List of speakers for hidden items is always visible.
|
||||||
|
|
||||||
Core:
|
Core:
|
||||||
- Added support for multiple projectors.
|
- Added support for multiple projectors.
|
||||||
- Added control for the resolution of the projectors.
|
- Added control for the resolution of the projectors.
|
||||||
|
@ -222,7 +224,7 @@ Core:
|
||||||
- Moved full-text search to client-side (removed the server-side search engine Whoosh).
|
- Moved full-text search to client-side (removed the server-side search engine Whoosh).
|
||||||
- Made a lot of code clean up, improvements and bug fixes in client and
|
- Made a lot of code clean up, improvements and bug fixes in client and
|
||||||
backend.
|
backend.
|
||||||
|
|
||||||
Motions:
|
Motions:
|
||||||
- Added adjustable line numbering mode (outside, inside, none) for each
|
- Added adjustable line numbering mode (outside, inside, none) for each
|
||||||
motion text.
|
motion text.
|
||||||
|
@ -247,7 +249,7 @@ Motions:
|
||||||
- Add new personal settings to remove all whitespaces from motion identifier.
|
- Add new personal settings to remove all whitespaces from motion identifier.
|
||||||
- Add new personal settings to allow amendments of amendments.
|
- Add new personal settings to allow amendments of amendments.
|
||||||
- Added inline editing for comments.
|
- Added inline editing for comments.
|
||||||
|
|
||||||
Elections:
|
Elections:
|
||||||
- Added options to calculate percentages on different bases.
|
- Added options to calculate percentages on different bases.
|
||||||
- Added calculation for required majority.
|
- Added calculation for required majority.
|
||||||
|
@ -255,7 +257,7 @@ Elections:
|
||||||
- Removed unused assignment config to publish winner election results only.
|
- Removed unused assignment config to publish winner election results only.
|
||||||
- Number of ballots printed can now be set in config.
|
- Number of ballots printed can now be set in config.
|
||||||
- Added inline edit field for a specific hint on ballot papers.
|
- Added inline edit field for a specific hint on ballot papers.
|
||||||
|
|
||||||
Users:
|
Users:
|
||||||
- Added new matrix-interface for managing groups and their permissions.
|
- Added new matrix-interface for managing groups and their permissions.
|
||||||
- Added autoupdate on permission change (permission added).
|
- Added autoupdate on permission change (permission added).
|
||||||
|
@ -267,13 +269,13 @@ Users:
|
||||||
- Allowed to import/export initial user password.
|
- Allowed to import/export initial user password.
|
||||||
- Added more multiselect actions.
|
- Added more multiselect actions.
|
||||||
- Added QR code in users access pdf.
|
- Added QR code in users access pdf.
|
||||||
|
|
||||||
Mediafiles:
|
Mediafiles:
|
||||||
- Allowed to project uploaded images (png, jpg, gif) and video files
|
- Allowed to project uploaded images (png, jpg, gif) and video files
|
||||||
(e. g. mp4, wmv, flv, quicktime, ogg).
|
(e. g. mp4, wmv, flv, quicktime, ogg).
|
||||||
- Allowed to hide uploaded files in overview list for non authorized users.
|
- Allowed to hide uploaded files in overview list for non authorized users.
|
||||||
- Enabled removing of files from filesystem on model instance delete.
|
- Enabled removing of files from filesystem on model instance delete.
|
||||||
|
|
||||||
Other:
|
Other:
|
||||||
- Added Russian translation (Thanks to Andreas Engler).
|
- Added Russian translation (Thanks to Andreas Engler).
|
||||||
- Added command to create example data.
|
- Added command to create example data.
|
||||||
|
@ -563,7 +565,7 @@ Agenda:
|
||||||
- New duration field for each item (with total time calculation for end time of event).
|
- New duration field for each item (with total time calculation for end time of event).
|
||||||
- Better drag'n'drop sorting of agenda items (with nestedSortable jQuery plugin).
|
- Better drag'n'drop sorting of agenda items (with nestedSortable jQuery plugin).
|
||||||
Motions:
|
Motions:
|
||||||
- Integrated CKEditor to use allowed HTML formatting in motion text/reason.
|
- Integrated CKEditor to use allowed HTML formatting in motion text/reason.
|
||||||
With server-side whitelist filtering of HTML tags (with bleach) and HTML support
|
With server-side whitelist filtering of HTML tags (with bleach) and HTML support
|
||||||
for reportlab in motion pdf.
|
for reportlab in motion pdf.
|
||||||
- New motion API.
|
- New motion API.
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
"ngstorage": "~0.3.11",
|
"ngstorage": "~0.3.11",
|
||||||
"ngBootbox": "~0.1.3",
|
"ngBootbox": "~0.1.3",
|
||||||
"papaparse": "~4.1.2",
|
"papaparse": "~4.1.2",
|
||||||
"pdfmake": "0.1.33",
|
"pdfmake": "0.1.37",
|
||||||
"roboto-fontface": "~0.6.0"
|
"roboto-fontface": "~0.6.0"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
|
|
|
@ -360,9 +360,23 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
margin: [15,5]
|
margin: [15,5]
|
||||||
},
|
},
|
||||||
tableofcontent: {
|
tocEntry: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
margin: [0,3]
|
margin: [0,0,0,0],
|
||||||
|
bold: false
|
||||||
|
},
|
||||||
|
tocCategoryEntry: {
|
||||||
|
fontSize: 12,
|
||||||
|
margin: [10,0,0,0],
|
||||||
|
bold: false
|
||||||
|
},
|
||||||
|
tocCategoryTitle: {
|
||||||
|
fontSize: 12,
|
||||||
|
margin: [0,0,0,0],
|
||||||
|
bold: true,
|
||||||
|
},
|
||||||
|
tocCategorySection: {
|
||||||
|
margin: [0,0,0,10],
|
||||||
},
|
},
|
||||||
listParent: {
|
listParent: {
|
||||||
fontSize: 12,
|
fontSize: 12,
|
||||||
|
|
|
@ -460,6 +460,10 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||||
return motion.identifier ? motion.identifier : '';
|
return motion.identifier ? motion.identifier : '';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var getId = function() {
|
||||||
|
return motion.id;
|
||||||
|
};
|
||||||
|
|
||||||
var getCategory = function() {
|
var getCategory = function() {
|
||||||
return motion.category;
|
return motion.category;
|
||||||
};
|
};
|
||||||
|
@ -476,6 +480,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||||
getContent: getContent,
|
getContent: getContent,
|
||||||
getTitle: getTitle,
|
getTitle: getTitle,
|
||||||
getIdentifier: getIdentifier,
|
getIdentifier: getIdentifier,
|
||||||
|
getId: getId,
|
||||||
getCategory: getCategory,
|
getCategory: getCategory,
|
||||||
getImageMap: getImageMap,
|
getImageMap: getImageMap,
|
||||||
});
|
});
|
||||||
|
@ -833,8 +838,9 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||||
* Constructor
|
* Constructor
|
||||||
* @function
|
* @function
|
||||||
* @param {object} allMotions - A sorted array of all motions to parse
|
* @param {object} allMotions - A sorted array of all motions to parse
|
||||||
|
* @param {string} sorting - The way the catalog has been sorted. Necessary for ToC
|
||||||
*/
|
*/
|
||||||
var createInstance = function(allMotions) {
|
var createInstance = function(allMotions, sorting) {
|
||||||
|
|
||||||
var title = PDFLayout.createTitle(
|
var title = PDFLayout.createTitle(
|
||||||
Config.translate(Config.get('motions_export_title').value)
|
Config.translate(Config.get('motions_export_title').value)
|
||||||
|
@ -853,84 +859,130 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||||
};
|
};
|
||||||
|
|
||||||
var createTOContent = function() {
|
var createTOContent = function() {
|
||||||
var heading = {
|
var toc = [];
|
||||||
text: gettextCatalog.getString("Table of contents"),
|
var exportCategory = (sorting === 'identifier' || sorting === 'category.prefix');
|
||||||
style: "heading2"
|
var uniqueCategories = getUniqueCategories();
|
||||||
|
var tocTitle = {
|
||||||
|
text: gettextCatalog.getString('Table of contents'),
|
||||||
|
style: 'heading2'
|
||||||
};
|
};
|
||||||
|
|
||||||
var toc = [];
|
// all motions need a page ID. We use the motion identifier for that
|
||||||
angular.forEach(allMotions, function(motion) {
|
_.forEach(allMotions, function (motion) {
|
||||||
var identifier = motion.getIdentifier() ? motion.getIdentifier() : '';
|
motion.getContent()[0].id = ''+motion.getId();
|
||||||
toc.push(
|
|
||||||
{
|
|
||||||
columns: [
|
|
||||||
{
|
|
||||||
text: identifier,
|
|
||||||
style: 'tableofcontent',
|
|
||||||
width: 70
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: motion.getTitle(),
|
|
||||||
style: 'tableofcontent'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (exportCategory && uniqueCategories) {
|
||||||
|
// own table per category
|
||||||
|
var catTocBody = [];
|
||||||
|
_.forEach(uniqueCategories, function (category) {
|
||||||
|
// push the name of the category
|
||||||
|
// make a table for correct alignment
|
||||||
|
catTocBody.push({
|
||||||
|
table: {
|
||||||
|
body: [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: category.prefix + ' - ' + category.name,
|
||||||
|
style: 'tocCategoryTitle'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
]
|
||||||
|
},
|
||||||
|
layout: 'noBorders',
|
||||||
|
});
|
||||||
|
|
||||||
|
var tocBody = [];
|
||||||
|
_.forEach(allMotions, function (motion) {
|
||||||
|
if (motion.getCategory() && category.name === motion.getCategory().name) {
|
||||||
|
tocBody.push(tocLine(motion, 'tocCategoryEntry'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
catTocBody.push(tocTable(tocBody));
|
||||||
|
});
|
||||||
|
|
||||||
|
//handle thouse without category
|
||||||
|
var uncatTocBody = [];
|
||||||
|
_.forEach(allMotions, function (motion) {
|
||||||
|
if (!motion.getCategory()) {
|
||||||
|
uncatTocBody.push(tocLine(motion, 'tocEntry'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// only push this array if there is at least one entry
|
||||||
|
if (uncatTocBody.length > 0) {
|
||||||
|
catTocBody.push(tocTable(uncatTocBody));
|
||||||
|
}
|
||||||
|
|
||||||
|
toc.push(catTocBody);
|
||||||
|
} else {
|
||||||
|
// all categories in the same table
|
||||||
|
var tocBody = [];
|
||||||
|
_.forEach(allMotions, function (motion) {
|
||||||
|
tocBody.push(tocLine(motion, 'tocEntry'));
|
||||||
|
});
|
||||||
|
toc.push(tocTable(tocBody));
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
heading,
|
tocTitle,
|
||||||
toc,
|
toc,
|
||||||
PDFLayout.addPageBreak()
|
PDFLayout.addPageBreak()
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
// function to create the table of catergories (if any)
|
// creates a new table of contents table body
|
||||||
var createTOCategories = function() {
|
var tocTable = function (tocBody) {
|
||||||
|
return {
|
||||||
|
table: {
|
||||||
|
widths: ['auto', '*', 'auto'],
|
||||||
|
body: tocBody
|
||||||
|
},
|
||||||
|
layout: 'noBorders',
|
||||||
|
style: 'tocCategorySection'
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// generates a line in the toc as list-object
|
||||||
|
var tocLine = function (motion, style) {
|
||||||
|
var firstColumn = "";
|
||||||
|
if (motion.getIdentifier()) {
|
||||||
|
firstColumn = motion.getIdentifier();
|
||||||
|
}
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: firstColumn,
|
||||||
|
style: style
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: motion.getTitle(),
|
||||||
|
style: 'tocEntry'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pageReference: ''+motion.getId(),
|
||||||
|
style: 'tocEntry',
|
||||||
|
alignment: 'right'
|
||||||
|
},
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns a list of unique category names
|
||||||
|
// necessary to create a ToC with categories
|
||||||
|
// if a motions without category is found,
|
||||||
|
// a corresponding entry should be added aswell
|
||||||
|
var getUniqueCategories = function() {
|
||||||
var categories = [];
|
var categories = [];
|
||||||
_.forEach(allMotions, function (motion) {
|
_.forEach(allMotions, function (motion) {
|
||||||
var category = motion.getCategory();
|
if (motion.getCategory()) {
|
||||||
if (category) {
|
categories.push(
|
||||||
categories.push(category);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var sortKey = Config.get('motions_export_category_sorting').value;
|
|
||||||
categories = _.orderBy(_.uniqBy(categories, 'id'), [sortKey]);
|
|
||||||
if (categories.length > 1) {
|
|
||||||
var heading = {
|
|
||||||
text: gettextCatalog.getString('Categories'),
|
|
||||||
style: 'heading2',
|
|
||||||
};
|
|
||||||
|
|
||||||
var toc = [];
|
|
||||||
angular.forEach(categories, function(cat) {
|
|
||||||
toc.push(
|
|
||||||
{
|
{
|
||||||
columns: [
|
name: motion.getCategory().name,
|
||||||
{
|
prefix: motion.getCategory().prefix
|
||||||
text: cat.prefix,
|
|
||||||
style: 'tableofcontent',
|
|
||||||
width: 50
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: cat.name,
|
|
||||||
style: 'tableofcontent'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
}
|
||||||
|
});
|
||||||
return [
|
return _.uniqBy(categories, 'name');
|
||||||
heading,
|
|
||||||
toc,
|
|
||||||
PDFLayout.addPageBreak()
|
|
||||||
];
|
|
||||||
} else {
|
|
||||||
// if there are no categories, return "empty string"
|
|
||||||
// pdfmake takes "null" literally and throws an error
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// returns the pure content of the motion, parseable by pdfmake
|
// returns the pure content of the motion, parseable by pdfmake
|
||||||
|
@ -948,7 +1000,6 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||||
content.push(
|
content.push(
|
||||||
title,
|
title,
|
||||||
createPreamble(),
|
createPreamble(),
|
||||||
createTOCategories(),
|
|
||||||
createTOContent()
|
createTOContent()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1253,7 +1304,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||||
if (singleMotion) {
|
if (singleMotion) {
|
||||||
documentProviderPromise = PdfMakeDocumentProvider.createInstance(motionContentProviderArray[0]);
|
documentProviderPromise = PdfMakeDocumentProvider.createInstance(motionContentProviderArray[0]);
|
||||||
} else {
|
} else {
|
||||||
var motionCatalogContentProvider = MotionCatalogContentProvider.createInstance(motionContentProviderArray);
|
var motionCatalogContentProvider = MotionCatalogContentProvider.createInstance(motionContentProviderArray, params.column);
|
||||||
documentProviderPromise = PdfMakeDocumentProvider.createInstance(motionCatalogContentProvider);
|
documentProviderPromise = PdfMakeDocumentProvider.createInstance(motionCatalogContentProvider);
|
||||||
}
|
}
|
||||||
documentProviderPromise.then(function (documentProvider) {
|
documentProviderPromise.then(function (documentProvider) {
|
||||||
|
|
|
@ -1454,7 +1454,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||||
};
|
};
|
||||||
// Export dialog
|
// Export dialog
|
||||||
$scope.openExportDialog = function (motions) {
|
$scope.openExportDialog = function (motions) {
|
||||||
ngDialog.open(MotionExportForm.getDialog(motions));
|
ngDialog.open(MotionExportForm.getDialog(motions, $scope.sort));
|
||||||
};
|
};
|
||||||
$scope.pdfExport = function (motions) {
|
$scope.pdfExport = function (motions) {
|
||||||
MotionPdfExport.export(motions);
|
MotionPdfExport.export(motions);
|
||||||
|
|
Loading…
Reference in New Issue