You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.6 KiB
174 lines
5.6 KiB
'use strict';
|
|
|
|
var isUndefined = require('./helpers').isUndefined;
|
|
var ElementWriter = require('./elementWriter');
|
|
|
|
/**
|
|
* Creates an instance of PageElementWriter - an extended ElementWriter
|
|
* which can handle:
|
|
* - page-breaks (it adds new pages when there's not enough space left),
|
|
* - repeatable fragments (like table-headers, which are repeated everytime
|
|
* a page-break occurs)
|
|
* - transactions (used for unbreakable-blocks when we want to make sure
|
|
* whole block will be rendered on the same page)
|
|
*/
|
|
function PageElementWriter(context, tracker) {
|
|
this.transactionLevel = 0;
|
|
this.repeatables = [];
|
|
this.tracker = tracker;
|
|
this.writer = new ElementWriter(context, tracker);
|
|
}
|
|
|
|
function fitOnPage(self, addFct) {
|
|
var position = addFct(self);
|
|
if (!position) {
|
|
self.moveToNextPage();
|
|
position = addFct(self);
|
|
}
|
|
return position;
|
|
}
|
|
|
|
PageElementWriter.prototype.addLine = function (line, dontUpdateContextPosition, index) {
|
|
return fitOnPage(this, function (self) {
|
|
return self.writer.addLine(line, dontUpdateContextPosition, index);
|
|
});
|
|
};
|
|
|
|
PageElementWriter.prototype.addImage = function (image, index) {
|
|
return fitOnPage(this, function (self) {
|
|
return self.writer.addImage(image, index);
|
|
});
|
|
};
|
|
|
|
PageElementWriter.prototype.addSVG = function (image, index) {
|
|
return fitOnPage(this, function (self) {
|
|
return self.writer.addSVG(image, index);
|
|
});
|
|
};
|
|
|
|
PageElementWriter.prototype.addQr = function (qr, index) {
|
|
return fitOnPage(this, function (self) {
|
|
return self.writer.addQr(qr, index);
|
|
});
|
|
};
|
|
|
|
PageElementWriter.prototype.addVector = function (vector, ignoreContextX, ignoreContextY, index) {
|
|
return this.writer.addVector(vector, ignoreContextX, ignoreContextY, index);
|
|
};
|
|
|
|
PageElementWriter.prototype.beginClip = function (width, height) {
|
|
return this.writer.beginClip(width, height);
|
|
};
|
|
|
|
PageElementWriter.prototype.endClip = function () {
|
|
return this.writer.endClip();
|
|
};
|
|
|
|
PageElementWriter.prototype.alignCanvas = function (node) {
|
|
this.writer.alignCanvas(node);
|
|
};
|
|
|
|
PageElementWriter.prototype.addFragment = function (fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition) {
|
|
if (!this.writer.addFragment(fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition)) {
|
|
this.moveToNextPage();
|
|
this.writer.addFragment(fragment, useBlockXOffset, useBlockYOffset, dontUpdateContextPosition);
|
|
}
|
|
};
|
|
|
|
PageElementWriter.prototype.moveToNextPage = function (pageOrientation) {
|
|
|
|
var nextPage = this.writer.context.moveToNextPage(pageOrientation);
|
|
|
|
// moveToNextPage is called multiple times for table, because is called for each column
|
|
// and repeatables are inserted only in the first time. If columns are used, is needed
|
|
// call for table in first column and then for table in the second column (is other repeatables).
|
|
this.repeatables.forEach(function (rep) {
|
|
if (isUndefined(rep.insertedOnPages[this.writer.context.page])) {
|
|
rep.insertedOnPages[this.writer.context.page] = true;
|
|
this.writer.addFragment(rep, true);
|
|
} else {
|
|
this.writer.context.moveDown(rep.height);
|
|
}
|
|
}, this);
|
|
|
|
this.writer.tracker.emit('pageChanged', {
|
|
prevPage: nextPage.prevPage,
|
|
prevY: nextPage.prevY,
|
|
y: this.writer.context.y
|
|
});
|
|
};
|
|
|
|
PageElementWriter.prototype.beginUnbreakableBlock = function (width, height) {
|
|
if (this.transactionLevel++ === 0) {
|
|
this.originalX = this.writer.context.x;
|
|
this.writer.pushContext(width, height);
|
|
}
|
|
};
|
|
|
|
PageElementWriter.prototype.commitUnbreakableBlock = function (forcedX, forcedY) {
|
|
if (--this.transactionLevel === 0) {
|
|
var unbreakableContext = this.writer.context;
|
|
this.writer.popContext();
|
|
|
|
var nbPages = unbreakableContext.pages.length;
|
|
if (nbPages > 0) {
|
|
// no support for multi-page unbreakableBlocks
|
|
var fragment = unbreakableContext.pages[0];
|
|
fragment.xOffset = forcedX;
|
|
fragment.yOffset = forcedY;
|
|
|
|
//TODO: vectors can influence height in some situations
|
|
if (nbPages > 1) {
|
|
// on out-of-context blocs (headers, footers, background) height should be the whole DocumentContext height
|
|
if (forcedX !== undefined || forcedY !== undefined) {
|
|
fragment.height = unbreakableContext.getCurrentPage().pageSize.height - unbreakableContext.pageMargins.top - unbreakableContext.pageMargins.bottom;
|
|
} else {
|
|
fragment.height = this.writer.context.getCurrentPage().pageSize.height - this.writer.context.pageMargins.top - this.writer.context.pageMargins.bottom;
|
|
for (var i = 0, l = this.repeatables.length; i < l; i++) {
|
|
fragment.height -= this.repeatables[i].height;
|
|
}
|
|
}
|
|
} else {
|
|
fragment.height = unbreakableContext.y;
|
|
}
|
|
|
|
if (forcedX !== undefined || forcedY !== undefined) {
|
|
this.writer.addFragment(fragment, true, true, true);
|
|
} else {
|
|
this.addFragment(fragment);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
PageElementWriter.prototype.currentBlockToRepeatable = function () {
|
|
var unbreakableContext = this.writer.context;
|
|
var rep = { items: [] };
|
|
|
|
unbreakableContext.pages[0].items.forEach(function (item) {
|
|
rep.items.push(item);
|
|
});
|
|
|
|
rep.xOffset = this.originalX;
|
|
|
|
//TODO: vectors can influence height in some situations
|
|
rep.height = unbreakableContext.y;
|
|
|
|
rep.insertedOnPages = [];
|
|
|
|
return rep;
|
|
};
|
|
|
|
PageElementWriter.prototype.pushToRepeatables = function (rep) {
|
|
this.repeatables.push(rep);
|
|
};
|
|
|
|
PageElementWriter.prototype.popFromRepeatables = function () {
|
|
this.repeatables.pop();
|
|
};
|
|
|
|
PageElementWriter.prototype.context = function () {
|
|
return this.writer.context;
|
|
};
|
|
|
|
module.exports = PageElementWriter;
|