|
26 | 26 | */
|
27 | 27 |
|
28 | 28 | (function(jsPDFAPI) {
|
29 |
| - var DrillForContent, FontNameDB, FontStyleMap, FontWeightMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, process, tableToJson; |
| 29 | + var DrillForContent, FontNameDB, FontStyleMap, FontWeightMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, checkForFooter, process, tableToJson; |
30 | 30 | PurgeWhiteSpace = function(array) {
|
31 | 31 | var fragment, i, l, lTrimmed, r, rTrimmed, trailingSpace;
|
32 | 32 | i = 0;
|
|
253 | 253 | while (i < l) {
|
254 | 254 | cn = cns[i];
|
255 | 255 | if (typeof cn === "object") {
|
| 256 | + |
| 257 | + /*** HEADER rendering **/ |
| 258 | + if (cn.nodeType === 1 && cn.nodeName === 'HEADER') { |
| 259 | + var header = cn; |
| 260 | + //store old top margin |
| 261 | + var oldMarginTop = renderer.pdf.margins_doc.top; |
| 262 | + //subscribe for new page event and render header first on every page |
| 263 | + renderer.pdf.internal.events.subscribe('addPage', function(pageInfo) { |
| 264 | + //set current y position to old margin |
| 265 | + renderer.y = oldMarginTop; |
| 266 | + //render all child nodes of the header element |
| 267 | + DrillForContent(header,renderer,elementHandlers); |
| 268 | + //set margin to old margin + rendered header + 10 space to prevent overlapping |
| 269 | + //important for other plugins (e.g. table) to start rendering at correct position after header |
| 270 | + renderer.pdf.margins_doc.top = renderer.y+10; |
| 271 | + renderer.y += 10; |
| 272 | + }, false); |
| 273 | + } |
| 274 | + |
256 | 275 | if (cn.nodeType === 8 && cn.nodeName === "#comment") {
|
257 | 276 | if (cn.textContent.match("ADD_PAGE")) {
|
258 | 277 | renderer.pdf.addPage();
|
259 | 278 | renderer.y = renderer.pdf.margins_doc.top;
|
260 | 279 | }
|
261 |
| - } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) { |
| 280 | + } else if (cn.nodeType === 1 && !SkipNode[cn.nodeName]) { |
262 | 281 | if (cn.nodeName === "IMG" && images[cn.getAttribute("src")]) {
|
263 | 282 | if ((renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom < renderer.y + cn.height) && (renderer.y > renderer.pdf.margins_doc.top)) {
|
264 |
| - renderer.pdf.addPage(); |
265 | 283 | renderer.y = renderer.pdf.margins_doc.top;
|
| 284 | + renderer.pdf.addPage(); |
266 | 285 | }
|
267 | 286 | renderer.pdf.addImage(images[cn.getAttribute("src")], renderer.x, renderer.y, cn.width, cn.height);
|
268 | 287 | renderer.y += cn.height;
|
|
296 | 315 | loadImgs = function(element, renderer, elementHandlers, cb) {
|
297 | 316 | var imgs = element.getElementsByTagName('img'), l = imgs.length, x = 0;
|
298 | 317 | function done() {
|
299 |
| - DrillForContent(element, renderer, elementHandlers); |
300 |
| - cb(renderer.dispose()); |
| 318 | + renderer.pdf.internal.events.publish('imagesLoaded'); |
| 319 | + cb(); |
301 | 320 | }
|
302 | 321 | function loadImage(url) {
|
303 | 322 | if(!url) return;
|
|
315 | 334 | cb = cb || function() {};
|
316 | 335 | return x || done();
|
317 | 336 | };
|
| 337 | + checkForFooter = function(elem, renderer, elementHandlers, callback) { |
| 338 | + //check if we can found a <footer> element |
| 339 | + var footer = elem.getElementsByTagName("footer"); |
| 340 | + if (footer.length > 0) { |
| 341 | + |
| 342 | + footer = footer[0]; |
| 343 | + |
| 344 | + //bad hack to get height of footer |
| 345 | + //creat dummy out and check new y after fake rendering |
| 346 | + var oldOut = renderer.pdf.internal.write; |
| 347 | + var oldY = renderer.y; |
| 348 | + renderer.pdf.internal.write = function() {}; |
| 349 | + DrillForContent(footer, renderer, elementHandlers); |
| 350 | + var footerHeight = Math.ceil(renderer.y-oldY)+5; |
| 351 | + renderer.y = oldY; |
| 352 | + renderer.pdf.internal.write = oldOut; |
| 353 | + |
| 354 | + //add 20% to prevent overlapping |
| 355 | + renderer.pdf.margins_doc.bottom += footerHeight; |
| 356 | + |
| 357 | + //Create function render header on every page |
| 358 | + var renderFooter = function(pageInfo) { |
| 359 | + var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1; |
| 360 | + //set current y position to old margin |
| 361 | + var oldPosition = renderer.y; |
| 362 | + //render all child nodes of the header element |
| 363 | + renderer.y = renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom; |
| 364 | + renderer.pdf.margins_doc.bottom -= footerHeight; |
| 365 | + |
| 366 | + //check if we have to add page numbers |
| 367 | + var spans = footer.getElementsByTagName('span'); |
| 368 | + for(var i=0; i < spans.length; ++i) { |
| 369 | + //if we find some span element with class pageCounter, set the page |
| 370 | + if ( (" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1 ) { |
| 371 | + spans[i].innerHTML = pageNumber; |
| 372 | + } |
| 373 | + //if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages |
| 374 | + if ( (" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1 ) { |
| 375 | + spans[i].innerHTML = '###jsPDFVarTotalPages###'; |
| 376 | + } |
| 377 | + } |
| 378 | + |
| 379 | + //render footer content |
| 380 | + DrillForContent(footer,renderer,elementHandlers); |
| 381 | + //set bottom margin to previous height including the footer height |
| 382 | + renderer.pdf.margins_doc.bottom += footerHeight; |
| 383 | + //important for other plugins (e.g. table) to start rendering at correct position after header |
| 384 | + renderer.y = oldPosition; |
| 385 | + }; |
| 386 | + |
| 387 | + //check if footer contains totalPages which shoudl be replace at the disoposal of the document |
| 388 | + var spans = footer.getElementsByTagName('span'); |
| 389 | + for(var i=0; i < spans.length; ++i) { |
| 390 | + if ( (" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1 ) { |
| 391 | + renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true); |
| 392 | + } |
| 393 | + } |
| 394 | + |
| 395 | + //register event to render footer on every new page |
| 396 | + renderer.pdf.internal.events.subscribe('addPage', renderFooter, false); |
| 397 | + //render footer on first page |
| 398 | + renderFooter(); |
| 399 | + |
| 400 | + //prevent footer rendering |
| 401 | + SkipNode['FOOTER'] = 1; |
| 402 | + |
| 403 | + } |
| 404 | + |
| 405 | + //footer preperation finished |
| 406 | + callback(); |
| 407 | + |
| 408 | + }; |
318 | 409 | process = function(pdf, element, x, y, settings, callback) {
|
319 | 410 | if (!element) return false;
|
320 | 411 | if (!element.parentNode) element = '' + element.innerHTML;
|
|
333 | 424 | })(element.replace(/<\/?script[^>]*?>/gi,''));
|
334 | 425 | }
|
335 | 426 | var r = new Renderer(pdf, x, y, settings);
|
336 |
| - loadImgs.call(this, element, r, settings.elementHandlers, callback); |
| 427 | + |
| 428 | + // 1. load images |
| 429 | + // 2. prepare optional footer elements |
| 430 | + // 3. render content |
| 431 | + loadImgs.call(this, element, r, settings.elementHandlers, function() { |
| 432 | + checkForFooter.call(this, element, r, settings.elementHandlers, function() { |
| 433 | + DrillForContent(element, r, settings.elementHandlers); |
| 434 | + //send event dispose for final taks (e.g. footer totalpage replacement) |
| 435 | + r.pdf.internal.events.publish('htmlRenderingFinished'); |
| 436 | + callback(r.dispose()); |
| 437 | + }); |
| 438 | + }); |
| 439 | + |
337 | 440 | return r.dispose();
|
338 | 441 | };
|
339 | 442 | Renderer.prototype.init = function() {
|
|
344 | 447 | return this.pdf.internal.write("q");
|
345 | 448 | };
|
346 | 449 | Renderer.prototype.dispose = function() {
|
347 |
| - this.pdf.internal.write("Q"); |
| 450 | + this.pdf.internal.write("Q"); |
348 | 451 | return {
|
349 | 452 | x: this.x,
|
350 | 453 | y: this.y
|
|
406 | 509 | if (this.pdf.internal.pageSize.height - this.pdf.margins_doc.bottom < this.y + this.pdf.internal.getFontSize()) {
|
407 | 510 | this.pdf.internal.write("ET", "Q");
|
408 | 511 | this.pdf.addPage();
|
409 |
| - this.y = this.pdf.margins_doc.top; |
| 512 | + this.y = this.pdf.margins_doc.top; |
410 | 513 | this.pdf.internal.write("q", "BT", this.pdf.internal.getCoordinateString(this.x), this.pdf.internal.getVerticalCoordinateString(this.y), "Td");
|
411 | 514 | }
|
412 | 515 | defaultFontSize = 12;
|
|
0 commit comments