|
27 | 27 | */
|
28 | 28 |
|
29 | 29 | (function(jsPDFAPI) {
|
30 |
| - var clone,DrillForContent, FontNameDB, FontStyleMap, FontWeightMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, process, tableToJson; |
| 30 | + var clone,DrillForContent, FontNameDB, FontStyleMap, FontWeightMap, GetCSS, PurgeWhiteSpace, Renderer, ResolveFont, ResolveUnitedNumber, UnitedNumberMap, elementHandledElsewhere, images, loadImgs, checkForFooter, process, tableToJson; |
31 | 31 | clone = (function(){
|
32 | 32 | return function (obj) { Clone.prototype=obj; return new Clone() };
|
33 | 33 | function Clone(){}
|
|
270 | 270 | while (i < l) {
|
271 | 271 | cn = cns[i];
|
272 | 272 | if (typeof cn === "object") {
|
| 273 | + |
| 274 | + /*** HEADER rendering **/ |
| 275 | + if (cn.nodeType === 1 && cn.nodeName === 'HEADER') { |
| 276 | + var header = cn; |
| 277 | + //store old top margin |
| 278 | + var oldMarginTop = renderer.pdf.margins_doc.top; |
| 279 | + //subscribe for new page event and render header first on every page |
| 280 | + renderer.pdf.internal.events.subscribe('addPage', function(pageInfo) { |
| 281 | + //set current y position to old margin |
| 282 | + renderer.y = oldMarginTop; |
| 283 | + //render all child nodes of the header element |
| 284 | + DrillForContent(header,renderer,elementHandlers); |
| 285 | + //set margin to old margin + rendered header + 10 space to prevent overlapping |
| 286 | + //important for other plugins (e.g. table) to start rendering at correct position after header |
| 287 | + renderer.pdf.margins_doc.top = renderer.y+10; |
| 288 | + renderer.y += 10; |
| 289 | + }, false); |
| 290 | + } |
| 291 | + |
273 | 292 | if (cn.nodeType === 8 && cn.nodeName === "#comment") {
|
274 | 293 | if (cn.textContent.match("ADD_PAGE")) {
|
275 | 294 | renderer.pdf.addPage();
|
|
343 | 362 | loadImgs = function(element, renderer, elementHandlers, cb) {
|
344 | 363 | var imgs = element.getElementsByTagName('img'), l = imgs.length, x = 0;
|
345 | 364 | function done() {
|
346 |
| - DrillForContent(element, renderer, elementHandlers); |
347 |
| - cb(renderer.dispose()); |
| 365 | + renderer.pdf.internal.events.publish('imagesLoaded'); |
| 366 | + cb(); |
348 | 367 | }
|
349 | 368 | function loadImage(url) {
|
350 | 369 | if(!url) return;
|
|
362 | 381 | cb = cb || function() {};
|
363 | 382 | return x || done();
|
364 | 383 | };
|
| 384 | + checkForFooter = function(elem, renderer, elementHandlers, callback) { |
| 385 | + //check if we can found a <footer> element |
| 386 | + var footer = elem.getElementsByTagName("footer"); |
| 387 | + if (footer.length > 0) { |
| 388 | + |
| 389 | + footer = footer[0]; |
| 390 | + |
| 391 | + //bad hack to get height of footer |
| 392 | + //creat dummy out and check new y after fake rendering |
| 393 | + var oldOut = renderer.pdf.internal.write; |
| 394 | + var oldY = renderer.y; |
| 395 | + renderer.pdf.internal.write = function() {}; |
| 396 | + DrillForContent(footer, renderer, elementHandlers); |
| 397 | + var footerHeight = Math.ceil(renderer.y-oldY)+5; |
| 398 | + renderer.y = oldY; |
| 399 | + renderer.pdf.internal.write = oldOut; |
| 400 | + |
| 401 | + //add 20% to prevent overlapping |
| 402 | + renderer.pdf.margins_doc.bottom += footerHeight; |
| 403 | + |
| 404 | + //Create function render header on every page |
| 405 | + var renderFooter = function(pageInfo) { |
| 406 | + var pageNumber = pageInfo !== undefined ? pageInfo.pageNumber : 1; |
| 407 | + //set current y position to old margin |
| 408 | + var oldPosition = renderer.y; |
| 409 | + //render all child nodes of the header element |
| 410 | + renderer.y = renderer.pdf.internal.pageSize.height - renderer.pdf.margins_doc.bottom; |
| 411 | + renderer.pdf.margins_doc.bottom -= footerHeight; |
| 412 | + |
| 413 | + //check if we have to add page numbers |
| 414 | + var spans = footer.getElementsByTagName('span'); |
| 415 | + for(var i=0; i < spans.length; ++i) { |
| 416 | + //if we find some span element with class pageCounter, set the page |
| 417 | + if ( (" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" pageCounter ") > -1 ) { |
| 418 | + spans[i].innerHTML = pageNumber; |
| 419 | + } |
| 420 | + //if we find some span element with class totalPages, set a variable which is replaced after rendering of all pages |
| 421 | + if ( (" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1 ) { |
| 422 | + spans[i].innerHTML = '###jsPDFVarTotalPages###'; |
| 423 | + } |
| 424 | + } |
| 425 | + |
| 426 | + //render footer content |
| 427 | + DrillForContent(footer,renderer,elementHandlers); |
| 428 | + //set bottom margin to previous height including the footer height |
| 429 | + renderer.pdf.margins_doc.bottom += footerHeight; |
| 430 | + //important for other plugins (e.g. table) to start rendering at correct position after header |
| 431 | + renderer.y = oldPosition; |
| 432 | + }; |
| 433 | + |
| 434 | + //check if footer contains totalPages which shoudl be replace at the disoposal of the document |
| 435 | + var spans = footer.getElementsByTagName('span'); |
| 436 | + for(var i=0; i < spans.length; ++i) { |
| 437 | + if ( (" " + spans[i].className + " ").replace(/[\n\t]/g, " ").indexOf(" totalPages ") > -1 ) { |
| 438 | + renderer.pdf.internal.events.subscribe('htmlRenderingFinished', renderer.pdf.putTotalPages.bind(renderer.pdf, '###jsPDFVarTotalPages###'), true); |
| 439 | + } |
| 440 | + } |
| 441 | + |
| 442 | + //register event to render footer on every new page |
| 443 | + renderer.pdf.internal.events.subscribe('addPage', renderFooter, false); |
| 444 | + //render footer on first page |
| 445 | + renderFooter(); |
| 446 | + |
| 447 | + //prevent footer rendering |
| 448 | + SkipNode['FOOTER'] = 1; |
| 449 | + |
| 450 | + } |
| 451 | + |
| 452 | + //footer preperation finished |
| 453 | + callback(); |
| 454 | + |
| 455 | + }; |
365 | 456 | process = function(pdf, element, x, y, settings, callback) {
|
366 | 457 | if (!element) return false;
|
367 | 458 | if (!element.parentNode) element = '' + element.innerHTML;
|
|
380 | 471 | })(element.replace(/<\/?script[^>]*?>/gi,''));
|
381 | 472 | }
|
382 | 473 | var r = new Renderer(pdf, x, y, settings);
|
383 |
| - loadImgs.call(this, element, r, settings.elementHandlers, callback); |
| 474 | + |
| 475 | + // 1. load images |
| 476 | + // 2. prepare optional footer elements |
| 477 | + // 3. render content |
| 478 | + loadImgs.call(this, element, r, settings.elementHandlers, function() { |
| 479 | + checkForFooter.call(this, element, r, settings.elementHandlers, function() { |
| 480 | + DrillForContent(element, r, settings.elementHandlers); |
| 481 | + //send event dispose for final taks (e.g. footer totalpage replacement) |
| 482 | + r.pdf.internal.events.publish('htmlRenderingFinished'); |
| 483 | + callback(r.dispose()); |
| 484 | + }); |
| 485 | + }); |
| 486 | + |
384 | 487 | return r.dispose();
|
385 | 488 | };
|
386 | 489 | Renderer.prototype.init = function() {
|
|
475 | 578 | }
|
476 | 579 |
|
477 | 580 | return lines;
|
478 |
| - }; |
| 581 | + }; |
479 | 582 | Renderer.prototype.RenderTextFragment = function(text, style) {
|
480 | 583 | var defaultFontSize, font;
|
481 | 584 | if (this.pdf.internal.pageSize.height - this.pdf.margins_doc.bottom < this.y + this.pdf.internal.getFontSize()) {
|
|
0 commit comments