commit
7d2785b9ec
@ -17,6 +17,7 @@ Motions:
|
||||
- Fixed empty motion comment field in motion update form [#3194].
|
||||
- Removed server side image to base64 transformation and
|
||||
added local transformation [#2705]
|
||||
- Added support for export motions in a zip archive [#3189].
|
||||
|
||||
Core:
|
||||
- No reload on logoff. OpenSlides is now a full single page
|
||||
|
@ -28,6 +28,7 @@
|
||||
"jquery.cookie": "~1.4.1",
|
||||
"js-data": "~2.9.0",
|
||||
"js-data-angular": "~3.2.1",
|
||||
"jszip": "~3.1.3",
|
||||
"lodash": "~4.16.0",
|
||||
"ng-dialog": "~0.6.4",
|
||||
"ng-file-upload": "~11.2.3",
|
||||
|
@ -859,10 +859,11 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
||||
|
||||
.factory('PdfCreate', [
|
||||
'$timeout',
|
||||
'$q',
|
||||
'gettextCatalog',
|
||||
'FileSaver',
|
||||
'Messaging',
|
||||
function ($timeout, gettextCatalog, FileSaver, Messaging) {
|
||||
function ($timeout, $q, gettextCatalog, FileSaver, Messaging) {
|
||||
var filenameMessageMap = {};
|
||||
var b64toBlob = function(b64Data) {
|
||||
var byteCharacters = atob(b64Data);
|
||||
@ -898,19 +899,28 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
||||
}, 1);
|
||||
};
|
||||
return {
|
||||
getBase64FromDocument: function (pdfDocument) {
|
||||
return $q(function (resolve, reject) {
|
||||
var pdfWorker = new Worker('/static/js/workers/pdf-worker.js');
|
||||
pdfWorker.addEventListener('message', function (event) {
|
||||
resolve(event.data);
|
||||
});
|
||||
pdfWorker.addEventListener('error', function (event) {
|
||||
reject(event);
|
||||
});
|
||||
pdfWorker.postMessage(JSON.stringify(pdfDocument));
|
||||
});
|
||||
},
|
||||
download: function (pdfDocument, filename) {
|
||||
stateChange('info', filename);
|
||||
var pdfWorker = new Worker('/static/js/workers/pdf-worker.js');
|
||||
|
||||
pdfWorker.addEventListener('message', function (event) {
|
||||
var blob = b64toBlob(event.data);
|
||||
this.getBase64FromDocument(pdfDocument).then(function (data) {
|
||||
var blob = b64toBlob(data);
|
||||
stateChange('success', filename);
|
||||
FileSaver.saveAs(blob, filename);
|
||||
}, function (error) {
|
||||
stateChange('error', filename, error.message);
|
||||
});
|
||||
pdfWorker.addEventListener('error', function (event) {
|
||||
stateChange('error', filename, event.message);
|
||||
});
|
||||
pdfWorker.postMessage(JSON.stringify(pdfDocument));
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -288,7 +288,6 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
for (var i = 0; i < fields.length; i++) {
|
||||
if (motion.comments[i] && canSeeComment(i)) {
|
||||
var title = gettextCatalog.getString('Comment') + ' ' + fields[i].name;
|
||||
console.log(fields[i]);
|
||||
if (!fields[i].public) {
|
||||
title += ' (' + gettextCatalog.getString('internal') + ')';
|
||||
}
|
||||
@ -602,6 +601,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
|
||||
.factory('MotionPdfExport', [
|
||||
'$http',
|
||||
'$q',
|
||||
'Config',
|
||||
'gettextCatalog',
|
||||
'MotionChangeRecommendation',
|
||||
@ -614,15 +614,14 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
'PdfMakeBallotPaperProvider',
|
||||
'PdfCreate',
|
||||
'PDFLayout',
|
||||
'$q',
|
||||
function ($http, Config, gettextCatalog, MotionChangeRecommendation, HTMLValidizer, PdfMakeConverter,
|
||||
'Messaging',
|
||||
'FileSaver',
|
||||
function ($http, $q, Config, gettextCatalog, MotionChangeRecommendation, HTMLValidizer, PdfMakeConverter,
|
||||
MotionContentProvider, MotionCatalogContentProvider, PdfMakeDocumentProvider, PollContentProvider,
|
||||
PdfMakeBallotPaperProvider, PdfCreate, PDFLayout, $q) {
|
||||
PdfMakeBallotPaperProvider, PdfCreate, PDFLayout, Messaging, FileSaver) {
|
||||
return {
|
||||
export: function (motions, params, singleMotion) {
|
||||
if (!params) {
|
||||
params = {};
|
||||
}
|
||||
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,
|
||||
@ -643,11 +642,11 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
angular.forEach(motions, function (motion) {
|
||||
if (singleMotion) {
|
||||
motion.changeRecommendations = MotionChangeRecommendation.filter({
|
||||
'where': {'motion_version_id': {'==': motion.active_version}}
|
||||
'where': {'motion_version_id': {'==': params.version}}
|
||||
});
|
||||
} else {
|
||||
motion.changeRecommendations = MotionChangeRecommendation.filter({
|
||||
'where': {'motion_version_id': {'==': params.version}}
|
||||
'where': {'motion_version_id': {'==': motion.active_version}}
|
||||
});
|
||||
}
|
||||
var text = motion.getTextByMode(params.changeRecommendationMode, null);
|
||||
@ -659,43 +658,93 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
||||
image_sources = image_sources.concat(tmp_image_sources);
|
||||
});
|
||||
|
||||
var image_map = {};
|
||||
_.forEach(image_sources, function (image_source) {
|
||||
image_map[image_source] = PDFLayout.imageURLtoBase64(image_source);
|
||||
var imageMap = {};
|
||||
var imagePromises = _.map(image_sources, function (image_source) {
|
||||
return PDFLayout.imageURLtoBase64(image_source).then(function (base64Str) {
|
||||
imageMap[image_source] = base64Str;
|
||||
});
|
||||
});
|
||||
|
||||
var image_promises = Object.keys(image_map).map(function( key ) {
|
||||
return image_map[key];
|
||||
return $q(function (resolve) {
|
||||
//resolve promises to get base64
|
||||
$q.all(imagePromises).then(function(base64Str) {
|
||||
var converter = PdfMakeConverter.createInstance(imageMap);
|
||||
var motionContentProviderArray = [];
|
||||
|
||||
//convert all motions to motionContentProviders
|
||||
angular.forEach(motions, function (motion) {
|
||||
var version = (singleMotion ? params.version : motion.active_version);
|
||||
motionContentProviderArray.push(MotionContentProvider.createInstance(
|
||||
converter, motion, version, params.changeRecommendationMode,
|
||||
motion.changeRecommendations, params.lineNumberMode,
|
||||
params.includeReason, params.includeComments
|
||||
));
|
||||
});
|
||||
|
||||
var documentProvider;
|
||||
if (singleMotion) {
|
||||
documentProvider = PdfMakeDocumentProvider.createInstance(motionContentProviderArray[0]);
|
||||
} else {
|
||||
var motionCatalogContentProvider = MotionCatalogContentProvider.createInstance(motionContentProviderArray);
|
||||
documentProvider = PdfMakeDocumentProvider.createInstance(motionCatalogContentProvider);
|
||||
}
|
||||
|
||||
resolve(documentProvider);
|
||||
});
|
||||
});
|
||||
|
||||
//resolv promises to get base64
|
||||
$q.all(image_promises).then(function(base64Str) {
|
||||
Object.keys(image_map).map(function(key, i) {
|
||||
image_map[key] = base64Str[i];
|
||||
});
|
||||
|
||||
var converter = PdfMakeConverter.createInstance(image_map);
|
||||
var motionContentProviderArray = [];
|
||||
|
||||
//convert all motions to motionContentProviders
|
||||
angular.forEach(motions, function (motion) {
|
||||
var version = (singleMotion ? params.version : motion.active_version);
|
||||
motionContentProviderArray.push(MotionContentProvider.createInstance(
|
||||
converter, motion, version, params.changeRecommendationMode,
|
||||
motion.changeRecommendations, params.lineNumberMode,
|
||||
params.includeReason, params.includeComments
|
||||
));
|
||||
});
|
||||
|
||||
var documentProvider;
|
||||
if (singleMotion) {
|
||||
documentProvider = PdfMakeDocumentProvider.createInstance(motionContentProviderArray[0]);
|
||||
} else {
|
||||
var motionCatalogContentProvider = MotionCatalogContentProvider.createInstance(motionContentProviderArray);
|
||||
documentProvider = PdfMakeDocumentProvider.createInstance(motionCatalogContentProvider);
|
||||
},
|
||||
export: function (motions, params, singleMotion) {
|
||||
_.defaults(params, {
|
||||
filename: gettextCatalog.getString('motions') + '.pdf',
|
||||
});
|
||||
this.getDocumentProvider(motions, params, singleMotion).then(
|
||||
function (documentProvider) {
|
||||
PdfCreate.download(documentProvider.getDocument(), params.filename);
|
||||
}
|
||||
);
|
||||
},
|
||||
exportZip: function (motions, params) {
|
||||
var messageId = Messaging.addMessage('<i class="fa fa-spinner fa-pulse fa-lg spacer-right"></i>' +
|
||||
gettextCatalog.getString('Generating PDFs and ZIP archive') + ' ...', 'info');
|
||||
var zipFilename = params.filename || gettextCatalog.getString('motions') + '.zip';
|
||||
params.filename = void 0; // clear this, so we do not override the default filenames for each pdf.
|
||||
|
||||
PdfCreate.download(documentProvider.getDocument(), params.filename);
|
||||
var self = this;
|
||||
var pdfs = {};
|
||||
var pdfPromises = _.map(motions, function (motion) {
|
||||
var identifier = motion.identifier ? '-' + motion.identifier : '';
|
||||
var filename = gettextCatalog.getString('Motion') + identifier + '.pdf';
|
||||
|
||||
return $q(function (resolve, reject) {
|
||||
// get documentProvider for every motion.
|
||||
self.getDocumentProvider(motion, params, true).then(function (documentProvider) {
|
||||
var doc = documentProvider.getDocument();
|
||||
|
||||
PdfCreate.getBase64FromDocument(doc).then(function (data) {
|
||||
pdfs[filename] = data;
|
||||
resolve();
|
||||
}, function (error) {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// Wait for all documents to be generated. Then put them into a zip and download it.
|
||||
$q.all(pdfPromises).then(function () {
|
||||
var zip = new JSZip();
|
||||
_.forEach(pdfs, function (data, filename) {
|
||||
zip.file(filename, data, {base64: true});
|
||||
});
|
||||
Messaging.createOrEditMessage(messageId, '<i class="fa fa-check fa-lg spacer-right"></i>' +
|
||||
gettextCatalog.getString('ZIP successfully generated.'), 'success', {timeout: 3000});
|
||||
zip.generateAsync({type: 'blob'}).then(function (content) {
|
||||
FileSaver.saveAs(content, zipFilename);
|
||||
});
|
||||
}, function (error) {
|
||||
Messaging.createOrEditMessage(messageId, '<i class="fa fa-exclamation-triangle fa-lg ' +
|
||||
'spacer-right"></i>' + gettextCatalog.getString('Error while generating ZIP file') +
|
||||
': <code>' + error + '</code>', 'error');
|
||||
});
|
||||
},
|
||||
createPollPdf: function (motion, version) {
|
||||
|
@ -733,9 +733,23 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
],
|
||||
},
|
||||
hideExpression: "model.format !== 'pdf'",
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!singleMotion) {
|
||||
fields.push({
|
||||
key: 'pdfFormat',
|
||||
type: 'select-radio',
|
||||
templateOptions: {
|
||||
label: gettextCatalog.getString('PDF format'),
|
||||
options: [
|
||||
{name: gettextCatalog.getString('One PDF'), value: 'pdf'},
|
||||
{name: gettextCatalog.getString('Multiple PDFs in a zip arcive'), value: 'zip'},
|
||||
],
|
||||
},
|
||||
hideExpression: "model.format !== 'pdf'",
|
||||
});
|
||||
}
|
||||
return fields;
|
||||
},
|
||||
};
|
||||
@ -761,6 +775,7 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
$scope.params = params || {};
|
||||
_.defaults($scope.params, {
|
||||
format: 'pdf',
|
||||
pdfFormat: 'pdf',
|
||||
changeRecommendationMode: Config.get('motions_recommendation_text_mode').value,
|
||||
lineNumberMode: Config.get('motions_default_line_numbering').value,
|
||||
includeReason: true,
|
||||
@ -772,7 +787,11 @@ angular.module('OpenSlidesApp.motions.site', [
|
||||
$scope.export = function () {
|
||||
switch ($scope.params.format) {
|
||||
case 'pdf':
|
||||
MotionPdfExport.export(motions, $scope.params, singleMotion);
|
||||
if ($scope.params.pdfFormat === 'pdf') {
|
||||
MotionPdfExport.export(motions, $scope.params, singleMotion);
|
||||
} else {
|
||||
MotionPdfExport.exportZip(motions, $scope.params);
|
||||
}
|
||||
break;
|
||||
case 'csv':
|
||||
MotionCsvExport.export(motions, $scope.params);
|
||||
|
Loading…
Reference in New Issue
Block a user