From a315a4d8279987afe49c6c3c86985063113ff69f Mon Sep 17 00:00:00 2001 From: Steven Spungin Date: Wed, 12 Nov 2014 11:40:52 -0500 Subject: [PATCH] Added a plugin manager. Fire a plugin event on the static PubSub before the first page is added. --- jspdf.js | 18 ++- jspdf.plugin.annotations.js | 27 ++-- jspdf.plugin.outline.js | 254 +++++++++++++++++++----------------- test/test_annotation.html | 13 +- test/test_outline.html | 1 - 5 files changed, 179 insertions(+), 134 deletions(-) diff --git a/jspdf.js b/jspdf.js index 5a85b391d..c3394c9bb 100644 --- a/jspdf.js +++ b/jspdf.js @@ -1768,6 +1768,7 @@ var jsPDF = (function(global) { // Add the first page automatically addFonts(); activeFontKey = 'F1'; + jsPDF.plugins.internal.onInitialize(API); _addPage(format, orientation); events.publish('initialized'); @@ -1802,7 +1803,6 @@ var jsPDF = (function(global) { */ jsPDF.API = {events:[]}; jsPDF.version = "1.0.0-trunk"; - if (typeof define === 'function' && define.amd) { define('jsPDF', function() { return jsPDF; @@ -1810,5 +1810,21 @@ var jsPDF = (function(global) { } else { global.jsPDF = jsPDF; } + jsPDF.plugins = { + register:function(plugin){ + this.internal.plugins.push(plugin); + }, + internal:{ + plugins:[], + onInitialize: function(pdf){ + for (var i = 0; i < this.plugins.length; i++) { + var plugin = this.plugins[i]; + if (typeof plugin.onInitialize === 'function'){ + plugin.onInitialize.call(plugin, pdf); + } + } + }, + } + }; return jsPDF; }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this)); diff --git a/jspdf.plugin.annotations.js b/jspdf.plugin.annotations.js index 7b53bd658..3b7d94e18 100644 --- a/jspdf.plugin.annotations.js +++ b/jspdf.plugin.annotations.js @@ -8,7 +8,7 @@ /** * There are many types of annotations in a PDF document. Annotations are placed - * on a page at a particular location. They are not 'attached' to an object' + * on a page at a particular location. They are not 'attached' to an object. *
* This plugin current supports
*
  • Goto Page (set pageNumber in options) @@ -36,23 +36,31 @@ function notEmpty(obj) { (function(jsPDFAPI) { 'use strict'; - jsPDFAPI.initAnnotationPlugin = function() { - this.annotationPlugin = {}; + var annotationPlugin = { + onInitialize : function(pdf) { + this.installAnnotationPlugin(pdf); + } + }; + jsPDF.API.annotationPlugin = annotationPlugin; + jsPDF.plugins.register(annotationPlugin); + + annotationPlugin.installAnnotationPlugin = function(pdf) { - this.annotationPlugin.annotations = []; + this.annotations = []; + // TODO remove this after we find a way to subscribe before the // first page is created. - this.annotationPlugin.annotations[1] = []; + //this.annotations[1] = []; - this.annotationPlugin.f2 = function(number) { + this.f2 = function(number) { return number.toFixed(2); }; - this.internal.events.subscribe('addPage', function(info) { + pdf.internal.events.subscribe('addPage', function(info) { this.annotationPlugin.annotations[info.pageNumber] = []; }); - this.internal.events.subscribe('render/page', function(info) { + pdf.internal.events.subscribe('render/page', function(info) { var pageAnnos = this.annotationPlugin.annotations[info.pageNumber]; var found = false; @@ -70,11 +78,12 @@ function notEmpty(obj) { } this.internal.write("/Annots ["); + var f2 = this.annotationPlugin.f2; for (var a = 0; a < pageAnnos.length; a++) { var anno = pageAnnos[a]; var k = this.internal.scaleFactor; var pageHeight = this.internal.pageSize.height; - var rect = "/Rect [" + this.annotationPlugin.f2(anno.x * k) + " " + this.annotationPlugin.f2((pageHeight - anno.y) * k) + " " + this.annotationPlugin.f2(anno.x + anno.w * k) + " " + this.annotationPlugin.f2(pageHeight - (anno.y + anno.h) * k) + "] "; + var rect = "/Rect [" + f2(anno.x * k) + " " + f2((pageHeight - anno.y) * k) + " " + f2(anno.x + anno.w * k) + " " + f2(pageHeight - (anno.y + anno.h) * k) + "] "; if (anno.options.url) { this.internal.write('<> >>') } else if (anno.options.pageNumber) { diff --git a/jspdf.plugin.outline.js b/jspdf.plugin.outline.js index f73081e7e..5a5b24daa 100644 --- a/jspdf.plugin.outline.js +++ b/jspdf.plugin.outline.js @@ -12,151 +12,165 @@ ; (function(jsPDFAPI) { 'use strict'; - - jsPDFAPI.initOutlinePlugin = function() { - - this.outline = {}; - this.outline.root = { - children : [] - }; - - this.internal.events.subscribe('postPutResources', function() { - if (this.outline.root.children.length > 0) { - var lines = this.outline.render().split(/\r\n/); - for (var int = 0; int < lines.length; int++) { - var line = lines[int]; - if (line.endsWith('obj')){ - var oid = line.split(' ')[0]; - this.internal.newObjectDeferredBegin(oid); + var outline = { + + onInitialize : function(pdf) { + + this.installOutlinePlugin(pdf); + + pdf.internal.events.subscribe('postPutResources', function() { + + var rx = /^(\d+) 0 obj$/; + + if (this.outline.root.children.length > 0) { + var lines = pdf.outline.render().split(/\r\n/); + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + var m = rx.exec(line); + if (m != null) { + var oid = m[1]; + pdf.internal.newObjectDeferredBegin(oid); + } + pdf.internal.write(line); } - this.internal.write(line); } - } - }); + }); + + pdf.internal.events.subscribe('putCatalog', function() { + if (pdf.outline.root.children.length > 0) { + pdf.internal.write("/Outlines", this.outline.makeRef(this.outline.root)); + } + }); + }, + + installOutlinePlugin : function(pdf) { - this.internal.events.subscribe('putCatalog', function() { - if (this.outline.root.children.length > 0) { - this.internal.write("/Outlines", this.outline.makeRef(this.outline.root)); - } - }); - - /** - * Options: pageNumber - */ - this.outline.add = function(parent,title,options) { - var item = { - title : title, - options : options, + pdf.outline = {}; + pdf.outline.root = { children : [] }; - if (parent == null) { - parent = this.root; + + /** + * Options: pageNumber + */ + pdf.outline.add = function(parent,title,options) { + var item = { + title : title, + options : options, + children : [] + }; + if (parent == null) { + parent = this.root; + } + parent.children.push(item); + return item; } - parent.children.push(item); - return item; - } - this.outline.render = function() { - this.outline.ctx = {}; - this.outline.nextId = 1000; - this.outline.ctx.val = ''; - this.outline.ctx.pdf = this; + pdf.outline.render = function() { + this.ctx = {}; + this.ctx.val = ''; + this.ctx.pdf = pdf; - this.outline.genIds_r(this.outline.root); - this.outline.renderRoot(this.outline.root); - this.outline.renderItems(this.outline.root); + this.genIds_r(this.root); + this.renderRoot(this.root); + this.renderItems(this.root); - return this.outline.ctx.val; - }.bind(this); + return this.ctx.val; + }; - this.outline.genIds_r = function(node) { - node.id = this.internal.newObjectDeferred(); - for (var i = 0; i < node.children.length; i++) { - this.outline.genIds_r(node.children[i]); - } - }.bind(this); - - this.outline.renderRoot = function(node) { - this.objStart(node); - this.line('/Type /Outlines'); - if (node.children.length > 0) { - this.line('/First ' + this.makeRef(node.children[0])); - this.line('/Last ' + this.makeRef(node.children[node.children.length - 1])); - } - this.line('/Count ' + this.count_r({ - count : 0 - }, node)); - this.objEnd(); - } + pdf.outline.genIds_r = function(node) { + node.id = pdf.internal.newObjectDeferred(); + for (var i = 0; i < node.children.length; i++) { + this.genIds_r(node.children[i]); + } + }; - this.outline.renderItems = function(node) { - for (var i = 0; i < node.children.length; i++) { - var item = node.children[i]; - this.objStart(item); + pdf.outline.renderRoot = function(node) { + this.objStart(node); + this.line('/Type /Outlines'); + if (node.children.length > 0) { + this.line('/First ' + this.makeRef(node.children[0])); + this.line('/Last ' + this.makeRef(node.children[node.children.length - 1])); + } + this.line('/Count ' + this.count_r({ + count : 0 + }, node)); + this.objEnd(); + }; - this.line('/Title ' + this.makeString(item.title)); + pdf.outline.renderItems = function(node) { + for (var i = 0; i < node.children.length; i++) { + var item = node.children[i]; + this.objStart(item); - this.line('/Parent ' + this.makeRef(node)); - if (i > 0) { - this.line('/Prev ' + this.makeRef(node.children[i - 1])); - } - if (i < node.children.length - 1) { - this.line('/Next ' + this.makeRef(node.children[i + 1])); - } - if (item.children.length > 0) { - this.line('/First ' + this.makeRef(item.children[0])); - this.line('/Last ' + this.makeRef(item.children[item.children.length - 1])); - } + this.line('/Title ' + this.makeString(item.title)); - var count = this.count = this.count_r({ - count : 0 - }, item); - if (count > 0) { - this.line('/Count ' + count); - } + this.line('/Parent ' + this.makeRef(node)); + if (i > 0) { + this.line('/Prev ' + this.makeRef(node.children[i - 1])); + } + if (i < node.children.length - 1) { + this.line('/Next ' + this.makeRef(node.children[i + 1])); + } + if (item.children.length > 0) { + this.line('/First ' + this.makeRef(item.children[0])); + this.line('/Last ' + this.makeRef(item.children[item.children.length - 1])); + } + + var count = this.count = this.count_r({ + count : 0 + }, item); + if (count > 0) { + this.line('/Count ' + count); + } - if (item.options) { - if (item.options.pageNumber) { - this.line('/Dest ' + '[' + (item.options.pageNumber - 1) + ' /XYZ 0 ' + this.ctx.pdf.internal.pageSize.height + ' 0]'); - //this.line('/Dest ' + '[' + (item.options.pageNumber - 1) + ' /Fit]'); + if (item.options) { + if (item.options.pageNumber) { + this.line('/Dest ' + '[' + (item.options.pageNumber - 1) + ' /XYZ 0 ' + this.ctx.pdf.internal.pageSize.height + ' 0]'); + // this.line('/Dest ' + '[' + + // (item.options.pageNumber - + // 1) + ' /Fit]'); + } } + this.objEnd(); } - this.objEnd(); - } - for (var i = 0; i < node.children.length; i++) { - var item = node.children[i]; - this.renderItems(item); - } - } + for (var i = 0; i < node.children.length; i++) { + var item = node.children[i]; + this.renderItems(item); + } + }; - this.outline.line = function(text) { - this.ctx.val += text + '\r\n'; - } + pdf.outline.line = function(text) { + this.ctx.val += text + '\r\n'; + }; - this.outline.makeRef = function(node) { - return node.id + ' 0 R'; - } + pdf.outline.makeRef = function(node) { + return node.id + ' 0 R'; + }; - this.outline.makeString = function(val) { - return '(' + this.internal.pdfEscape(val) + ')'; - }.bind(this); + pdf.outline.makeString = function(val) { + return '(' + pdf.internal.pdfEscape(val) + ')'; + }; - this.outline.objStart = function(node) { - this.ctx.val += '\r\n' + node.id + ' 0 obj' + '\r\n<<\r\n'; - } + pdf.outline.objStart = function(node) { + this.ctx.val += '\r\n' + node.id + ' 0 obj' + '\r\n<<\r\n'; + }; - this.outline.objEnd = function(node) { - this.ctx.val += '>> \r\n' + 'endobj' + '\r\n'; - } + pdf.outline.objEnd = function(node) { + this.ctx.val += '>> \r\n' + 'endobj' + '\r\n'; + }; - this.outline.count_r = function(ctx,node) { - for (var i = 0; i < node.children.length; i++) { - ctx.count++; - this.count_r(ctx, node.children[i]); - } - return ctx.count; + pdf.outline.count_r = function(ctx,node) { + for (var i = 0; i < node.children.length; i++) { + ctx.count++; + this.count_r(ctx, node.children[i]); + } + return ctx.count; + }; } } + jsPDF.API.outline = outline; + jsPDF.plugins.register(outline); return this; })(jsPDF.API); diff --git a/test/test_annotation.html b/test/test_annotation.html index 7e7a2bb18..e36520026 100644 --- a/test/test_annotation.html +++ b/test/test_annotation.html @@ -27,7 +27,6 @@ var pdf = new jsPDF('p', 'pt', 'letter'); - pdf.initAnnotationPlugin(); // Create pages with a table of contents. // TOC links to each page @@ -60,8 +59,8 @@ } // generate either the pdf or source code - //TODO use query string ?source=true - if(true){ + // generate either the pdf or source code + if (getParameterByName('src') != 'true'){ var frame = document.getElementById('pdfframe'); frame.src = pdf.output('datauristring'); } @@ -88,6 +87,14 @@ return entityMap[s]; }); } + + function getParameterByName(name) { + name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]"); + var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), + results = regex.exec(location.search); + return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); + } + diff --git a/test/test_outline.html b/test/test_outline.html index 65e3af0db..67f04e702 100644 --- a/test/test_outline.html +++ b/test/test_outline.html @@ -32,7 +32,6 @@ pdf.addPage(); pdf.text(20, 20, 'More'); - pdf.initOutlinePlugin(); var node = pdf.outline.add(null, 'Test Pages', null); pdf.outline.add(node, 'Hello', {pageNumber:1}); pdf.outline.add(node, 'PDF', {pageNumber:2});