Comparing version 0.3.0 to 0.3.1
@@ -33,2 +33,3 @@ module.exports = function(opts, definition) { | ||
this.rows = [] | ||
this._beforeBreak = this._afterBreak = null | ||
@@ -44,47 +45,76 @@ if (definition) definition.call(this, this) | ||
Table.prototype.beforeBreak = function(opts, definition) { | ||
return this._beforeBreak = new Row(this, opts, definition) | ||
} | ||
Table.prototype.afterBreak = function(opts, definition) { | ||
return this._afterBreak = new Row(this, opts, definition) | ||
} | ||
Table.prototype.render = function(page, width) { | ||
var columns = [], self = this | ||
var highestRowWidth = Math.max.apply(Math, this.rows.map(function(row) { | ||
return row.cells.map(function(cell, i) { | ||
if (columns[i] === undefined || (cell.width > columns[i] && !(cell.opts.colspan > 1))) | ||
columns[i] = cell.width | ||
return cell.width | ||
}).reduce(function(lhs, rhs) { return lhs + rhs }, 0) | ||
})) | ||
var maxWidth = width | ||
if (highestRowWidth > maxWidth) { | ||
var widthPerCell = maxWidth / columns.length | ||
, toShrink = [] | ||
, unused = 0 | ||
, maxWidth = minWidth = width | ||
if (Array.isArray(this.opts.width)) { | ||
var widths = this.opts.width | ||
var absolute = 0 | ||
widths.forEach(function(width, i) { | ||
if (!!~width.toString().indexOf('%')) | ||
return | ||
absolute += (columns[i] = parseFloat(width)) | ||
}) | ||
var remaining = maxWidth - absolute | ||
widths.forEach(function(width, i) { | ||
if (!!~width.toString().indexOf('%')) { | ||
columns[i] = utils.resolveWidth(width, remaining) | ||
} | ||
}) | ||
} else { | ||
if ('width' in this.opts) | ||
minWidth = utils.resolveWidth(widths, maxWidth) | ||
var highestRowWidth = Math.max.apply(Math, this.rows.map(function(row) { | ||
return row.cells.map(function(cell, i) { | ||
if (columns[i] === undefined || (cell.width > columns[i] && !(cell.opts.colspan > 1))) | ||
columns[i] = cell.width | ||
return cell.width | ||
}).reduce(function(lhs, rhs) { return lhs + rhs }, 0) | ||
})) | ||
for (var i = 0, len = columns.length; i < len; ++i) { | ||
if (columns[i] < widthPerCell) unused += widthPerCell - columns[i] | ||
else toShrink.push(i) | ||
if (highestRowWidth > maxWidth) { | ||
var widthPerCell = maxWidth / columns.length | ||
, toShrink = [] | ||
, unused = 0 | ||
for (var i = 0, len = columns.length; i < len; ++i) { | ||
if (columns[i] < widthPerCell) unused += widthPerCell - columns[i] | ||
else toShrink.push(i) | ||
} | ||
widthPerCell += unused / toShrink.length | ||
toShrink.forEach(function(i) { | ||
columns[i] = widthPerCell | ||
}) | ||
} | ||
widthPerCell += unused / toShrink.length | ||
toShrink.forEach(function(i) { | ||
columns[i] = widthPerCell | ||
}) | ||
} | ||
var minWidth = this.opts.width || maxWidth | ||
if (minWidth && highestRowWidth < minWidth) { | ||
var widthPerCell = minWidth / columns.length | ||
, toExtend = [] | ||
, used = 0 | ||
for (var i = 0, len = columns.length; i < len; ++i) { | ||
if (columns[i] < widthPerCell) toExtend.push(i) | ||
used += columns[i] | ||
if (minWidth && highestRowWidth < minWidth) { | ||
var widthPerCell = minWidth / columns.length | ||
, toExtend = [] | ||
, used = 0 | ||
for (var i = 0, len = columns.length; i < len; ++i) { | ||
if (columns[i] < widthPerCell) toExtend.push(i) | ||
used += columns[i] | ||
} | ||
var add = (minWidth - used) / toExtend.length | ||
toExtend.forEach(function(i) { | ||
columns[i] += add | ||
}) | ||
} | ||
var add = (minWidth - used) / toExtend.length | ||
toExtend.forEach(function(i) { | ||
columns[i] += add | ||
}) | ||
} | ||
var left = page.cursor.x | ||
var left = page.cursor.x, transactions = [] | ||
for (var i = 0; i < this.rows.length; ++i) { | ||
@@ -94,5 +124,5 @@ var y = page.cursor.y | ||
var transaction = this.doc.startTransaction() | ||
var transaction = transactions[i] = this.doc.startTransaction() | ||
var height = row.render(page, columns) | ||
var height = row.render(page, columns, { table: { row: i }, doc: this.doc }) | ||
@@ -106,6 +136,39 @@ if (height === false) { | ||
--i | ||
// before break | ||
if (this._beforeBreak) { | ||
while (height === false && i > 0) { | ||
var attempt = this.doc.startTransaction() | ||
height = this._beforeBreak.render(page, columns, { table: { row: i }, doc: this.doc }) | ||
if (height === false) { | ||
page.cursor.x = left | ||
page.cursor.y = y | ||
attempt.rollback() | ||
this.rows[i].allowBreak = false | ||
transactions[i--].rollback() | ||
this.rows[i].allowBreak = true | ||
} else { | ||
attempt.commit() | ||
} | ||
} | ||
} | ||
// break | ||
page = this.doc.pagebreak() | ||
y = page.cursor.y | ||
height = 0 | ||
var context = { table: { row: i }, doc: this.doc } | ||
// after break | ||
if (this._afterBreak) { | ||
page.cursor.x = left | ||
height += this._afterBreak.render(page, columns, context) | ||
page.cursor.y = y - height | ||
} | ||
// header | ||
if (this.opts.header === true) { | ||
page = this.doc.pagebreak() | ||
y = page.cursor.y | ||
height = this.rows[0].render(page, columns) | ||
page.cursor.x = left | ||
height += this.rows[0].render(page, columns, context) | ||
} | ||
@@ -164,3 +227,3 @@ } else { | ||
Row.prototype.render = function(page, columns) { | ||
Row.prototype.render = function(page, columns, context) { | ||
var left = page.cursor.x | ||
@@ -196,3 +259,3 @@ , y = page.cursor.y | ||
var pageIndex = this.doc.pages.pages.indexOf(page) | ||
cell.render(page, innerWidth) // below: padding bottom | ||
cell.render(page, innerWidth, context) // below: padding bottom | ||
var height = pageIndex + 1 < this.doc.pages.count | ||
@@ -252,4 +315,4 @@ ? y - this.doc.padding.bottom | ||
Cell.prototype.render = function(page, width) { | ||
this.content.render(page, width) | ||
Cell.prototype.render = function(page, width, context) { | ||
this.content.render(page, width, context) | ||
} | ||
@@ -377,2 +440,3 @@ | ||
for (var key in from) { | ||
if (key === 'width') continue | ||
var val = into[key] | ||
@@ -379,0 +443,0 @@ if (val === undefined || val === null) |
@@ -30,10 +30,14 @@ var PDFString = require('../objects/string') | ||
var self = this, font = (opts.font ? this.doc.registerFont(opts.font) : this.doc.defaultFont).fromOpts(opts) | ||
var words = str.toString().replace(/\t/g, ' ').replace(/\r\n/g, '\n').split(/ +|^|$/mg) | ||
// if (words[0].match(/\.\!\?\,/) && this.contents.length) | ||
// this.contents[this.contents.length - 1].content += words.shift() | ||
words.forEach(function(word) { | ||
if (!word.length) return | ||
font.use(word) | ||
self.contents.push(new Word(word, font, opts)) | ||
}) | ||
if (typeof str === 'function') { | ||
this.contents.push(new Word(str, font, opts)) | ||
} else { | ||
var words = str.toString().replace(/\t/g, ' ').replace(/\r\n/g, '\n').split(/ +|^|$/mg) | ||
// if (words[0].match(/\.\!\?\,/) && this.contents.length) | ||
// this.contents[this.contents.length - 1].content += words.shift() | ||
words.forEach(function(word) { | ||
if (!word.length) return | ||
font.use(word) | ||
self.contents.push(new Word(word, font, opts)) | ||
}) | ||
} | ||
return this.textFn | ||
@@ -43,3 +47,5 @@ } | ||
Text.prototype.text.br = function() { | ||
this.contents.push(new Word('\n', this.opts.font ? this.doc.registerFont(opts.font) : this.doc.defaultFont.regular, {})) | ||
this.contents.push(new Word('\n', this.opts.font ? this.doc.registerFont(opts.font) : this.doc.defaultFont.regular, { | ||
size: this.opts.size | ||
})) | ||
return this.textFn | ||
@@ -49,9 +55,10 @@ } | ||
Text.prototype.text.pageNumber = function() { | ||
this.contents.push(new Word((function() { | ||
return this.pages.count | ||
}).bind(this.doc.doc || this.doc), this.opts.font ? this.doc.registerFont(opts.font) : this.doc.defaultFont.regular, {})) | ||
this.text(function() { | ||
if (!this.pages && !this.doc) return | ||
return (this.pages || this.doc.pages).count | ||
}) | ||
return this.textFn | ||
} | ||
Text.prototype.render = function(page, width) { | ||
Text.prototype.render = function(page, width, context) { | ||
var self = this | ||
@@ -137,2 +144,3 @@ , spaceLeft = width | ||
this.contents.forEach(function(word, i) { | ||
word.context = context || (self.doc.doc || self.doc) | ||
var wordWidth = word.width, wordSpacing = !line.length || word.isStartingWithPunctuation ? 0 : word.spacing | ||
@@ -183,2 +191,3 @@ | ||
this.opts = opts || {} | ||
this.context = {} | ||
Object.defineProperty(this, 'word', { | ||
@@ -214,2 +223,3 @@ enumerable: true, | ||
get: function() { | ||
if (!this.word[0]) return false | ||
return this.word[0].match(/\.|\!|\?|,/) !== null | ||
@@ -222,3 +232,3 @@ } | ||
if (typeof this._word === 'function') { | ||
var res = this._word().toString() | ||
var res = (this._word.call(this.context) || '').toString() | ||
this.font.use(res) | ||
@@ -225,0 +235,0 @@ return res |
@@ -85,3 +85,3 @@ var Fragment = module.exports = function(doc, opts) { | ||
Fragment.prototype.render = function(page, width) { | ||
Fragment.prototype.render = function(page, width, context) { | ||
var x = page.cursor.x | ||
@@ -96,3 +96,3 @@ page.cursor.x += this.padding.left | ||
this.contents.forEach(function(content) { | ||
content.render(self.doc.cursor, width || self.innerWidth) | ||
content.render(self.doc.cursor, width || self.innerWidth, context) | ||
}) | ||
@@ -99,0 +99,0 @@ if ('minHeight' in this.opts && this.doc.cursor === page && (y - this.opts.minHeight) < page.cursor.y) { |
@@ -14,2 +14,14 @@ exports.extend = function(destination, source) { | ||
}) | ||
} | ||
exports.resolveWidth = function(width, maxWidth) { | ||
var isRelative = !!~width.toString().indexOf('%') | ||
width = parseFloat(width) | ||
if (isRelative) { | ||
if (width >= 100) return maxWidth | ||
return (width / 100) * maxWidth | ||
} else { | ||
if (width > maxWidth) return maxWidth | ||
else return width | ||
} | ||
} |
@@ -7,3 +7,3 @@ { | ||
}, | ||
"version": "0.3.0", | ||
"version": "0.3.1", | ||
"homepage": "https://github.com/rkusa/pdfjs", | ||
@@ -10,0 +10,0 @@ "keywords": ["pdf", "generator"], |
205
README.md
@@ -6,6 +6,6 @@ # pdfjs | ||
{ "name": "pdfjs", | ||
"version": "0.3.0" } | ||
"version": "0.3.1" } | ||
``` | ||
### Status | ||
#### Status | ||
@@ -17,9 +17,11 @@ Early development stage, i.e., not well tested. | ||
### Contents | ||
1. [API](#api) | ||
2. [License](#license) | ||
#### Contents | ||
## API | ||
1. [Document](#document) | ||
2. [Text](#text) | ||
3. [Table](#table) | ||
4. [Font](#font) | ||
5. [License](#license) | ||
### Document | ||
## Document | ||
@@ -30,3 +32,3 @@ ```js | ||
#### new Document(font) | ||
### new Document(font) | ||
@@ -47,3 +49,3 @@ **Arguments:** | ||
#### .text(text, opts) | ||
### .text(text[, opts]) | ||
@@ -75,20 +77,16 @@ **Arguments:** | ||
#### .text(fn) | ||
### .text([definition]) | ||
This text method can be used to render more advanced/complex text fragments. It allows to combine multiple text styles. | ||
This text method can be used to render more advanced/complex text fragments. It allows to combine multiple text styles. **Returns** a [Text](#text) function. | ||
**Arguments:** | ||
* **fn** - a function describing the text to be rendered; it gets the `text` function described below as an argument | ||
* **definition** - a function describing the text to be rendered; it gets the `text` object described in [Text](#text) | ||
**text(text, opts)** | ||
* **.br()** - line break | ||
* **.pageNumber()** - current page number | ||
**Example:** | ||
```js | ||
this.text(function(text) { | ||
text.opts.size = 12 | ||
doc.text(function(text) { | ||
// this === text | ||
this.opts.size = 12 | ||
this.opts.lineSpacing = 1.35 | ||
@@ -106,10 +104,25 @@ text('This is a header', { bold: true, size: 18 }).br() | ||
![Result](https://dl.dropboxusercontent.com/u/6699613/Github/pdfjs-example1.png) | ||
**Result:** | ||
#### .table([opts, ] definition) | ||
![Result](https://raw.github.com/rkusa/pdfjs/gh-pages/images/text-example.png) | ||
### .table([opts, ] [definition]) | ||
This method can be used to define tables. **Returns** a [Table](#table) object. | ||
**Arguments:** | ||
* **opts** - table options | ||
* **definition** - a function that contains the table definition | ||
**Options:** | ||
* **borderWidth** - | ||
* **width** - total width (absolute or relative) or an array of column widths | ||
* + [Text Options](#texttext-opts) | ||
**Example:** | ||
```js | ||
doc.table({ header: true, size: 14 }, function() { | ||
doc.table({ header: true, size: 11 }, function() { | ||
this.tr({ bold: true, borderWidth: { bottom: 1.5 } }, function() { | ||
@@ -119,4 +132,4 @@ this.td('#') | ||
this.td('Subject') | ||
this.td('Price') | ||
this.td('Total') | ||
this.td('Price', { align: 'right' }) | ||
this.td('Total', { align: 'right' }) | ||
}) | ||
@@ -127,4 +140,4 @@ this.tr({ borderWidth: { horizontal: 0.1 } }, function() { | ||
this.td(function() { | ||
this.text('Article A', { size: 14, bold: true }) | ||
this.text('Lorem ipsum ...', { size: 12, align: 'justify' }) | ||
this.text('Article A', { size: 11, bold: true }) | ||
this.text('Lorem ipsum ...', { size: 9, align: 'justify' }) | ||
}) | ||
@@ -138,4 +151,4 @@ this.td('500.00€', { align: 'right' }) | ||
this.td(function() { | ||
this.text('Article B', { size: 14, bold: true }) | ||
this.text('Lorem ipsum ...', { size: 12, align: 'justify' }) | ||
this.text('Article B', { size: 11, bold: true }) | ||
this.text('Cum id fugiunt ...', { size: 9, align: 'justify' }) | ||
}) | ||
@@ -152,4 +165,8 @@ this.td('250.00€', { align: 'right' }) | ||
#### .toDataURL() | ||
**Result:** | ||
![Result](https://raw.github.com/rkusa/pdfjs/gh-pages/images/table-example.png) | ||
### .toDataURL() | ||
Returns the document as [data URL](https://developer.mozilla.org/en-US/docs/data_URIs). | ||
@@ -169,3 +186,3 @@ | ||
#### .toString() | ||
### .toString() | ||
@@ -181,9 +198,131 @@ Returns the document as plain text. | ||
### Font | ||
## Text | ||
#### new Font(path) | ||
#### new Font(opts) | ||
This is a function itself and an alias for `.text()`. It is used to define more complex/advanced text fragments. **Returns** itself. | ||
### .text() | ||
Same as [doc.text(text[, opts])](#texttext-opts) | ||
### .br() | ||
Line Break. Returns the [Text](#text) function. | ||
### .pageNumber() | ||
Print the page number the text fragment is rendered on. Returns the [Text](#text) function. | ||
**Example:** | ||
```js | ||
doc.text(function(text) { | ||
text('Page').pageNumber() | ||
}) | ||
``` | ||
## Table | ||
This table object is used to define its rows and its behaviour on page breaks. | ||
### .tr([opts,] definition) | ||
This method is used to define a table row. **Returns** a [Table Row](#table-row) object. | ||
**Arguments:** | ||
* **opts** - row options | ||
* **definition** - a function that contains the row definition | ||
**Options:** | ||
* **borderWidth** - | ||
* + [Text Options](#texttext-opts) | ||
### .beforeBreak([opts,] definition) | ||
Same as [.tr([opts,] definition)](#tropts-definition), but only rendered if the table is broken among two pages. This row is then rendered directly before the page break. | ||
```js | ||
table.beforeBreak(function() { | ||
this.td('Subtotal:', { colspan: 4, align: 'right' }) | ||
this.td(function() { | ||
this.text(function(text) { | ||
this.opts.align = 'right' | ||
this.opts.size = 11 | ||
text(function() { | ||
if (!this.table) return '' | ||
return items.subtotalUntil(this.table.row) | ||
}) | ||
}) | ||
}) | ||
}) | ||
``` | ||
### .afterBreak([opts,] definition) | ||
Same as [.tr([opts,] definition)](#tropts-definition), but only rendered if the table is broken among two pages. This row is then rendered directly after the header on the new page. | ||
**Example:** | ||
```js | ||
table.afterBreak(function() { | ||
this.td('Carryover:', { colspan: 4, align: 'right' }) | ||
this.td(function() { | ||
this.text(function(text) { | ||
this.opts.align = 'right' | ||
this.opts.size = 11 | ||
text(function() { | ||
if (!this.table) return '' | ||
return items.subtotalUntil(this.table.row) | ||
}) | ||
}) | ||
}) | ||
}) | ||
``` | ||
**Result:** | ||
![Result](https://raw.github.com/rkusa/pdfjs/gh-pages/images/table-pagebreak-example.png) | ||
## Table Row | ||
This table row object is used to define its cells. | ||
### .td(text[, opts]) | ||
This method is used to define a cell of the row. | ||
**Arguments:** | ||
* **text** - the text contained in the cell | ||
* **opts** - cell options | ||
**Options:** | ||
* **borderWidth** - | ||
* **colspan** - | ||
* + [Text Options](#texttext-opts) | ||
### .td([opts,] definition) | ||
This method is used to define a cell of the row. | ||
**Arguments:** | ||
* **opts** - cell options | ||
* **definition** - a function that contains the cell definition | ||
**Options:** | ||
* **borderWidth** - | ||
* **colspan** - | ||
* + [Text Options](#texttext-opts) | ||
## Font | ||
### new Font(path) | ||
### new Font(opts) | ||
**Options:** | ||
* **normal** - | ||
@@ -190,0 +329,0 @@ * **italic** - |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
292405
4377
330