Merge pull request #2430 from tsiegleauq/issue2299-motion-katalog
Add motion catalog over pdfmake (fixes #2299)
This commit is contained in:
commit
f305d19856
@ -89,6 +89,22 @@ angular.module('OpenSlidesApp.core.site', [
|
|||||||
header: header,
|
header: header,
|
||||||
footer: footer,
|
footer: footer,
|
||||||
content: content,
|
content: content,
|
||||||
|
styles: {
|
||||||
|
title: {
|
||||||
|
fontSize: 30,
|
||||||
|
margin: [0,0,0,20],
|
||||||
|
bold: true
|
||||||
|
},
|
||||||
|
heading: {
|
||||||
|
fontSize: 16,
|
||||||
|
margin: [0,0,0,10],
|
||||||
|
bold: true
|
||||||
|
},
|
||||||
|
tableofcontent: {
|
||||||
|
fontSize: 12,
|
||||||
|
margin: [0,3]
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
|
@ -9,223 +9,182 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
|
|||||||
* Provides the content as JS objects for Motions in pdfMake context
|
* Provides the content as JS objects for Motions in pdfMake context
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
var createInstance = function(converter) {
|
|
||||||
/**
|
|
||||||
* Text of motion
|
|
||||||
* @function
|
|
||||||
* @param {object} motion - Current motion
|
|
||||||
* @param {object} $scope - Current $scope
|
|
||||||
*/
|
|
||||||
var textContent = function(motion, $scope) {
|
|
||||||
if ($scope.lineNumberMode == "inline" || $scope.lineNumberMode == "outside") {
|
|
||||||
/* in order to distinguish between the line-number-types we need to pass the scope
|
|
||||||
* to the convertHTML function.
|
|
||||||
* We should avoid this, since this completly breaks compatibilty for every
|
|
||||||
* other project that might want to use this HTML to PDF parser.
|
|
||||||
* https://github.com/OpenSlides/OpenSlides/issues/2361
|
|
||||||
*/
|
|
||||||
return converter.convertHTML($scope.lineBrokenText, $scope);
|
|
||||||
} else {
|
|
||||||
return converter.convertHTML(motion.getText($scope.version), $scope);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Generate text of reason
|
|
||||||
* @function
|
|
||||||
* @param {object} motion - Current motion
|
|
||||||
* @param {object} $scope - Current $scope
|
|
||||||
*/
|
|
||||||
reasonContent = function(motion, $scope) {
|
|
||||||
return converter.convertHTML(motion.getReason($scope.version), $scope);
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Generate header text of motion
|
|
||||||
* @function
|
|
||||||
* @param {object} motion - Current motion
|
|
||||||
* @param {object} $scope - Current $scope
|
|
||||||
*/
|
|
||||||
motionHeader = function(motion, $scope) {
|
|
||||||
var header = converter.createElement("text", gettextCatalog.getString("Motion") + " " + motion.identifier + ": " + motion.getTitle($scope.version));
|
|
||||||
header.bold = true;
|
|
||||||
header.fontSize = 26;
|
|
||||||
return header;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Generate text of signment
|
|
||||||
* @function
|
|
||||||
* @param {object} motion - Current motion
|
|
||||||
* @param {object} $scope - Current $scope
|
|
||||||
* @param {object} User - Current user
|
|
||||||
*/
|
|
||||||
signment = function(motion, $scope, User) {
|
|
||||||
var label = converter.createElement("text", gettextCatalog.getString('Submitter') + ':\nStatus:');
|
|
||||||
var state = converter.createElement("text", User.get(motion.submitters_id[0]).full_name + '\n'+gettextCatalog.getString(motion.state.name));
|
|
||||||
state.width = "70%";
|
|
||||||
label.width = "30%";
|
|
||||||
label.bold = true;
|
|
||||||
var signment = converter.createElement("columns", [label, state]);
|
|
||||||
signment.margin = [10, 20, 0, 10];
|
|
||||||
signment.lineHeight = 2.5;
|
|
||||||
return signment;
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Generates polls
|
|
||||||
* @function
|
|
||||||
* @param {object} motion - Current motion
|
|
||||||
* @param {object} $scope - Current $scope
|
|
||||||
*/
|
|
||||||
polls = function(motion, $scope) {
|
|
||||||
if (!motion.polls.length) return {};
|
|
||||||
var pollLabel = converter.createElement("text", gettextCatalog.getString('Voting result') + ":"),
|
|
||||||
results = function() {
|
|
||||||
return motion.polls.map(function(poll, index) {
|
|
||||||
var id = index + 1,
|
|
||||||
yes = poll.yes ? poll.yes : '-', // if no poll.yes is given set it to '-'
|
|
||||||
yesRelative = poll.getVote(poll.yes, 'yes').percentStr,
|
|
||||||
no = poll.no ? poll.no : '-',
|
|
||||||
noRelative = poll.getVote(poll.no, 'no').percentStr,
|
|
||||||
abstain = poll.abstain ? poll.abstain : '-',
|
|
||||||
abstainRelative = poll.getVote(poll.abstain, 'abstain').percentStr,
|
|
||||||
valid = poll.votesvalid ? poll.votesvalid : '-',
|
|
||||||
validRelative = poll.getVote(poll.votesvalid, 'votesvalid').percentStr,
|
|
||||||
number = {
|
|
||||||
text: id + ".",
|
|
||||||
width: "5%"
|
|
||||||
},
|
|
||||||
headerText = {
|
|
||||||
text: gettextCatalog.getString('Vote'),
|
|
||||||
width: "15%"
|
|
||||||
},
|
|
||||||
/**
|
|
||||||
* Generates a part (consisting of different columns) of the polls
|
|
||||||
*
|
|
||||||
* Example Ja 100 ( 90% )
|
|
||||||
*
|
|
||||||
* @function
|
|
||||||
* @param {string} name - E.g. "Ja"
|
|
||||||
* @param {number} value - E.g.100
|
|
||||||
* @param {number} relValue - E.g. 90
|
|
||||||
*/
|
|
||||||
createPart = function(name, value, relValue) {
|
|
||||||
var indexColumn = converter.createElement("text");
|
|
||||||
var nameColumn = converter.createElement("text", "" + name);
|
|
||||||
var valueColumn = converter.createElement("text", "" + value);
|
|
||||||
var relColumn = converter.createElement("text", relValue);
|
|
||||||
valueColumn.width = "40%";
|
|
||||||
indexColumn.width = "5%";
|
|
||||||
valueColumn.width = "5%";
|
|
||||||
valueColumn.alignment = "right";
|
|
||||||
relColumn.margin = [5, 0, 0, 0];
|
|
||||||
return [indexColumn, nameColumn, valueColumn, relColumn];
|
|
||||||
},
|
|
||||||
yesPart = converter.createElement("columns", createPart(gettextCatalog.getString("Yes"), yes, yesRelative)),
|
|
||||||
noPart = converter.createElement("columns", createPart(gettextCatalog.getString("No"), no, noRelative)),
|
|
||||||
abstainPart = converter.createElement("columns", createPart(gettextCatalog.getString("Abstain"), abstain, abstainRelative)),
|
|
||||||
totalPart = converter.createElement("columns", createPart(gettextCatalog.getString("Valid ballots"), valid, validRelative)),
|
|
||||||
heading = converter.createElement("columns", [number, headerText]),
|
|
||||||
pollResult = converter.createElement("stack", [
|
|
||||||
heading, yesPart, noPart, abstainPart, totalPart
|
|
||||||
]);
|
|
||||||
|
|
||||||
return pollResult;
|
var createInstance = function(converter, motion, $scope, User) {
|
||||||
}, {});
|
|
||||||
};
|
// generates the text of the motion. Also septerates between line-numbers
|
||||||
pollLabel.width = '35%';
|
var textContent = function() {
|
||||||
pollLabel.bold = true;
|
if ($scope.lineNumberMode == "inline" || $scope.lineNumberMode == "outside") {
|
||||||
var result = converter.createElement("columns", [pollLabel, results()]);
|
/* in order to distinguish between the line-number-types we need to pass the scope
|
||||||
result.margin = [10, 0, 0, 10];
|
* to the convertHTML function.
|
||||||
result.lineHeight = 1;
|
* We should avoid this, since this completly breaks compatibilty for every
|
||||||
return result;
|
* other project that might want to use this HTML to PDF parser.
|
||||||
},
|
* https://github.com/OpenSlides/OpenSlides/issues/2361
|
||||||
/**
|
*/
|
||||||
* Generates title section for motion
|
return converter.convertHTML($scope.lineBrokenText, $scope);
|
||||||
* @function
|
} else {
|
||||||
* @param {object} motion - Current motion
|
return converter.convertHTML(motion.getText($scope.version), $scope);
|
||||||
* @param {object} $scope - Current $scope
|
}
|
||||||
*/
|
};
|
||||||
titleSection = function(motion, $scope) {
|
|
||||||
var title = converter.createElement("text", motion.getTitle($scope.version));
|
// Generate text of reason
|
||||||
title.bold = true;
|
var reasonContent = function() {
|
||||||
title.fontSize = 14;
|
return converter.convertHTML(motion.getReason($scope.version), $scope);
|
||||||
title.margin = [0, 0, 0, 10];
|
};
|
||||||
return title;
|
|
||||||
},
|
// Generate header text of motion
|
||||||
/**
|
var motionHeader = function() {
|
||||||
* Generates reason section for polls
|
var header = converter.createElement("text", gettextCatalog.getString("Motion") + " " + motion.identifier + ": " + motion.getTitle($scope.version));
|
||||||
* @function
|
header.bold = true;
|
||||||
* @param {object} motion - Current motion
|
header.fontSize = 26;
|
||||||
* @param {object} $scope - Current $scope
|
return header;
|
||||||
*/
|
};
|
||||||
reason = function(motion, $scope) {
|
|
||||||
var r = converter.createElement("text", gettextCatalog.getString("Reason") + ":");
|
// Generate text of signment
|
||||||
r.bold = true;
|
var signment = function() {
|
||||||
r.fontSize = 14;
|
var label = converter.createElement("text", gettextCatalog.getString('Submitter') + ':\nStatus:');
|
||||||
r.margin = [0, 30, 0, 10];
|
var state = converter.createElement("text", User.get(motion.submitters_id[0]).full_name + '\n'+gettextCatalog.getString(motion.state.name));
|
||||||
return r;
|
state.width = "70%";
|
||||||
},
|
label.width = "30%";
|
||||||
/**
|
label.bold = true;
|
||||||
* Generates content as a pdfmake consumable
|
var signment = converter.createElement("columns", [label, state]);
|
||||||
* @function
|
signment.margin = [10, 20, 0, 10];
|
||||||
* @param {object} motion - Current motion
|
signment.lineHeight = 2.5;
|
||||||
* @param {object} $scope - Current $scope
|
return signment;
|
||||||
* @param {object} User - Current user
|
};
|
||||||
*/
|
|
||||||
getContent = function(motion, $scope, User) {
|
// Generates polls
|
||||||
if (reasonContent(motion, $scope).length === 0 ) {
|
var polls = function() {
|
||||||
return [
|
if (!motion.polls.length) return {};
|
||||||
motionHeader(motion, $scope),
|
var pollLabel = converter.createElement("text", gettextCatalog.getString('Voting result') + ":"),
|
||||||
signment(motion, $scope, User),
|
results = function() {
|
||||||
polls(motion, $scope),
|
return motion.polls.map(function(poll, index) {
|
||||||
titleSection(motion, $scope),
|
var id = index + 1,
|
||||||
textContent(motion, $scope),
|
yes = poll.yes ? poll.yes : '-', // if no poll.yes is given set it to '-'
|
||||||
];
|
yesRelative = poll.getVote(poll.yes, 'yes').percentStr,
|
||||||
} else {
|
no = poll.no ? poll.no : '-',
|
||||||
return [
|
noRelative = poll.getVote(poll.no, 'no').percentStr,
|
||||||
motionHeader(motion, $scope),
|
abstain = poll.abstain ? poll.abstain : '-',
|
||||||
signment(motion, $scope, User),
|
abstainrelativeGet = poll.getVote(poll.abstain, 'abstain').percentStr,
|
||||||
polls(motion, $scope),
|
abstainRelative = abstainrelativeGet ? abstainrelativeGet : '',
|
||||||
titleSection(motion, $scope),
|
valid = poll.votesvalid ? poll.votesvalid : '-',
|
||||||
textContent(motion, $scope),
|
validRelative = poll.getVote(poll.votesvalid, 'votesvalid').percentStr,
|
||||||
reason(motion, $scope),
|
number = {
|
||||||
reasonContent(motion, $scope)
|
text: id + ".",
|
||||||
];
|
width: "5%"
|
||||||
}
|
},
|
||||||
};
|
headerText = {
|
||||||
|
text: gettextCatalog.getString('Vote'),
|
||||||
|
width: "15%"
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Generates a part (consisting of different columns) of the polls
|
||||||
|
*
|
||||||
|
* Example Ja 100 ( 90% )
|
||||||
|
*
|
||||||
|
* @function
|
||||||
|
* @param {string} name - E.g. "Ja"
|
||||||
|
* @param {number} value - E.g.100
|
||||||
|
* @param {number} relValue - E.g. 90
|
||||||
|
*/
|
||||||
|
createPart = function(name, value, relValue) {
|
||||||
|
var indexColumn = converter.createElement("text");
|
||||||
|
var nameColumn = converter.createElement("text", "" + name);
|
||||||
|
var valueColumn = converter.createElement("text", "" + value);
|
||||||
|
var relColumn = converter.createElement("text", relValue);
|
||||||
|
valueColumn.width = "40%";
|
||||||
|
indexColumn.width = "5%";
|
||||||
|
valueColumn.width = "5%";
|
||||||
|
valueColumn.alignment = "right";
|
||||||
|
relColumn.margin = [5, 0, 0, 0];
|
||||||
|
return [indexColumn, nameColumn, valueColumn, relColumn];
|
||||||
|
},
|
||||||
|
yesPart = converter.createElement("columns", createPart(gettextCatalog.getString("Yes"), yes, yesRelative)),
|
||||||
|
noPart = converter.createElement("columns", createPart(gettextCatalog.getString("No"), no, noRelative)),
|
||||||
|
abstainPart = converter.createElement("columns", createPart(gettextCatalog.getString("Abstain"), abstain, abstainRelative)),
|
||||||
|
totalPart = converter.createElement("columns", createPart(gettextCatalog.getString("Valid votes"), valid, validRelative)),
|
||||||
|
heading = converter.createElement("columns", [number, headerText]),
|
||||||
|
pollResult = converter.createElement("stack", [
|
||||||
|
heading, yesPart, noPart, abstainPart, totalPart
|
||||||
|
]);
|
||||||
|
|
||||||
|
return pollResult;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
pollLabel.width = '35%';
|
||||||
|
pollLabel.bold = true;
|
||||||
|
var result = converter.createElement("columns", [pollLabel, results()]);
|
||||||
|
result.margin = [10, 0, 0, 10];
|
||||||
|
result.lineHeight = 1;
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generates title section for motion
|
||||||
|
var titleSection = function() {
|
||||||
|
var title = converter.createElement("text", motion.getTitle($scope.version));
|
||||||
|
title.bold = true;
|
||||||
|
title.fontSize = 14;
|
||||||
|
title.margin = [0, 0, 0, 10];
|
||||||
|
return title;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generates reason section for polls
|
||||||
|
var reason = function() {
|
||||||
|
var r = converter.createElement("text", gettextCatalog.getString("Reason") + ":");
|
||||||
|
r.bold = true;
|
||||||
|
r.fontSize = 14;
|
||||||
|
r.margin = [0, 30, 0, 10];
|
||||||
|
return r;
|
||||||
|
};
|
||||||
|
|
||||||
|
//getters
|
||||||
|
var getTitle = function() {
|
||||||
|
return motion.getTitle($scope.verion);
|
||||||
|
};
|
||||||
|
|
||||||
|
var getIdentifier = function() {
|
||||||
|
return motion.identifier;
|
||||||
|
};
|
||||||
|
|
||||||
|
var getCategory = function() {
|
||||||
|
return motion.category;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generates content as a pdfmake consumable
|
||||||
|
var getContent = function() {
|
||||||
|
if (reasonContent().length === 0 ) {
|
||||||
|
return [
|
||||||
|
motionHeader(),
|
||||||
|
signment(),
|
||||||
|
polls(),
|
||||||
|
titleSection(),
|
||||||
|
textContent(),
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
return [
|
||||||
|
motionHeader(),
|
||||||
|
signment(),
|
||||||
|
polls(),
|
||||||
|
titleSection(),
|
||||||
|
textContent(),
|
||||||
|
reason(),
|
||||||
|
reasonContent()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
getContent: getContent
|
getContent: getContent,
|
||||||
|
getTitle: getTitle,
|
||||||
|
getIdentifier: getIdentifier,
|
||||||
|
getCategory: getCategory
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createInstance: createInstance
|
createInstance: createInstance
|
||||||
};
|
};
|
||||||
}])
|
}])
|
||||||
.factory('SingleMotionContentProvider', function() {
|
|
||||||
/**
|
|
||||||
* Generates a content provider
|
|
||||||
* @constructor
|
|
||||||
* @param {object} motionContentProvider - Generates pdfMake structure from motion
|
|
||||||
* @param {object} $scope - Current $scope
|
|
||||||
* @param {object} User - Current User
|
|
||||||
*/
|
|
||||||
var createInstance = function(motionContentProvider, motion, $scope, User) {
|
|
||||||
/**
|
|
||||||
* Returns Content for single motion
|
|
||||||
* @function
|
|
||||||
* @param {object} motion - Current motion
|
|
||||||
* @param {object} $scope - Current $scope
|
|
||||||
* @param {object} User - Current User
|
|
||||||
*/
|
|
||||||
var getContent = function() {
|
|
||||||
return motionContentProvider.getContent(motion, $scope, User);
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
getContent: getContent
|
|
||||||
};
|
|
||||||
};
|
|
||||||
return {
|
|
||||||
createInstance: createInstance
|
|
||||||
};
|
|
||||||
})
|
|
||||||
.factory('PollContentProvider', function() {
|
.factory('PollContentProvider', function() {
|
||||||
/**
|
/**
|
||||||
* Generates a content provider for polls
|
* Generates a content provider for polls
|
||||||
@ -356,6 +315,127 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
|
.factory('MotionCatalogContentProvider', ['gettextCatalog', function(gettextCatalog) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor
|
||||||
|
* @function
|
||||||
|
* @param {object} allMotions - A sorted array of all motions to parse
|
||||||
|
* @param {object} $scope - Current $scope
|
||||||
|
* @param {object} User - Current user
|
||||||
|
*/
|
||||||
|
var createInstance = function(allMotions, $scope, User, Category) {
|
||||||
|
|
||||||
|
//function to create the Table of contents
|
||||||
|
var createTitle = function() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
text: gettextCatalog.getString("Motions"),
|
||||||
|
style: "title"
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var createTOContent = function(motionTitles) {
|
||||||
|
|
||||||
|
var heading = {
|
||||||
|
text: gettextCatalog.getString("Table of contents"),
|
||||||
|
style: "heading",
|
||||||
|
};
|
||||||
|
|
||||||
|
var toc = [];
|
||||||
|
angular.forEach(motionTitles, function(title) {
|
||||||
|
toc.push({
|
||||||
|
text: gettextCatalog.getString("Motion") + " " + title,
|
||||||
|
style: "tableofcontent",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
heading,
|
||||||
|
toc,
|
||||||
|
addPageBreak()
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
// function to create the table of catergories (if any)
|
||||||
|
var createTOCatergories = function() {
|
||||||
|
if (Category.getAll().length > 0) {
|
||||||
|
var heading = {
|
||||||
|
text: gettextCatalog.getString("Categories"),
|
||||||
|
style: "heading"
|
||||||
|
};
|
||||||
|
|
||||||
|
var toc = [];
|
||||||
|
angular.forEach(Category.getAll(), function(cat) {
|
||||||
|
toc.push(
|
||||||
|
{
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
text: cat.prefix,
|
||||||
|
style: 'tableofcontent',
|
||||||
|
width: 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: cat.name,
|
||||||
|
style: 'tableofcontent'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
heading,
|
||||||
|
toc,
|
||||||
|
addPageBreak()
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
// if there are no categories, return "empty string"
|
||||||
|
// pdfmake takes "null" literally and throws an error
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// function to apply a pagebreak-keyword
|
||||||
|
var addPageBreak = function() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
text: '',
|
||||||
|
pageBreak: 'after'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
// returns the pure content of the motion, parseable by makepdf
|
||||||
|
var getContent = function() {
|
||||||
|
var motionContent = [];
|
||||||
|
var motionTitles = [];
|
||||||
|
var motionCategories = [];
|
||||||
|
angular.forEach(allMotions, function(motion, key) {
|
||||||
|
motionTitles.push(motion.getIdentifier() + ": " + motion.getTitle());
|
||||||
|
motionContent.push(motion.getContent());
|
||||||
|
if (key < allMotions.length - 1) {
|
||||||
|
motionContent.push(addPageBreak());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return [
|
||||||
|
createTitle(),
|
||||||
|
createTOCatergories(),
|
||||||
|
createTOContent(motionTitles),
|
||||||
|
motionContent
|
||||||
|
];
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
getContent: getContent
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
createInstance: createInstance
|
||||||
|
};
|
||||||
|
}])
|
||||||
|
|
||||||
.config([
|
.config([
|
||||||
'mainMenuProvider',
|
'mainMenuProvider',
|
||||||
'gettext',
|
'gettext',
|
||||||
@ -831,7 +911,14 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
|
|||||||
'User',
|
'User',
|
||||||
'Agenda',
|
'Agenda',
|
||||||
'MotionDocxExport',
|
'MotionDocxExport',
|
||||||
function($scope, $state, $http, ngDialog, MotionForm, Motion, Category, Tag, Workflow, User, Agenda, MotionDocxExport) {
|
'MotionContentProvider',
|
||||||
|
'MotionCatalogContentProvider',
|
||||||
|
'PdfMakeConverter',
|
||||||
|
'PdfMakeDocumentProvider',
|
||||||
|
'gettextCatalog',
|
||||||
|
function($scope, $state, $http, ngDialog, MotionForm, Motion, Category, Tag, Workflow, User, Agenda, MotionDocxExport,
|
||||||
|
MotionContentProvider, MotionCatalogContentProvider, PdfMakeConverter,
|
||||||
|
PdfMakeDocumentProvider, gettextCatalog) {
|
||||||
Motion.bindAll({}, $scope, 'motions');
|
Motion.bindAll({}, $scope, 'motions');
|
||||||
Category.bindAll({}, $scope, 'categories');
|
Category.bindAll({}, $scope, 'categories');
|
||||||
Tag.bindAll({}, $scope, 'tags');
|
Tag.bindAll({}, $scope, 'tags');
|
||||||
@ -866,7 +953,6 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
|
|||||||
// add id
|
// add id
|
||||||
$scope.multiselectFilter[filter].push(id);
|
$scope.multiselectFilter[filter].push(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
// function to sort by clicked column
|
// function to sort by clicked column
|
||||||
@ -989,6 +1075,38 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
|
|||||||
ngDialog.open(MotionForm.getDialog(motion));
|
ngDialog.open(MotionForm.getDialog(motion));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Export as a pdf file
|
||||||
|
$scope.pdf_export = function() {
|
||||||
|
|
||||||
|
var filename = gettextCatalog.getString("Motions") + ".pdf";
|
||||||
|
var image_sources = [];
|
||||||
|
|
||||||
|
//save the arrays of the filtered motions to an array
|
||||||
|
angular.forEach($scope.motionsFiltered, function (motion) {
|
||||||
|
var content = motion.getText() + motion.getReason();
|
||||||
|
var map = Function.prototype.call.bind([].map);
|
||||||
|
var tmp_image_sources = map($(content).find("img"), function(element) {
|
||||||
|
return element.getAttribute("src");
|
||||||
|
});
|
||||||
|
image_sources = image_sources.concat(tmp_image_sources);
|
||||||
|
});
|
||||||
|
|
||||||
|
//post-request to convert the images. Async.
|
||||||
|
$http.post('/core/encode_media/', JSON.stringify(image_sources)).success(function(data) {
|
||||||
|
var converter = PdfMakeConverter.createInstance(data.images, data.fonts, pdfMake);
|
||||||
|
var motionContentProviderArray = [];
|
||||||
|
|
||||||
|
//convert the filtered motions to motionContentProviders
|
||||||
|
angular.forEach($scope.motionsFiltered, function (motion) {
|
||||||
|
motionContentProviderArray.push(MotionContentProvider.createInstance(converter, motion, $scope, User, $http));
|
||||||
|
});
|
||||||
|
var motionCatalogContentProvider = MotionCatalogContentProvider.createInstance(motionContentProviderArray, $scope, User, Category);
|
||||||
|
var documentProvider = PdfMakeDocumentProvider.createInstance(motionCatalogContentProvider, data.defaultFont);
|
||||||
|
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Export as a csv file
|
// Export as a csv file
|
||||||
$scope.csv_export = function () {
|
$scope.csv_export = function () {
|
||||||
var element = document.getElementById('downloadLinkCSV');
|
var element = document.getElementById('downloadLinkCSV');
|
||||||
@ -1065,7 +1183,6 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
|
|||||||
'Workflow',
|
'Workflow',
|
||||||
'Config',
|
'Config',
|
||||||
'motion',
|
'motion',
|
||||||
'SingleMotionContentProvider',
|
|
||||||
'MotionContentProvider',
|
'MotionContentProvider',
|
||||||
'PollContentProvider',
|
'PollContentProvider',
|
||||||
'PdfMakeConverter',
|
'PdfMakeConverter',
|
||||||
@ -1074,7 +1191,7 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
|
|||||||
'gettextCatalog',
|
'gettextCatalog',
|
||||||
'Projector',
|
'Projector',
|
||||||
function($scope, $http, ngDialog, MotionForm, Motion, Category, Mediafile, Tag, User, Workflow, Config,
|
function($scope, $http, ngDialog, MotionForm, Motion, Category, Mediafile, Tag, User, Workflow, Config,
|
||||||
motion, SingleMotionContentProvider, MotionContentProvider, PollContentProvider,
|
motion, MotionContentProvider, PollContentProvider,
|
||||||
PdfMakeConverter, PdfMakeDocumentProvider, MotionInlineEditing, gettextCatalog, Projector) {
|
PdfMakeConverter, PdfMakeDocumentProvider, MotionInlineEditing, gettextCatalog, Projector) {
|
||||||
Motion.bindOne(motion.id, $scope, 'motion');
|
Motion.bindOne(motion.id, $scope, 'motion');
|
||||||
Category.bindAll({}, $scope, 'categories');
|
Category.bindAll({}, $scope, 'categories');
|
||||||
@ -1125,29 +1242,20 @@ angular.module('OpenSlidesApp.motions.site', ['OpenSlidesApp.motions', 'OpenSlid
|
|||||||
};
|
};
|
||||||
|
|
||||||
$scope.makePDF = function() {
|
$scope.makePDF = function() {
|
||||||
var id = motion.identifier,
|
var content = motion.getText() + motion.getReason();
|
||||||
slice = Function.prototype.call.bind([].slice),
|
var map = Function.prototype.call.bind([].map);
|
||||||
map = Function.prototype.call.bind([].map),
|
var image_sources = map($(content).find("img"), function(element) {
|
||||||
image_sources = map($(content).find("img"), function(element) {
|
return element.getAttribute("src");
|
||||||
return element.getAttribute("src");
|
});
|
||||||
});
|
|
||||||
|
|
||||||
$http.post('/core/encode_media/', JSON.stringify(image_sources)).success(function(data) {
|
$http.post('/core/encode_media/', JSON.stringify(image_sources)).success(function(data) {
|
||||||
/**
|
var converter = PdfMakeConverter.createInstance(data.images, data.fonts, pdfMake);
|
||||||
* Converter for use with pdfMake
|
var motionContentProvider = MotionContentProvider.createInstance(converter, motion, $scope, User, $http);
|
||||||
* @constructor
|
var documentProvider = PdfMakeDocumentProvider.createInstance(motionContentProvider, data.defaultFont);
|
||||||
* @param {object} images - An object to resolve the BASE64 encoded images { "$src":$BASE64DATA }
|
var filename = gettextCatalog.getString("Motion") + "-" + motion.identifier + ".pdf";
|
||||||
* @param {object} fonts - An object representing the available custom fonts
|
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
||||||
* @param {object} pdfMake - pdfMake object for enhancement with custom fonts
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
var converter = PdfMakeConverter.createInstance(data.images, data.fonts, pdfMake),
|
|
||||||
motionContentProvider = MotionContentProvider.createInstance(converter),
|
|
||||||
contentProvider = SingleMotionContentProvider.createInstance(motionContentProvider, motion, $scope, User),
|
|
||||||
documentProvider = PdfMakeDocumentProvider.createInstance(contentProvider, data.defaultFont),
|
|
||||||
filename = gettextCatalog.getString("Motion") + "-" + id + ".pdf";
|
|
||||||
pdfMake.createPdf(documentProvider.getDocument()).download(filename);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//make PDF for polls
|
//make PDF for polls
|
||||||
|
@ -47,7 +47,7 @@
|
|||||||
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownExport">
|
<ul class="dropdown-menu dropdown-menu-right" aria-labelledby="dropdownExport">
|
||||||
<!-- PDF export -->
|
<!-- PDF export -->
|
||||||
<li>
|
<li>
|
||||||
<a ui-sref="motions_pdf" target="_blank">
|
<a href="" ng-click="pdf_export()">
|
||||||
<i class="fa fa-file-pdf-o fa-lg"></i>
|
<i class="fa fa-file-pdf-o fa-lg"></i>
|
||||||
PDF
|
PDF
|
||||||
</a>
|
</a>
|
||||||
@ -180,7 +180,7 @@
|
|||||||
<translate translate-comment="short form of agenda item">Item</translate>
|
<translate translate-comment="short form of agenda item">Item</translate>
|
||||||
<span class="spacer-right pull-right"></span>
|
<span class="spacer-right pull-right"></span>
|
||||||
<i class="pull-right fa"
|
<i class="pull-right fa"
|
||||||
ng-style="{'visibility': sortColumn === 'agenda_item.getItemNumberWithAncestors()' && header.sortable != false ? 'visible' : 'hidden'}"
|
ng-style="{'visibility': sortColumn === 'agenda_item.getItemNumberWithAncestors()' && header.sortable != false ? 'visible' : 'hidden'}"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
@ -191,7 +191,7 @@
|
|||||||
<translate>Identifier</translate>
|
<translate>Identifier</translate>
|
||||||
<span class="spacer-right pull-right"></span>
|
<span class="spacer-right pull-right"></span>
|
||||||
<i class="pull-right fa"
|
<i class="pull-right fa"
|
||||||
ng-style="{'visibility': sortColumn === 'identifier' && header.sortable != false ? 'visible' : 'hidden'}"
|
ng-style="{'visibility': sortColumn === 'identifier' && header.sortable != false ? 'visible' : 'hidden'}"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
@ -202,7 +202,7 @@
|
|||||||
<translate>Title</translate>
|
<translate>Title</translate>
|
||||||
<span class="spacer-right pull-right"></span>
|
<span class="spacer-right pull-right"></span>
|
||||||
<i class="pull-right fa"
|
<i class="pull-right fa"
|
||||||
ng-style="{'visibility': sortColumn === 'getTitle()' && header.sortable != false ? 'visible' : 'hidden'}"
|
ng-style="{'visibility': sortColumn === 'getTitle()' && header.sortable != false ? 'visible' : 'hidden'}"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
@ -213,7 +213,7 @@
|
|||||||
<translate>Submitters</translate>
|
<translate>Submitters</translate>
|
||||||
<span class="spacer-right pull-right"></span>
|
<span class="spacer-right pull-right"></span>
|
||||||
<i class="pull-right fa"
|
<i class="pull-right fa"
|
||||||
ng-style="{'visibility': sortColumn === 'submitters' && header.sortable != false ? 'visible' : 'hidden'}"
|
ng-style="{'visibility': sortColumn === 'submitters' && header.sortable != false ? 'visible' : 'hidden'}"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
@ -224,7 +224,7 @@
|
|||||||
<translate>Category</translate>
|
<translate>Category</translate>
|
||||||
<span class="spacer-right pull-right"></span>
|
<span class="spacer-right pull-right"></span>
|
||||||
<i class="pull-right fa"
|
<i class="pull-right fa"
|
||||||
ng-style="{'visibility': sortColumn === 'category' && header.sortable != false ? 'visible' : 'hidden'}"
|
ng-style="{'visibility': sortColumn === 'category' && header.sortable != false ? 'visible' : 'hidden'}"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
@ -235,7 +235,7 @@
|
|||||||
<translate>State</translate>
|
<translate>State</translate>
|
||||||
<span class="spacer-right pull-right"></span>
|
<span class="spacer-right pull-right"></span>
|
||||||
<i class="pull-right fa"
|
<i class="pull-right fa"
|
||||||
ng-style="{'visibility': sortColumn === 'state.name' && header.sortable != false ? 'visible' : 'hidden'}"
|
ng-style="{'visibility': sortColumn === 'state.name' && header.sortable != false ? 'visible' : 'hidden'}"
|
||||||
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'">
|
||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
@ -295,7 +295,7 @@
|
|||||||
| SelectMultipleFilter: multiselectFilter.category : getItemId.category
|
| SelectMultipleFilter: multiselectFilter.category : getItemId.category
|
||||||
| SelectMultipleFilter: multiselectFilter.tag : getItemId.tag
|
| SelectMultipleFilter: multiselectFilter.tag : getItemId.tag
|
||||||
| orderBy: sortColumn : reverse)">
|
| orderBy: sortColumn : reverse)">
|
||||||
|
|
||||||
<!-- select column -->
|
<!-- select column -->
|
||||||
<div ng-show="isDeleteMode" os-perms="motions.can_manage"
|
<div ng-show="isDeleteMode" os-perms="motions.can_manage"
|
||||||
class="col-xs-1 centered" ng-class="{'deleteColumn' : motion.selected}">
|
class="col-xs-1 centered" ng-class="{'deleteColumn' : motion.selected}">
|
||||||
@ -362,7 +362,7 @@
|
|||||||
<!-- Submitters -->
|
<!-- Submitters -->
|
||||||
<div>
|
<div>
|
||||||
<small>
|
<small>
|
||||||
<span class="optional" translate>by</span>
|
<span class="optional" translate>by</span>
|
||||||
<span class="optional" ng-repeat="submitter in motion.submitters | limitTo:3">
|
<span class="optional" ng-repeat="submitter in motion.submitters | limitTo:3">
|
||||||
{{ submitter.get_full_name() }}<span ng-if="!$last">,</span></span><span ng-if="motion.submitters.length > 3">, ...</span>
|
{{ submitter.get_full_name() }}<span ng-if="!$last">,</span></span><span ng-if="motion.submitters.length > 3">, ...</span>
|
||||||
<!-- sorry for merging them together, but otherwise there would be a whitespace because of the new line -->
|
<!-- sorry for merging them together, but otherwise there would be a whitespace because of the new line -->
|
||||||
|
Loading…
Reference in New Issue
Block a user