Merge pull request #2739 from CatoTH/Issue2561-pdf-line-numbering-in-lists
Attempt to mitigate the list / line number problem
This commit is contained in:
commit
4e5adb74e3
@ -380,8 +380,9 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
* Convertes HTML for use with pdfMake
|
* Convertes HTML for use with pdfMake
|
||||||
* @function
|
* @function
|
||||||
* @param {object} html - html
|
* @param {object} html - html
|
||||||
|
* @param {string} lineNumberMode - [inline, outside, none]
|
||||||
*/
|
*/
|
||||||
convertHTML = function(html, scope) {
|
convertHTML = function(html, lineNumberMode) {
|
||||||
var elementStyles = {
|
var elementStyles = {
|
||||||
"b": ["font-weight:bold"],
|
"b": ["font-weight:bold"],
|
||||||
"strong": ["font-weight:bold"],
|
"strong": ["font-weight:bold"],
|
||||||
@ -402,6 +403,31 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
"delete": ["color:red", "text-decoration:line-through"],
|
"delete": ["color:red", "text-decoration:line-through"],
|
||||||
"insert": ["color:green", "text-decoration:underline"]
|
"insert": ["color:green", "text-decoration:underline"]
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* Removes all line number nodes (not line-breaks)
|
||||||
|
* and returns an array containing the reoved numbers (as integer, not as node)
|
||||||
|
*
|
||||||
|
* @function
|
||||||
|
* @param {object} element
|
||||||
|
*/
|
||||||
|
extractLineNumbers = function(element) {
|
||||||
|
var foundLineNumbers = [];
|
||||||
|
if (element.nodeName == 'SPAN' && element.getAttribute('class').indexOf('os-line-number') > -1) {
|
||||||
|
foundLineNumbers.push(element.getAttribute('data-line-number'));
|
||||||
|
element.parentNode.removeChild(element);
|
||||||
|
} else {
|
||||||
|
var children = element.childNodes,
|
||||||
|
childrenLength = children.length;
|
||||||
|
for (var i = 0; i < children.length; i++) {
|
||||||
|
foundLineNumbers = _.union(foundLineNumbers, extractLineNumbers(children[i]));
|
||||||
|
if (children.length < childrenLength) {
|
||||||
|
i -= (childrenLength - children.length);
|
||||||
|
childrenLength = children.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return foundLineNumbers;
|
||||||
|
},
|
||||||
/**
|
/**
|
||||||
* Parses Children of the current paragraph
|
* Parses Children of the current paragraph
|
||||||
* @function
|
* @function
|
||||||
@ -593,7 +619,7 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
alreadyConverted.push(st);
|
alreadyConverted.push(st);
|
||||||
break;
|
break;
|
||||||
case "span":
|
case "span":
|
||||||
if (scope.lineNumberMode == "inline") {
|
if (lineNumberMode == "inline") {
|
||||||
if (diff_mode != DIFF_MODE_INSERT) {
|
if (diff_mode != DIFF_MODE_INSERT) {
|
||||||
var lineNumberInline = element.getAttribute("data-line-number"),
|
var lineNumberInline = element.getAttribute("data-line-number"),
|
||||||
lineNumberObjInline = {
|
lineNumberObjInline = {
|
||||||
@ -604,7 +630,7 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
currentParagraph.text.push(lineNumberObjInline);
|
currentParagraph.text.push(lineNumberObjInline);
|
||||||
}
|
}
|
||||||
parseChildren(alreadyConverted, element, currentParagraph, styles, diff_mode);
|
parseChildren(alreadyConverted, element, currentParagraph, styles, diff_mode);
|
||||||
} else if (scope.lineNumberMode == "outside") {
|
} else if (lineNumberMode == "outside") {
|
||||||
var lineNumberOutline;
|
var lineNumberOutline;
|
||||||
if (diff_mode == DIFF_MODE_INSERT) {
|
if (diff_mode == DIFF_MODE_INSERT) {
|
||||||
lineNumberOutline = "";
|
lineNumberOutline = "";
|
||||||
@ -633,7 +659,7 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
break;
|
break;
|
||||||
case "br":
|
case "br":
|
||||||
//in case of inline-line-numbers and the os-line-break class ignore the break
|
//in case of inline-line-numbers and the os-line-break class ignore the break
|
||||||
if (!(scope.lineNumberMode == "inline" && element.getAttribute("class") == "os-line-break")) {
|
if (!(lineNumberMode == "inline" && element.getAttribute("class") == "os-line-break")) {
|
||||||
currentParagraph = create("text");
|
currentParagraph = create("text");
|
||||||
alreadyConverted.push(currentParagraph);
|
alreadyConverted.push(currentParagraph);
|
||||||
}
|
}
|
||||||
@ -686,14 +712,37 @@ angular.module('OpenSlidesApp.core.pdf', [])
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case "ul":
|
case "ul":
|
||||||
var u = create("ul");
|
|
||||||
parseChildren(u.ul, element, currentParagraph, styles, diff_mode);
|
|
||||||
alreadyConverted.push(u);
|
|
||||||
break;
|
|
||||||
case "ol":
|
case "ol":
|
||||||
var o = create("ol");
|
var list = create(nodeName);
|
||||||
parseChildren(o.ol, element, currentParagraph, styles, diff_mode);
|
if (lineNumberMode == "outside") {
|
||||||
alreadyConverted.push(o);
|
var lines = extractLineNumbers(element);
|
||||||
|
parseChildren(list[nodeName], element, currentParagraph, styles, diff_mode);
|
||||||
|
if (lines.length > 0) {
|
||||||
|
var listCol = {
|
||||||
|
columns: [{
|
||||||
|
width: 20,
|
||||||
|
stack: []
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
_.forEach(lines, function(line) {
|
||||||
|
listCol.columns[0].stack.push({
|
||||||
|
width: 20,
|
||||||
|
text: line,
|
||||||
|
color: "gray",
|
||||||
|
fontSize: 8,
|
||||||
|
margin: [0, 2.35, 0, 0]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
listCol.columns.push(list);
|
||||||
|
listCol.margin = [0,10,0,0];
|
||||||
|
alreadyConverted.push(listCol);
|
||||||
|
} else {
|
||||||
|
alreadyConverted.push(list);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
parseChildren(list[nodeName], element, currentParagraph, styles, diff_mode);
|
||||||
|
alreadyConverted.push(list);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
var temporary = create("text", element.textContent.replace(/\n/g, ""));
|
var temporary = create("text", element.textContent.replace(/\n/g, ""));
|
||||||
|
@ -257,9 +257,9 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
* https://github.com/OpenSlides/OpenSlides/issues/2361
|
* https://github.com/OpenSlides/OpenSlides/issues/2361
|
||||||
*/
|
*/
|
||||||
var text = motion.getTextByMode($scope.viewChangeRecommendations.mode, $scope.version);
|
var text = motion.getTextByMode($scope.viewChangeRecommendations.mode, $scope.version);
|
||||||
return converter.convertHTML(text, $scope);
|
return converter.convertHTML(text, $scope.lineNumberMode);
|
||||||
} else {
|
} else {
|
||||||
return converter.convertHTML(motion.getText($scope.version), $scope);
|
return converter.convertHTML(motion.getText($scope.version), $scope.lineNumberMode);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -271,7 +271,7 @@ angular.module('OpenSlidesApp.motions.pdf', ['OpenSlidesApp.core.pdf'])
|
|||||||
text: gettextCatalog.getString('Reason'),
|
text: gettextCatalog.getString('Reason'),
|
||||||
style: 'heading3'
|
style: 'heading3'
|
||||||
});
|
});
|
||||||
reason.push(converter.convertHTML(motion.getReason($scope.version), $scope));
|
reason.push(converter.convertHTML(motion.getReason($scope.version), $scope.lineNumberMode));
|
||||||
}
|
}
|
||||||
return reason;
|
return reason;
|
||||||
};
|
};
|
||||||
|
163
tests/karma/core/pdf.service.test.js
Normal file
163
tests/karma/core/pdf.service.test.js
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
describe('pdf', function () {
|
||||||
|
|
||||||
|
beforeEach(module('OpenSlidesApp.core.pdf'));
|
||||||
|
beforeEach(module('OpenSlidesApp.motions.lineNumbering'));
|
||||||
|
|
||||||
|
var PdfMakeConverter,
|
||||||
|
lineNumberingService;
|
||||||
|
|
||||||
|
beforeEach(inject(function (_PdfMakeConverter_, _lineNumberingService_) {
|
||||||
|
PdfMakeConverter = _PdfMakeConverter_;
|
||||||
|
lineNumberingService = _lineNumberingService_;
|
||||||
|
}));
|
||||||
|
|
||||||
|
var defaultmargin = [0, 5],
|
||||||
|
emptyline = JSON.stringify({
|
||||||
|
"stack": [
|
||||||
|
{"text": [], "margin": defaultmargin}]
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('converting html to pdfmake', function () {
|
||||||
|
it('converts a simple html string', function () {
|
||||||
|
var instance = PdfMakeConverter.createInstance();
|
||||||
|
var pdfmake = instance.convertHTML(
|
||||||
|
'<p>Hello <strong>strong</strong> world</p>', 'none'
|
||||||
|
);
|
||||||
|
expect(JSON.stringify(pdfmake[0])).toBe(emptyline);
|
||||||
|
expect(JSON.stringify(pdfmake[1])).toBe(JSON.stringify({
|
||||||
|
"stack": [
|
||||||
|
{
|
||||||
|
"text": [
|
||||||
|
{"text": "Hello "},
|
||||||
|
{"text": "strong", "bold": true},
|
||||||
|
{"text": " world"}
|
||||||
|
], "margin": defaultmargin
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
expect(JSON.stringify(pdfmake[2])).toBe(emptyline);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('converts a simple list', function () {
|
||||||
|
var instance = PdfMakeConverter.createInstance();
|
||||||
|
var pdfmake = instance.convertHTML(
|
||||||
|
'<ul>' +
|
||||||
|
'<li>Point 1</li>' +
|
||||||
|
'<li>Point 2</li>' +
|
||||||
|
'</ul>', 'none'
|
||||||
|
);
|
||||||
|
expect(JSON.stringify(pdfmake[0])).toBe(emptyline);
|
||||||
|
expect(JSON.stringify(pdfmake[1])).toBe(JSON.stringify({
|
||||||
|
"ul": [
|
||||||
|
{"stack": [{"text": [{"text": "Point 1"}]}]},
|
||||||
|
{"stack": [{"text": [{"text": "Point 2"}]}]}
|
||||||
|
]
|
||||||
|
}));
|
||||||
|
expect(JSON.stringify(pdfmake[2])).toBe(emptyline);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('converts simple text including line numbers (inline)', function () {
|
||||||
|
var inHtml = "<span>Test</span>",
|
||||||
|
numberedHtml = lineNumberingService.insertLineNumbers(inHtml, 5);
|
||||||
|
var instance = PdfMakeConverter.createInstance();
|
||||||
|
var pdfmake = instance.convertHTML(numberedHtml, 'inline');
|
||||||
|
expect(JSON.stringify(pdfmake)).toBe(JSON.stringify([
|
||||||
|
{
|
||||||
|
"stack": [{
|
||||||
|
"text": [
|
||||||
|
{"text": "1", "color": "gray", "fontSize": 5},
|
||||||
|
{"text": " "},
|
||||||
|
{
|
||||||
|
"text": null,
|
||||||
|
"color": "gray",
|
||||||
|
"fontSize": 5
|
||||||
|
},
|
||||||
|
{"text": "Test"}
|
||||||
|
], "margin": [0, 5]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('converts simple text including line numbers (outside)', function () {
|
||||||
|
var inHtml = "<p>Test Test2 Test3</p>",
|
||||||
|
numberedHtml = lineNumberingService.insertLineNumbers(inHtml, 5);
|
||||||
|
var instance = PdfMakeConverter.createInstance();
|
||||||
|
var pdfmake = instance.convertHTML(numberedHtml, 'outside');
|
||||||
|
|
||||||
|
expect(JSON.stringify(pdfmake[0])).toBe(emptyline);
|
||||||
|
expect(JSON.stringify(pdfmake[1])).toBe(JSON.stringify({
|
||||||
|
"stack": [{"text": [], "margin": [0, 5]}, {
|
||||||
|
"columns": [{
|
||||||
|
"width": 20,
|
||||||
|
"text": "1",
|
||||||
|
"color": "gray",
|
||||||
|
"fontSize": 8,
|
||||||
|
"margin": [0, 2, 0, 0]
|
||||||
|
}, {"text": [{"text": " "}, {"text": "Test "}]}]
|
||||||
|
}, {"text": []}, {
|
||||||
|
"columns": [{
|
||||||
|
"width": 20,
|
||||||
|
"text": "2",
|
||||||
|
"color": "gray",
|
||||||
|
"fontSize": 8,
|
||||||
|
"margin": [0, 2, 0, 0]
|
||||||
|
}, {"text": [{"text": " "}, {"text": "Test2 "}]}]
|
||||||
|
}, {"text": []}, {
|
||||||
|
"columns": [{
|
||||||
|
"width": 20,
|
||||||
|
"text": "3",
|
||||||
|
"color": "gray",
|
||||||
|
"fontSize": 8,
|
||||||
|
"margin": [0, 2, 0, 0]
|
||||||
|
}, {"text": [{"text": " "}, {"text": "Test3"}]}]
|
||||||
|
}]
|
||||||
|
}));
|
||||||
|
expect(JSON.stringify(pdfmake[2])).toBe(emptyline);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('converts a list including line numbers (outside)', function () {
|
||||||
|
var inHtml = "<ul><li>Item 1</li><li>Item 2</li></ul>",
|
||||||
|
numberedHtml = lineNumberingService.insertLineNumbers(inHtml, 10);
|
||||||
|
|
||||||
|
var instance = PdfMakeConverter.createInstance();
|
||||||
|
var pdfmake = instance.convertHTML(numberedHtml, 'outside');
|
||||||
|
|
||||||
|
expect(JSON.stringify(pdfmake[0])).toBe(emptyline);
|
||||||
|
expect(JSON.stringify(pdfmake[1])).toBe(JSON.stringify({
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"width": 20,
|
||||||
|
"stack": [
|
||||||
|
{"width": 20, "text": "1", "color": "gray", "fontSize": 8, "margin": [0, 2.35, 0, 0]},
|
||||||
|
{"width": 20, "text": "2", "color": "gray", "fontSize": 8, "margin": [0, 2.35, 0, 0]},
|
||||||
|
{"width": 20, "text": "3", "color": "gray", "fontSize": 8, "margin": [0, 2.35, 0, 0]},
|
||||||
|
{"width": 20, "text": "4", "color": "gray", "fontSize": 8, "margin": [0, 2.35, 0, 0]}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ul": [{
|
||||||
|
"stack": [
|
||||||
|
{"text": [{"text": "Item "}]},
|
||||||
|
{"text": [{"text": "1"}]}
|
||||||
|
]
|
||||||
|
}, {
|
||||||
|
"stack": [
|
||||||
|
{"text": [{"text": "Item "}]},
|
||||||
|
{"text": [{"text": "2"}]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"margin": [0,10,0,0]
|
||||||
|
}));
|
||||||
|
expect(JSON.stringify(pdfmake[2])).toBe(emptyline);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
@ -19,6 +19,7 @@ module.exports = function(config) {
|
|||||||
'node_modules/angular-mocks/angular-mocks.js',
|
'node_modules/angular-mocks/angular-mocks.js',
|
||||||
'openslides/motions/static/js/motions/linenumbering.js',
|
'openslides/motions/static/js/motions/linenumbering.js',
|
||||||
'openslides/motions/static/js/motions/diff.js',
|
'openslides/motions/static/js/motions/diff.js',
|
||||||
|
'openslides/core/static/js/core/pdf.js',
|
||||||
'tests/karma/*/*.test.js'
|
'tests/karma/*/*.test.js'
|
||||||
],
|
],
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user