forked from dk96/QuotationMaker
2118 lines
59 KiB
JavaScript
2118 lines
59 KiB
JavaScript
/**
|
|
* html2pdf.js v0.9.2
|
|
* Copyright (c) 2020 Erik Koopmans
|
|
* Released under the MIT License.
|
|
*/
|
|
(function (global, factory) {
|
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('jspdf'), require('html2canvas')) :
|
|
typeof define === 'function' && define.amd ? define(['jspdf', 'html2canvas'], factory) :
|
|
(global.html2pdf = factory(global.jsPDF,global.html2canvas));
|
|
}(this, (function (jsPDF,html2canvas) { 'use strict';
|
|
|
|
jsPDF = jsPDF && jsPDF.hasOwnProperty('default') ? jsPDF['default'] : jsPDF;
|
|
html2canvas = html2canvas && html2canvas.hasOwnProperty('default') ? html2canvas['default'] : html2canvas;
|
|
|
|
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
|
return typeof obj;
|
|
} : function (obj) {
|
|
return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var _extends = Object.assign || function (target) {
|
|
for (var i = 1; i < arguments.length; i++) {
|
|
var source = arguments[i];
|
|
|
|
for (var key in source) {
|
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
target[key] = source[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
return target;
|
|
};
|
|
|
|
// Determine the type of a variable/object.
|
|
var objType = function objType(obj) {
|
|
var type = typeof obj === 'undefined' ? 'undefined' : _typeof(obj);
|
|
if (type === 'undefined') return 'undefined';else if (type === 'string' || obj instanceof String) return 'string';else if (type === 'number' || obj instanceof Number) return 'number';else if (type === 'function' || obj instanceof Function) return 'function';else if (!!obj && obj.constructor === Array) return 'array';else if (obj && obj.nodeType === 1) return 'element';else if (type === 'object') return 'object';else return 'unknown';
|
|
};
|
|
|
|
// Create an HTML element with optional className, innerHTML, and style.
|
|
var createElement = function createElement(tagName, opt) {
|
|
var el = document.createElement(tagName);
|
|
if (opt.className) el.className = opt.className;
|
|
if (opt.innerHTML) {
|
|
el.innerHTML = opt.innerHTML;
|
|
var scripts = el.getElementsByTagName('script');
|
|
for (var i = scripts.length; i-- > 0; null) {
|
|
scripts[i].parentNode.removeChild(scripts[i]);
|
|
}
|
|
}
|
|
for (var key in opt.style) {
|
|
el.style[key] = opt.style[key];
|
|
}
|
|
return el;
|
|
};
|
|
|
|
// Deep-clone a node and preserve contents/properties.
|
|
var cloneNode = function cloneNode(node, javascriptEnabled) {
|
|
// Recursively clone the node.
|
|
var clone = node.nodeType === 3 ? document.createTextNode(node.nodeValue) : node.cloneNode(false);
|
|
for (var child = node.firstChild; child; child = child.nextSibling) {
|
|
if (javascriptEnabled === true || child.nodeType !== 1 || child.nodeName !== 'SCRIPT') {
|
|
clone.appendChild(cloneNode(child, javascriptEnabled));
|
|
}
|
|
}
|
|
|
|
if (node.nodeType === 1) {
|
|
// Preserve contents/properties of special nodes.
|
|
if (node.nodeName === 'CANVAS') {
|
|
clone.width = node.width;
|
|
clone.height = node.height;
|
|
clone.getContext('2d').drawImage(node, 0, 0);
|
|
} else if (node.nodeName === 'TEXTAREA' || node.nodeName === 'SELECT') {
|
|
clone.value = node.value;
|
|
}
|
|
|
|
// Preserve the node's scroll position when it loads.
|
|
clone.addEventListener('load', function () {
|
|
clone.scrollTop = node.scrollTop;
|
|
clone.scrollLeft = node.scrollLeft;
|
|
}, true);
|
|
}
|
|
|
|
// Return the cloned node.
|
|
return clone;
|
|
};
|
|
|
|
// Convert units from px using the conversion value 'k' from jsPDF.
|
|
var unitConvert = function unitConvert(obj, k) {
|
|
if (objType(obj) === 'number') {
|
|
return obj * 72 / 96 / k;
|
|
} else {
|
|
var newObj = {};
|
|
for (var key in obj) {
|
|
newObj[key] = obj[key] * 72 / 96 / k;
|
|
}
|
|
return newObj;
|
|
}
|
|
};
|
|
|
|
// Convert units to px using the conversion value 'k' from jsPDF.
|
|
var toPx = function toPx(val, k) {
|
|
return Math.floor(val * k / 72 * 96);
|
|
};
|
|
|
|
var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
|
|
function commonjsRequire () {
|
|
throw new Error('Dynamic requires are not currently supported by rollup-plugin-commonjs');
|
|
}
|
|
|
|
|
|
|
|
function createCommonjsModule(fn, module) {
|
|
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
|
}
|
|
|
|
var es6Promise = createCommonjsModule(function (module, exports) {
|
|
/*!
|
|
* @overview es6-promise - a tiny implementation of Promises/A+.
|
|
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
|
|
* @license Licensed under MIT license
|
|
* See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
|
|
* @version v4.2.5+7f2b526d
|
|
*/
|
|
|
|
(function (global, factory) {
|
|
module.exports = factory();
|
|
}(commonjsGlobal, (function () { function objectOrFunction(x) {
|
|
var type = typeof x;
|
|
return x !== null && (type === 'object' || type === 'function');
|
|
}
|
|
|
|
function isFunction(x) {
|
|
return typeof x === 'function';
|
|
}
|
|
|
|
|
|
|
|
var _isArray = void 0;
|
|
if (Array.isArray) {
|
|
_isArray = Array.isArray;
|
|
} else {
|
|
_isArray = function (x) {
|
|
return Object.prototype.toString.call(x) === '[object Array]';
|
|
};
|
|
}
|
|
|
|
var isArray = _isArray;
|
|
|
|
var len = 0;
|
|
var vertxNext = void 0;
|
|
var customSchedulerFn = void 0;
|
|
|
|
var asap = function asap(callback, arg) {
|
|
queue[len] = callback;
|
|
queue[len + 1] = arg;
|
|
len += 2;
|
|
if (len === 2) {
|
|
// If len is 2, that means that we need to schedule an async flush.
|
|
// If additional callbacks are queued before the queue is flushed, they
|
|
// will be processed by this flush that we are scheduling.
|
|
if (customSchedulerFn) {
|
|
customSchedulerFn(flush);
|
|
} else {
|
|
scheduleFlush();
|
|
}
|
|
}
|
|
};
|
|
|
|
function setScheduler(scheduleFn) {
|
|
customSchedulerFn = scheduleFn;
|
|
}
|
|
|
|
function setAsap(asapFn) {
|
|
asap = asapFn;
|
|
}
|
|
|
|
var browserWindow = typeof window !== 'undefined' ? window : undefined;
|
|
var browserGlobal = browserWindow || {};
|
|
var BrowserMutationObserver = browserGlobal.MutationObserver || browserGlobal.WebKitMutationObserver;
|
|
var isNode = typeof self === 'undefined' && typeof process !== 'undefined' && {}.toString.call(process) === '[object process]';
|
|
|
|
// test for web worker but not in IE10
|
|
var isWorker = typeof Uint8ClampedArray !== 'undefined' && typeof importScripts !== 'undefined' && typeof MessageChannel !== 'undefined';
|
|
|
|
// node
|
|
function useNextTick() {
|
|
// node version 0.10.x displays a deprecation warning when nextTick is used recursively
|
|
// see https://github.com/cujojs/when/issues/410 for details
|
|
return function () {
|
|
return process.nextTick(flush);
|
|
};
|
|
}
|
|
|
|
// vertx
|
|
function useVertxTimer() {
|
|
if (typeof vertxNext !== 'undefined') {
|
|
return function () {
|
|
vertxNext(flush);
|
|
};
|
|
}
|
|
|
|
return useSetTimeout();
|
|
}
|
|
|
|
function useMutationObserver() {
|
|
var iterations = 0;
|
|
var observer = new BrowserMutationObserver(flush);
|
|
var node = document.createTextNode('');
|
|
observer.observe(node, { characterData: true });
|
|
|
|
return function () {
|
|
node.data = iterations = ++iterations % 2;
|
|
};
|
|
}
|
|
|
|
// web worker
|
|
function useMessageChannel() {
|
|
var channel = new MessageChannel();
|
|
channel.port1.onmessage = flush;
|
|
return function () {
|
|
return channel.port2.postMessage(0);
|
|
};
|
|
}
|
|
|
|
function useSetTimeout() {
|
|
// Store setTimeout reference so es6-promise will be unaffected by
|
|
// other code modifying setTimeout (like sinon.useFakeTimers())
|
|
var globalSetTimeout = setTimeout;
|
|
return function () {
|
|
return globalSetTimeout(flush, 1);
|
|
};
|
|
}
|
|
|
|
var queue = new Array(1000);
|
|
function flush() {
|
|
for (var i = 0; i < len; i += 2) {
|
|
var callback = queue[i];
|
|
var arg = queue[i + 1];
|
|
|
|
callback(arg);
|
|
|
|
queue[i] = undefined;
|
|
queue[i + 1] = undefined;
|
|
}
|
|
|
|
len = 0;
|
|
}
|
|
|
|
function attemptVertx() {
|
|
try {
|
|
var vertx = Function('return this')().require('vertx');
|
|
vertxNext = vertx.runOnLoop || vertx.runOnContext;
|
|
return useVertxTimer();
|
|
} catch (e) {
|
|
return useSetTimeout();
|
|
}
|
|
}
|
|
|
|
var scheduleFlush = void 0;
|
|
// Decide what async method to use to triggering processing of queued callbacks:
|
|
if (isNode) {
|
|
scheduleFlush = useNextTick();
|
|
} else if (BrowserMutationObserver) {
|
|
scheduleFlush = useMutationObserver();
|
|
} else if (isWorker) {
|
|
scheduleFlush = useMessageChannel();
|
|
} else if (browserWindow === undefined && typeof commonjsRequire === 'function') {
|
|
scheduleFlush = attemptVertx();
|
|
} else {
|
|
scheduleFlush = useSetTimeout();
|
|
}
|
|
|
|
function then(onFulfillment, onRejection) {
|
|
var parent = this;
|
|
|
|
var child = new this.constructor(noop);
|
|
|
|
if (child[PROMISE_ID] === undefined) {
|
|
makePromise(child);
|
|
}
|
|
|
|
var _state = parent._state;
|
|
|
|
|
|
if (_state) {
|
|
var callback = arguments[_state - 1];
|
|
asap(function () {
|
|
return invokeCallback(_state, child, callback, parent._result);
|
|
});
|
|
} else {
|
|
subscribe(parent, child, onFulfillment, onRejection);
|
|
}
|
|
|
|
return child;
|
|
}
|
|
|
|
/**
|
|
`Promise.resolve` returns a promise that will become resolved with the
|
|
passed `value`. It is shorthand for the following:
|
|
|
|
```javascript
|
|
let promise = new Promise(function(resolve, reject){
|
|
resolve(1);
|
|
});
|
|
|
|
promise.then(function(value){
|
|
// value === 1
|
|
});
|
|
```
|
|
|
|
Instead of writing the above, your code now simply becomes the following:
|
|
|
|
```javascript
|
|
let promise = Promise.resolve(1);
|
|
|
|
promise.then(function(value){
|
|
// value === 1
|
|
});
|
|
```
|
|
|
|
@method resolve
|
|
@static
|
|
@param {Any} value value that the returned promise will be resolved with
|
|
Useful for tooling.
|
|
@return {Promise} a promise that will become fulfilled with the given
|
|
`value`
|
|
*/
|
|
function resolve$1(object) {
|
|
/*jshint validthis:true */
|
|
var Constructor = this;
|
|
|
|
if (object && typeof object === 'object' && object.constructor === Constructor) {
|
|
return object;
|
|
}
|
|
|
|
var promise = new Constructor(noop);
|
|
resolve(promise, object);
|
|
return promise;
|
|
}
|
|
|
|
var PROMISE_ID = Math.random().toString(36).substring(2);
|
|
|
|
function noop() {}
|
|
|
|
var PENDING = void 0;
|
|
var FULFILLED = 1;
|
|
var REJECTED = 2;
|
|
|
|
var TRY_CATCH_ERROR = { error: null };
|
|
|
|
function selfFulfillment() {
|
|
return new TypeError("You cannot resolve a promise with itself");
|
|
}
|
|
|
|
function cannotReturnOwn() {
|
|
return new TypeError('A promises callback cannot return that same promise.');
|
|
}
|
|
|
|
function getThen(promise) {
|
|
try {
|
|
return promise.then;
|
|
} catch (error) {
|
|
TRY_CATCH_ERROR.error = error;
|
|
return TRY_CATCH_ERROR;
|
|
}
|
|
}
|
|
|
|
function tryThen(then$$1, value, fulfillmentHandler, rejectionHandler) {
|
|
try {
|
|
then$$1.call(value, fulfillmentHandler, rejectionHandler);
|
|
} catch (e) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
function handleForeignThenable(promise, thenable, then$$1) {
|
|
asap(function (promise) {
|
|
var sealed = false;
|
|
var error = tryThen(then$$1, thenable, function (value) {
|
|
if (sealed) {
|
|
return;
|
|
}
|
|
sealed = true;
|
|
if (thenable !== value) {
|
|
resolve(promise, value);
|
|
} else {
|
|
fulfill(promise, value);
|
|
}
|
|
}, function (reason) {
|
|
if (sealed) {
|
|
return;
|
|
}
|
|
sealed = true;
|
|
|
|
reject(promise, reason);
|
|
}, 'Settle: ' + (promise._label || ' unknown promise'));
|
|
|
|
if (!sealed && error) {
|
|
sealed = true;
|
|
reject(promise, error);
|
|
}
|
|
}, promise);
|
|
}
|
|
|
|
function handleOwnThenable(promise, thenable) {
|
|
if (thenable._state === FULFILLED) {
|
|
fulfill(promise, thenable._result);
|
|
} else if (thenable._state === REJECTED) {
|
|
reject(promise, thenable._result);
|
|
} else {
|
|
subscribe(thenable, undefined, function (value) {
|
|
return resolve(promise, value);
|
|
}, function (reason) {
|
|
return reject(promise, reason);
|
|
});
|
|
}
|
|
}
|
|
|
|
function handleMaybeThenable(promise, maybeThenable, then$$1) {
|
|
if (maybeThenable.constructor === promise.constructor && then$$1 === then && maybeThenable.constructor.resolve === resolve$1) {
|
|
handleOwnThenable(promise, maybeThenable);
|
|
} else {
|
|
if (then$$1 === TRY_CATCH_ERROR) {
|
|
reject(promise, TRY_CATCH_ERROR.error);
|
|
TRY_CATCH_ERROR.error = null;
|
|
} else if (then$$1 === undefined) {
|
|
fulfill(promise, maybeThenable);
|
|
} else if (isFunction(then$$1)) {
|
|
handleForeignThenable(promise, maybeThenable, then$$1);
|
|
} else {
|
|
fulfill(promise, maybeThenable);
|
|
}
|
|
}
|
|
}
|
|
|
|
function resolve(promise, value) {
|
|
if (promise === value) {
|
|
reject(promise, selfFulfillment());
|
|
} else if (objectOrFunction(value)) {
|
|
handleMaybeThenable(promise, value, getThen(value));
|
|
} else {
|
|
fulfill(promise, value);
|
|
}
|
|
}
|
|
|
|
function publishRejection(promise) {
|
|
if (promise._onerror) {
|
|
promise._onerror(promise._result);
|
|
}
|
|
|
|
publish(promise);
|
|
}
|
|
|
|
function fulfill(promise, value) {
|
|
if (promise._state !== PENDING) {
|
|
return;
|
|
}
|
|
|
|
promise._result = value;
|
|
promise._state = FULFILLED;
|
|
|
|
if (promise._subscribers.length !== 0) {
|
|
asap(publish, promise);
|
|
}
|
|
}
|
|
|
|
function reject(promise, reason) {
|
|
if (promise._state !== PENDING) {
|
|
return;
|
|
}
|
|
promise._state = REJECTED;
|
|
promise._result = reason;
|
|
|
|
asap(publishRejection, promise);
|
|
}
|
|
|
|
function subscribe(parent, child, onFulfillment, onRejection) {
|
|
var _subscribers = parent._subscribers;
|
|
var length = _subscribers.length;
|
|
|
|
|
|
parent._onerror = null;
|
|
|
|
_subscribers[length] = child;
|
|
_subscribers[length + FULFILLED] = onFulfillment;
|
|
_subscribers[length + REJECTED] = onRejection;
|
|
|
|
if (length === 0 && parent._state) {
|
|
asap(publish, parent);
|
|
}
|
|
}
|
|
|
|
function publish(promise) {
|
|
var subscribers = promise._subscribers;
|
|
var settled = promise._state;
|
|
|
|
if (subscribers.length === 0) {
|
|
return;
|
|
}
|
|
|
|
var child = void 0,
|
|
callback = void 0,
|
|
detail = promise._result;
|
|
|
|
for (var i = 0; i < subscribers.length; i += 3) {
|
|
child = subscribers[i];
|
|
callback = subscribers[i + settled];
|
|
|
|
if (child) {
|
|
invokeCallback(settled, child, callback, detail);
|
|
} else {
|
|
callback(detail);
|
|
}
|
|
}
|
|
|
|
promise._subscribers.length = 0;
|
|
}
|
|
|
|
function tryCatch(callback, detail) {
|
|
try {
|
|
return callback(detail);
|
|
} catch (e) {
|
|
TRY_CATCH_ERROR.error = e;
|
|
return TRY_CATCH_ERROR;
|
|
}
|
|
}
|
|
|
|
function invokeCallback(settled, promise, callback, detail) {
|
|
var hasCallback = isFunction(callback),
|
|
value = void 0,
|
|
error = void 0,
|
|
succeeded = void 0,
|
|
failed = void 0;
|
|
|
|
if (hasCallback) {
|
|
value = tryCatch(callback, detail);
|
|
|
|
if (value === TRY_CATCH_ERROR) {
|
|
failed = true;
|
|
error = value.error;
|
|
value.error = null;
|
|
} else {
|
|
succeeded = true;
|
|
}
|
|
|
|
if (promise === value) {
|
|
reject(promise, cannotReturnOwn());
|
|
return;
|
|
}
|
|
} else {
|
|
value = detail;
|
|
succeeded = true;
|
|
}
|
|
|
|
if (promise._state !== PENDING) {
|
|
// noop
|
|
} else if (hasCallback && succeeded) {
|
|
resolve(promise, value);
|
|
} else if (failed) {
|
|
reject(promise, error);
|
|
} else if (settled === FULFILLED) {
|
|
fulfill(promise, value);
|
|
} else if (settled === REJECTED) {
|
|
reject(promise, value);
|
|
}
|
|
}
|
|
|
|
function initializePromise(promise, resolver) {
|
|
try {
|
|
resolver(function resolvePromise(value) {
|
|
resolve(promise, value);
|
|
}, function rejectPromise(reason) {
|
|
reject(promise, reason);
|
|
});
|
|
} catch (e) {
|
|
reject(promise, e);
|
|
}
|
|
}
|
|
|
|
var id = 0;
|
|
function nextId() {
|
|
return id++;
|
|
}
|
|
|
|
function makePromise(promise) {
|
|
promise[PROMISE_ID] = id++;
|
|
promise._state = undefined;
|
|
promise._result = undefined;
|
|
promise._subscribers = [];
|
|
}
|
|
|
|
function validationError() {
|
|
return new Error('Array Methods must be provided an Array');
|
|
}
|
|
|
|
var Enumerator = function () {
|
|
function Enumerator(Constructor, input) {
|
|
this._instanceConstructor = Constructor;
|
|
this.promise = new Constructor(noop);
|
|
|
|
if (!this.promise[PROMISE_ID]) {
|
|
makePromise(this.promise);
|
|
}
|
|
|
|
if (isArray(input)) {
|
|
this.length = input.length;
|
|
this._remaining = input.length;
|
|
|
|
this._result = new Array(this.length);
|
|
|
|
if (this.length === 0) {
|
|
fulfill(this.promise, this._result);
|
|
} else {
|
|
this.length = this.length || 0;
|
|
this._enumerate(input);
|
|
if (this._remaining === 0) {
|
|
fulfill(this.promise, this._result);
|
|
}
|
|
}
|
|
} else {
|
|
reject(this.promise, validationError());
|
|
}
|
|
}
|
|
|
|
Enumerator.prototype._enumerate = function _enumerate(input) {
|
|
for (var i = 0; this._state === PENDING && i < input.length; i++) {
|
|
this._eachEntry(input[i], i);
|
|
}
|
|
};
|
|
|
|
Enumerator.prototype._eachEntry = function _eachEntry(entry, i) {
|
|
var c = this._instanceConstructor;
|
|
var resolve$$1 = c.resolve;
|
|
|
|
|
|
if (resolve$$1 === resolve$1) {
|
|
var _then = getThen(entry);
|
|
|
|
if (_then === then && entry._state !== PENDING) {
|
|
this._settledAt(entry._state, i, entry._result);
|
|
} else if (typeof _then !== 'function') {
|
|
this._remaining--;
|
|
this._result[i] = entry;
|
|
} else if (c === Promise$1) {
|
|
var promise = new c(noop);
|
|
handleMaybeThenable(promise, entry, _then);
|
|
this._willSettleAt(promise, i);
|
|
} else {
|
|
this._willSettleAt(new c(function (resolve$$1) {
|
|
return resolve$$1(entry);
|
|
}), i);
|
|
}
|
|
} else {
|
|
this._willSettleAt(resolve$$1(entry), i);
|
|
}
|
|
};
|
|
|
|
Enumerator.prototype._settledAt = function _settledAt(state, i, value) {
|
|
var promise = this.promise;
|
|
|
|
|
|
if (promise._state === PENDING) {
|
|
this._remaining--;
|
|
|
|
if (state === REJECTED) {
|
|
reject(promise, value);
|
|
} else {
|
|
this._result[i] = value;
|
|
}
|
|
}
|
|
|
|
if (this._remaining === 0) {
|
|
fulfill(promise, this._result);
|
|
}
|
|
};
|
|
|
|
Enumerator.prototype._willSettleAt = function _willSettleAt(promise, i) {
|
|
var enumerator = this;
|
|
|
|
subscribe(promise, undefined, function (value) {
|
|
return enumerator._settledAt(FULFILLED, i, value);
|
|
}, function (reason) {
|
|
return enumerator._settledAt(REJECTED, i, reason);
|
|
});
|
|
};
|
|
|
|
return Enumerator;
|
|
}();
|
|
|
|
/**
|
|
`Promise.all` accepts an array of promises, and returns a new promise which
|
|
is fulfilled with an array of fulfillment values for the passed promises, or
|
|
rejected with the reason of the first passed promise to be rejected. It casts all
|
|
elements of the passed iterable to promises as it runs this algorithm.
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
let promise1 = resolve(1);
|
|
let promise2 = resolve(2);
|
|
let promise3 = resolve(3);
|
|
let promises = [ promise1, promise2, promise3 ];
|
|
|
|
Promise.all(promises).then(function(array){
|
|
// The array here would be [ 1, 2, 3 ];
|
|
});
|
|
```
|
|
|
|
If any of the `promises` given to `all` are rejected, the first promise
|
|
that is rejected will be given as an argument to the returned promises's
|
|
rejection handler. For example:
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
let promise1 = resolve(1);
|
|
let promise2 = reject(new Error("2"));
|
|
let promise3 = reject(new Error("3"));
|
|
let promises = [ promise1, promise2, promise3 ];
|
|
|
|
Promise.all(promises).then(function(array){
|
|
// Code here never runs because there are rejected promises!
|
|
}, function(error) {
|
|
// error.message === "2"
|
|
});
|
|
```
|
|
|
|
@method all
|
|
@static
|
|
@param {Array} entries array of promises
|
|
@param {String} label optional string for labeling the promise.
|
|
Useful for tooling.
|
|
@return {Promise} promise that is fulfilled when all `promises` have been
|
|
fulfilled, or rejected if any of them become rejected.
|
|
@static
|
|
*/
|
|
function all(entries) {
|
|
return new Enumerator(this, entries).promise;
|
|
}
|
|
|
|
/**
|
|
`Promise.race` returns a new promise which is settled in the same way as the
|
|
first passed promise to settle.
|
|
|
|
Example:
|
|
|
|
```javascript
|
|
let promise1 = new Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve('promise 1');
|
|
}, 200);
|
|
});
|
|
|
|
let promise2 = new Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve('promise 2');
|
|
}, 100);
|
|
});
|
|
|
|
Promise.race([promise1, promise2]).then(function(result){
|
|
// result === 'promise 2' because it was resolved before promise1
|
|
// was resolved.
|
|
});
|
|
```
|
|
|
|
`Promise.race` is deterministic in that only the state of the first
|
|
settled promise matters. For example, even if other promises given to the
|
|
`promises` array argument are resolved, but the first settled promise has
|
|
become rejected before the other promises became fulfilled, the returned
|
|
promise will become rejected:
|
|
|
|
```javascript
|
|
let promise1 = new Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
resolve('promise 1');
|
|
}, 200);
|
|
});
|
|
|
|
let promise2 = new Promise(function(resolve, reject){
|
|
setTimeout(function(){
|
|
reject(new Error('promise 2'));
|
|
}, 100);
|
|
});
|
|
|
|
Promise.race([promise1, promise2]).then(function(result){
|
|
// Code here never runs
|
|
}, function(reason){
|
|
// reason.message === 'promise 2' because promise 2 became rejected before
|
|
// promise 1 became fulfilled
|
|
});
|
|
```
|
|
|
|
An example real-world use case is implementing timeouts:
|
|
|
|
```javascript
|
|
Promise.race([ajax('foo.json'), timeout(5000)])
|
|
```
|
|
|
|
@method race
|
|
@static
|
|
@param {Array} promises array of promises to observe
|
|
Useful for tooling.
|
|
@return {Promise} a promise which settles in the same way as the first passed
|
|
promise to settle.
|
|
*/
|
|
function race(entries) {
|
|
/*jshint validthis:true */
|
|
var Constructor = this;
|
|
|
|
if (!isArray(entries)) {
|
|
return new Constructor(function (_, reject) {
|
|
return reject(new TypeError('You must pass an array to race.'));
|
|
});
|
|
} else {
|
|
return new Constructor(function (resolve, reject) {
|
|
var length = entries.length;
|
|
for (var i = 0; i < length; i++) {
|
|
Constructor.resolve(entries[i]).then(resolve, reject);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
/**
|
|
`Promise.reject` returns a promise rejected with the passed `reason`.
|
|
It is shorthand for the following:
|
|
|
|
```javascript
|
|
let promise = new Promise(function(resolve, reject){
|
|
reject(new Error('WHOOPS'));
|
|
});
|
|
|
|
promise.then(function(value){
|
|
// Code here doesn't run because the promise is rejected!
|
|
}, function(reason){
|
|
// reason.message === 'WHOOPS'
|
|
});
|
|
```
|
|
|
|
Instead of writing the above, your code now simply becomes the following:
|
|
|
|
```javascript
|
|
let promise = Promise.reject(new Error('WHOOPS'));
|
|
|
|
promise.then(function(value){
|
|
// Code here doesn't run because the promise is rejected!
|
|
}, function(reason){
|
|
// reason.message === 'WHOOPS'
|
|
});
|
|
```
|
|
|
|
@method reject
|
|
@static
|
|
@param {Any} reason value that the returned promise will be rejected with.
|
|
Useful for tooling.
|
|
@return {Promise} a promise rejected with the given `reason`.
|
|
*/
|
|
function reject$1(reason) {
|
|
/*jshint validthis:true */
|
|
var Constructor = this;
|
|
var promise = new Constructor(noop);
|
|
reject(promise, reason);
|
|
return promise;
|
|
}
|
|
|
|
function needsResolver() {
|
|
throw new TypeError('You must pass a resolver function as the first argument to the promise constructor');
|
|
}
|
|
|
|
function needsNew() {
|
|
throw new TypeError("Failed to construct 'Promise': Please use the 'new' operator, this object constructor cannot be called as a function.");
|
|
}
|
|
|
|
/**
|
|
Promise objects represent the eventual result of an asynchronous operation. The
|
|
primary way of interacting with a promise is through its `then` method, which
|
|
registers callbacks to receive either a promise's eventual value or the reason
|
|
why the promise cannot be fulfilled.
|
|
|
|
Terminology
|
|
-----------
|
|
|
|
- `promise` is an object or function with a `then` method whose behavior conforms to this specification.
|
|
- `thenable` is an object or function that defines a `then` method.
|
|
- `value` is any legal JavaScript value (including undefined, a thenable, or a promise).
|
|
- `exception` is a value that is thrown using the throw statement.
|
|
- `reason` is a value that indicates why a promise was rejected.
|
|
- `settled` the final resting state of a promise, fulfilled or rejected.
|
|
|
|
A promise can be in one of three states: pending, fulfilled, or rejected.
|
|
|
|
Promises that are fulfilled have a fulfillment value and are in the fulfilled
|
|
state. Promises that are rejected have a rejection reason and are in the
|
|
rejected state. A fulfillment value is never a thenable.
|
|
|
|
Promises can also be said to *resolve* a value. If this value is also a
|
|
promise, then the original promise's settled state will match the value's
|
|
settled state. So a promise that *resolves* a promise that rejects will
|
|
itself reject, and a promise that *resolves* a promise that fulfills will
|
|
itself fulfill.
|
|
|
|
|
|
Basic Usage:
|
|
------------
|
|
|
|
```js
|
|
let promise = new Promise(function(resolve, reject) {
|
|
// on success
|
|
resolve(value);
|
|
|
|
// on failure
|
|
reject(reason);
|
|
});
|
|
|
|
promise.then(function(value) {
|
|
// on fulfillment
|
|
}, function(reason) {
|
|
// on rejection
|
|
});
|
|
```
|
|
|
|
Advanced Usage:
|
|
---------------
|
|
|
|
Promises shine when abstracting away asynchronous interactions such as
|
|
`XMLHttpRequest`s.
|
|
|
|
```js
|
|
function getJSON(url) {
|
|
return new Promise(function(resolve, reject){
|
|
let xhr = new XMLHttpRequest();
|
|
|
|
xhr.open('GET', url);
|
|
xhr.onreadystatechange = handler;
|
|
xhr.responseType = 'json';
|
|
xhr.setRequestHeader('Accept', 'application/json');
|
|
xhr.send();
|
|
|
|
function handler() {
|
|
if (this.readyState === this.DONE) {
|
|
if (this.status === 200) {
|
|
resolve(this.response);
|
|
} else {
|
|
reject(new Error('getJSON: `' + url + '` failed with status: [' + this.status + ']'));
|
|
}
|
|
}
|
|
};
|
|
});
|
|
}
|
|
|
|
getJSON('/posts.json').then(function(json) {
|
|
// on fulfillment
|
|
}, function(reason) {
|
|
// on rejection
|
|
});
|
|
```
|
|
|
|
Unlike callbacks, promises are great composable primitives.
|
|
|
|
```js
|
|
Promise.all([
|
|
getJSON('/posts'),
|
|
getJSON('/comments')
|
|
]).then(function(values){
|
|
values[0] // => postsJSON
|
|
values[1] // => commentsJSON
|
|
|
|
return values;
|
|
});
|
|
```
|
|
|
|
@class Promise
|
|
@param {Function} resolver
|
|
Useful for tooling.
|
|
@constructor
|
|
*/
|
|
|
|
var Promise$1 = function () {
|
|
function Promise(resolver) {
|
|
this[PROMISE_ID] = nextId();
|
|
this._result = this._state = undefined;
|
|
this._subscribers = [];
|
|
|
|
if (noop !== resolver) {
|
|
typeof resolver !== 'function' && needsResolver();
|
|
this instanceof Promise ? initializePromise(this, resolver) : needsNew();
|
|
}
|
|
}
|
|
|
|
/**
|
|
The primary way of interacting with a promise is through its `then` method,
|
|
which registers callbacks to receive either a promise's eventual value or the
|
|
reason why the promise cannot be fulfilled.
|
|
```js
|
|
findUser().then(function(user){
|
|
// user is available
|
|
}, function(reason){
|
|
// user is unavailable, and you are given the reason why
|
|
});
|
|
```
|
|
Chaining
|
|
--------
|
|
The return value of `then` is itself a promise. This second, 'downstream'
|
|
promise is resolved with the return value of the first promise's fulfillment
|
|
or rejection handler, or rejected if the handler throws an exception.
|
|
```js
|
|
findUser().then(function (user) {
|
|
return user.name;
|
|
}, function (reason) {
|
|
return 'default name';
|
|
}).then(function (userName) {
|
|
// If `findUser` fulfilled, `userName` will be the user's name, otherwise it
|
|
// will be `'default name'`
|
|
});
|
|
findUser().then(function (user) {
|
|
throw new Error('Found user, but still unhappy');
|
|
}, function (reason) {
|
|
throw new Error('`findUser` rejected and we're unhappy');
|
|
}).then(function (value) {
|
|
// never reached
|
|
}, function (reason) {
|
|
// if `findUser` fulfilled, `reason` will be 'Found user, but still unhappy'.
|
|
// If `findUser` rejected, `reason` will be '`findUser` rejected and we're unhappy'.
|
|
});
|
|
```
|
|
If the downstream promise does not specify a rejection handler, rejection reasons will be propagated further downstream.
|
|
```js
|
|
findUser().then(function (user) {
|
|
throw new PedagogicalException('Upstream error');
|
|
}).then(function (value) {
|
|
// never reached
|
|
}).then(function (value) {
|
|
// never reached
|
|
}, function (reason) {
|
|
// The `PedgagocialException` is propagated all the way down to here
|
|
});
|
|
```
|
|
Assimilation
|
|
------------
|
|
Sometimes the value you want to propagate to a downstream promise can only be
|
|
retrieved asynchronously. This can be achieved by returning a promise in the
|
|
fulfillment or rejection handler. The downstream promise will then be pending
|
|
until the returned promise is settled. This is called *assimilation*.
|
|
```js
|
|
findUser().then(function (user) {
|
|
return findCommentsByAuthor(user);
|
|
}).then(function (comments) {
|
|
// The user's comments are now available
|
|
});
|
|
```
|
|
If the assimliated promise rejects, then the downstream promise will also reject.
|
|
```js
|
|
findUser().then(function (user) {
|
|
return findCommentsByAuthor(user);
|
|
}).then(function (comments) {
|
|
// If `findCommentsByAuthor` fulfills, we'll have the value here
|
|
}, function (reason) {
|
|
// If `findCommentsByAuthor` rejects, we'll have the reason here
|
|
});
|
|
```
|
|
Simple Example
|
|
--------------
|
|
Synchronous Example
|
|
```javascript
|
|
let result;
|
|
try {
|
|
result = findResult();
|
|
// success
|
|
} catch(reason) {
|
|
// failure
|
|
}
|
|
```
|
|
Errback Example
|
|
```js
|
|
findResult(function(result, err){
|
|
if (err) {
|
|
// failure
|
|
} else {
|
|
// success
|
|
}
|
|
});
|
|
```
|
|
Promise Example;
|
|
```javascript
|
|
findResult().then(function(result){
|
|
// success
|
|
}, function(reason){
|
|
// failure
|
|
});
|
|
```
|
|
Advanced Example
|
|
--------------
|
|
Synchronous Example
|
|
```javascript
|
|
let author, books;
|
|
try {
|
|
author = findAuthor();
|
|
books = findBooksByAuthor(author);
|
|
// success
|
|
} catch(reason) {
|
|
// failure
|
|
}
|
|
```
|
|
Errback Example
|
|
```js
|
|
function foundBooks(books) {
|
|
}
|
|
function failure(reason) {
|
|
}
|
|
findAuthor(function(author, err){
|
|
if (err) {
|
|
failure(err);
|
|
// failure
|
|
} else {
|
|
try {
|
|
findBoooksByAuthor(author, function(books, err) {
|
|
if (err) {
|
|
failure(err);
|
|
} else {
|
|
try {
|
|
foundBooks(books);
|
|
} catch(reason) {
|
|
failure(reason);
|
|
}
|
|
}
|
|
});
|
|
} catch(error) {
|
|
failure(err);
|
|
}
|
|
// success
|
|
}
|
|
});
|
|
```
|
|
Promise Example;
|
|
```javascript
|
|
findAuthor().
|
|
then(findBooksByAuthor).
|
|
then(function(books){
|
|
// found books
|
|
}).catch(function(reason){
|
|
// something went wrong
|
|
});
|
|
```
|
|
@method then
|
|
@param {Function} onFulfilled
|
|
@param {Function} onRejected
|
|
Useful for tooling.
|
|
@return {Promise}
|
|
*/
|
|
|
|
/**
|
|
`catch` is simply sugar for `then(undefined, onRejection)` which makes it the same
|
|
as the catch block of a try/catch statement.
|
|
```js
|
|
function findAuthor(){
|
|
throw new Error('couldn't find that author');
|
|
}
|
|
// synchronous
|
|
try {
|
|
findAuthor();
|
|
} catch(reason) {
|
|
// something went wrong
|
|
}
|
|
// async with promises
|
|
findAuthor().catch(function(reason){
|
|
// something went wrong
|
|
});
|
|
```
|
|
@method catch
|
|
@param {Function} onRejection
|
|
Useful for tooling.
|
|
@return {Promise}
|
|
*/
|
|
|
|
|
|
Promise.prototype.catch = function _catch(onRejection) {
|
|
return this.then(null, onRejection);
|
|
};
|
|
|
|
/**
|
|
`finally` will be invoked regardless of the promise's fate just as native
|
|
try/catch/finally behaves
|
|
|
|
Synchronous example:
|
|
|
|
```js
|
|
findAuthor() {
|
|
if (Math.random() > 0.5) {
|
|
throw new Error();
|
|
}
|
|
return new Author();
|
|
}
|
|
|
|
try {
|
|
return findAuthor(); // succeed or fail
|
|
} catch(error) {
|
|
return findOtherAuther();
|
|
} finally {
|
|
// always runs
|
|
// doesn't affect the return value
|
|
}
|
|
```
|
|
|
|
Asynchronous example:
|
|
|
|
```js
|
|
findAuthor().catch(function(reason){
|
|
return findOtherAuther();
|
|
}).finally(function(){
|
|
// author was either found, or not
|
|
});
|
|
```
|
|
|
|
@method finally
|
|
@param {Function} callback
|
|
@return {Promise}
|
|
*/
|
|
|
|
|
|
Promise.prototype.finally = function _finally(callback) {
|
|
var promise = this;
|
|
var constructor = promise.constructor;
|
|
|
|
if (isFunction(callback)) {
|
|
return promise.then(function (value) {
|
|
return constructor.resolve(callback()).then(function () {
|
|
return value;
|
|
});
|
|
}, function (reason) {
|
|
return constructor.resolve(callback()).then(function () {
|
|
throw reason;
|
|
});
|
|
});
|
|
}
|
|
|
|
return promise.then(callback, callback);
|
|
};
|
|
|
|
return Promise;
|
|
}();
|
|
|
|
Promise$1.prototype.then = then;
|
|
Promise$1.all = all;
|
|
Promise$1.race = race;
|
|
Promise$1.resolve = resolve$1;
|
|
Promise$1.reject = reject$1;
|
|
Promise$1._setScheduler = setScheduler;
|
|
Promise$1._setAsap = setAsap;
|
|
Promise$1._asap = asap;
|
|
|
|
/*global self*/
|
|
function polyfill() {
|
|
var local = void 0;
|
|
|
|
if (typeof commonjsGlobal !== 'undefined') {
|
|
local = commonjsGlobal;
|
|
} else if (typeof self !== 'undefined') {
|
|
local = self;
|
|
} else {
|
|
try {
|
|
local = Function('return this')();
|
|
} catch (e) {
|
|
throw new Error('polyfill failed because global object is unavailable in this environment');
|
|
}
|
|
}
|
|
|
|
var P = local.Promise;
|
|
|
|
if (P) {
|
|
var promiseToString = null;
|
|
try {
|
|
promiseToString = Object.prototype.toString.call(P.resolve());
|
|
} catch (e) {
|
|
// silently ignored
|
|
}
|
|
|
|
if (promiseToString === '[object Promise]' && !P.cast) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
local.Promise = Promise$1;
|
|
}
|
|
|
|
// Strange compat..
|
|
Promise$1.polyfill = polyfill;
|
|
Promise$1.Promise = Promise$1;
|
|
|
|
return Promise$1;
|
|
|
|
})));
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
var Promise$1 = es6Promise.Promise;
|
|
|
|
/* ----- CONSTRUCTOR ----- */
|
|
|
|
var Worker = function Worker(opt) {
|
|
// Create the root parent for the proto chain, and the starting Worker.
|
|
var root = _extends(Worker.convert(Promise$1.resolve()), JSON.parse(JSON.stringify(Worker.template)));
|
|
var self = Worker.convert(Promise$1.resolve(), root);
|
|
|
|
// Set progress, optional settings, and return.
|
|
self = self.setProgress(1, Worker, 1, [Worker]);
|
|
self = self.set(opt);
|
|
return self;
|
|
};
|
|
|
|
// Boilerplate for subclassing Promise.
|
|
Worker.prototype = Object.create(Promise$1.prototype);
|
|
Worker.prototype.constructor = Worker;
|
|
|
|
// Converts/casts promises into Workers.
|
|
Worker.convert = function convert(promise, inherit) {
|
|
// Uses prototypal inheritance to receive changes made to ancestors' properties.
|
|
promise.__proto__ = inherit || Worker.prototype;
|
|
return promise;
|
|
};
|
|
|
|
Worker.template = {
|
|
prop: {
|
|
src: null,
|
|
container: null,
|
|
overlay: null,
|
|
canvas: null,
|
|
img: null,
|
|
pdf: null,
|
|
pageSize: null
|
|
},
|
|
progress: {
|
|
val: 0,
|
|
state: null,
|
|
n: 0,
|
|
stack: []
|
|
},
|
|
opt: {
|
|
filename: 'file.pdf',
|
|
margin: [0, 0, 0, 0],
|
|
image: { type: 'jpeg', quality: 0.95 },
|
|
enableLinks: true,
|
|
html2canvas: {},
|
|
jsPDF: {}
|
|
}
|
|
};
|
|
|
|
/* ----- FROM / TO ----- */
|
|
|
|
Worker.prototype.from = function from(src, type) {
|
|
function getType(src) {
|
|
switch (objType(src)) {
|
|
case 'string':
|
|
return 'string';
|
|
case 'element':
|
|
return src.nodeName.toLowerCase === 'canvas' ? 'canvas' : 'element';
|
|
default:
|
|
return 'unknown';
|
|
}
|
|
}
|
|
|
|
return this.then(function from_main() {
|
|
type = type || getType(src);
|
|
switch (type) {
|
|
case 'string':
|
|
return this.set({ src: createElement('div', { innerHTML: src }) });
|
|
case 'element':
|
|
return this.set({ src: src });
|
|
case 'canvas':
|
|
return this.set({ canvas: src });
|
|
case 'img':
|
|
return this.set({ img: src });
|
|
default:
|
|
return this.error('Unknown source type.');
|
|
}
|
|
});
|
|
};
|
|
|
|
Worker.prototype.to = function to(target) {
|
|
// Route the 'to' request to the appropriate method.
|
|
switch (target) {
|
|
case 'container':
|
|
return this.toContainer();
|
|
case 'canvas':
|
|
return this.toCanvas();
|
|
case 'img':
|
|
return this.toImg();
|
|
case 'pdf':
|
|
return this.toPdf();
|
|
default:
|
|
return this.error('Invalid target.');
|
|
}
|
|
};
|
|
|
|
Worker.prototype.toContainer = function toContainer() {
|
|
// Set up function prerequisites.
|
|
var prereqs = [function checkSrc() {
|
|
return this.prop.src || this.error('Cannot duplicate - no source HTML.');
|
|
}, function checkPageSize() {
|
|
return this.prop.pageSize || this.setPageSize();
|
|
}];
|
|
|
|
return this.thenList(prereqs).then(function toContainer_main() {
|
|
// Define the CSS styles for the container and its overlay parent.
|
|
var overlayCSS = {
|
|
position: 'fixed', overflow: 'hidden', zIndex: 1000,
|
|
left: 0, right: 0, bottom: 0, top: 0,
|
|
backgroundColor: 'rgba(0,0,0,0.8)'
|
|
};
|
|
var containerCSS = {
|
|
position: 'absolute', width: this.prop.pageSize.inner.width + this.prop.pageSize.unit,
|
|
left: 0, right: 0, top: 0, height: 'auto', margin: 'auto',
|
|
backgroundColor: 'white'
|
|
};
|
|
|
|
// Set the overlay to hidden (could be changed in the future to provide a print preview).
|
|
overlayCSS.opacity = 0;
|
|
|
|
// Create and attach the elements.
|
|
var source = cloneNode(this.prop.src, this.opt.html2canvas.javascriptEnabled);
|
|
this.prop.overlay = createElement('div', { className: 'html2pdf__overlay', style: overlayCSS });
|
|
this.prop.container = createElement('div', { className: 'html2pdf__container', style: containerCSS });
|
|
this.prop.container.appendChild(source);
|
|
this.prop.overlay.appendChild(this.prop.container);
|
|
document.body.appendChild(this.prop.overlay);
|
|
});
|
|
};
|
|
|
|
Worker.prototype.toCanvas = function toCanvas() {
|
|
// Set up function prerequisites.
|
|
var prereqs = [function checkContainer() {
|
|
return document.body.contains(this.prop.container) || this.toContainer();
|
|
}];
|
|
|
|
// Fulfill prereqs then create the canvas.
|
|
return this.thenList(prereqs).then(function toCanvas_main() {
|
|
// Handle old-fashioned 'onrendered' argument.
|
|
var options = _extends({}, this.opt.html2canvas);
|
|
delete options.onrendered;
|
|
|
|
return html2canvas(this.prop.container, options);
|
|
}).then(function toCanvas_post(canvas) {
|
|
// Handle old-fashioned 'onrendered' argument.
|
|
var onRendered = this.opt.html2canvas.onrendered || function () {};
|
|
onRendered(canvas);
|
|
|
|
this.prop.canvas = canvas;
|
|
document.body.removeChild(this.prop.overlay);
|
|
});
|
|
};
|
|
|
|
Worker.prototype.toImg = function toImg() {
|
|
// Set up function prerequisites.
|
|
var prereqs = [function checkCanvas() {
|
|
return this.prop.canvas || this.toCanvas();
|
|
}];
|
|
|
|
// Fulfill prereqs then create the image.
|
|
return this.thenList(prereqs).then(function toImg_main() {
|
|
var imgData = this.prop.canvas.toDataURL('image/' + this.opt.image.type, this.opt.image.quality);
|
|
this.prop.img = document.createElement('img');
|
|
this.prop.img.src = imgData;
|
|
});
|
|
};
|
|
|
|
Worker.prototype.toPdf = function toPdf() {
|
|
// Set up function prerequisites.
|
|
var prereqs = [function checkCanvas() {
|
|
return this.prop.canvas || this.toCanvas();
|
|
}];
|
|
|
|
// Fulfill prereqs then create the image.
|
|
return this.thenList(prereqs).then(function toPdf_main() {
|
|
// Create local copies of frequently used properties.
|
|
var canvas = this.prop.canvas;
|
|
var opt = this.opt;
|
|
|
|
// Calculate the number of pages.
|
|
var pxFullHeight = canvas.height;
|
|
var pxPageHeight = Math.floor(canvas.width * this.prop.pageSize.inner.ratio);
|
|
var nPages = Math.ceil(pxFullHeight / pxPageHeight);
|
|
|
|
// Define pageHeight separately so it can be trimmed on the final page.
|
|
var pageHeight = this.prop.pageSize.inner.height;
|
|
|
|
// Create a one-page canvas to split up the full image.
|
|
var pageCanvas = document.createElement('canvas');
|
|
var pageCtx = pageCanvas.getContext('2d');
|
|
pageCanvas.width = canvas.width;
|
|
pageCanvas.height = pxPageHeight;
|
|
|
|
// Initialize the PDF.
|
|
this.prop.pdf = this.prop.pdf || new jsPDF(opt.jsPDF);
|
|
|
|
for (var page = 0; page < nPages; page++) {
|
|
// Trim the final page to reduce file size.
|
|
if (page === nPages - 1 && pxFullHeight % pxPageHeight !== 0) {
|
|
pageCanvas.height = pxFullHeight % pxPageHeight;
|
|
pageHeight = pageCanvas.height * this.prop.pageSize.inner.width / pageCanvas.width;
|
|
}
|
|
|
|
// Display the page.
|
|
var w = pageCanvas.width;
|
|
var h = pageCanvas.height;
|
|
pageCtx.fillStyle = 'white';
|
|
pageCtx.fillRect(0, 0, w, h);
|
|
pageCtx.drawImage(canvas, 0, page * pxPageHeight, w, h, 0, 0, w, h);
|
|
|
|
// Add the page to the PDF.
|
|
if (page) this.prop.pdf.addPage();
|
|
var imgData = pageCanvas.toDataURL('image/' + opt.image.type, opt.image.quality);
|
|
this.prop.pdf.addImage(imgData, opt.image.type, opt.margin[1], opt.margin[0], this.prop.pageSize.inner.width, pageHeight);
|
|
}
|
|
});
|
|
};
|
|
|
|
/* ----- OUTPUT / SAVE ----- */
|
|
|
|
Worker.prototype.output = function output(type, options, src) {
|
|
// Redirect requests to the correct function (outputPdf / outputImg).
|
|
src = src || 'pdf';
|
|
if (src.toLowerCase() === 'img' || src.toLowerCase() === 'image') {
|
|
return this.outputImg(type, options);
|
|
} else {
|
|
return this.outputPdf(type, options);
|
|
}
|
|
};
|
|
|
|
Worker.prototype.outputPdf = function outputPdf(type, options) {
|
|
// Set up function prerequisites.
|
|
var prereqs = [function checkPdf() {
|
|
return this.prop.pdf || this.toPdf();
|
|
}];
|
|
|
|
// Fulfill prereqs then perform the appropriate output.
|
|
return this.thenList(prereqs).then(function outputPdf_main() {
|
|
/* Currently implemented output types:
|
|
* https://rawgit.com/MrRio/jsPDF/master/docs/jspdf.js.html#line992
|
|
* save(options), arraybuffer, blob, bloburi/bloburl,
|
|
* datauristring/dataurlstring, dataurlnewwindow, datauri/dataurl
|
|
*/
|
|
return this.prop.pdf.output(type, options);
|
|
});
|
|
};
|
|
|
|
Worker.prototype.outputImg = function outputImg(type, options) {
|
|
// Set up function prerequisites.
|
|
var prereqs = [function checkImg() {
|
|
return this.prop.img || this.toImg();
|
|
}];
|
|
|
|
// Fulfill prereqs then perform the appropriate output.
|
|
return this.thenList(prereqs).then(function outputImg_main() {
|
|
switch (type) {
|
|
case undefined:
|
|
case 'img':
|
|
return this.prop.img;
|
|
case 'datauristring':
|
|
case 'dataurlstring':
|
|
return this.prop.img.src;
|
|
case 'datauri':
|
|
case 'dataurl':
|
|
return document.location.href = this.prop.img.src;
|
|
default:
|
|
throw 'Image output type "' + type + '" is not supported.';
|
|
}
|
|
});
|
|
};
|
|
|
|
Worker.prototype.save = function save(filename) {
|
|
// Set up function prerequisites.
|
|
var prereqs = [function checkPdf() {
|
|
return this.prop.pdf || this.toPdf();
|
|
}];
|
|
|
|
// Fulfill prereqs, update the filename (if provided), and save the PDF.
|
|
return this.thenList(prereqs).set(filename ? { filename: filename } : null).then(function save_main() {
|
|
this.prop.pdf.save(this.opt.filename);
|
|
});
|
|
};
|
|
|
|
/* ----- SET / GET ----- */
|
|
|
|
Worker.prototype.set = function set$$1(opt) {
|
|
// TODO: Implement ordered pairs?
|
|
|
|
// Silently ignore invalid or empty input.
|
|
if (objType(opt) !== 'object') {
|
|
return this;
|
|
}
|
|
|
|
// Build an array of setter functions to queue.
|
|
var fns = Object.keys(opt || {}).map(function (key) {
|
|
if (key in Worker.template.prop) {
|
|
// Set pre-defined properties.
|
|
return function set_prop() {
|
|
this.prop[key] = opt[key];
|
|
};
|
|
} else {
|
|
switch (key) {
|
|
case 'margin':
|
|
return this.setMargin.bind(this, opt.margin);
|
|
case 'jsPDF':
|
|
return function set_jsPDF() {
|
|
this.opt.jsPDF = opt.jsPDF;return this.setPageSize();
|
|
};
|
|
case 'pageSize':
|
|
return this.setPageSize.bind(this, opt.pageSize);
|
|
default:
|
|
// Set any other properties in opt.
|
|
return function set_opt() {
|
|
this.opt[key] = opt[key];
|
|
};
|
|
}
|
|
}
|
|
}, this);
|
|
|
|
// Set properties within the promise chain.
|
|
return this.then(function set_main() {
|
|
return this.thenList(fns);
|
|
});
|
|
};
|
|
|
|
Worker.prototype.get = function get$$1(key, cbk) {
|
|
return this.then(function get_main() {
|
|
// Fetch the requested property, either as a predefined prop or in opt.
|
|
var val = key in Worker.template.prop ? this.prop[key] : this.opt[key];
|
|
return cbk ? cbk(val) : val;
|
|
});
|
|
};
|
|
|
|
Worker.prototype.setMargin = function setMargin(margin) {
|
|
return this.then(function setMargin_main() {
|
|
// Parse the margin property: [top, left, bottom, right].
|
|
switch (objType(margin)) {
|
|
case 'number':
|
|
margin = [margin, margin, margin, margin];
|
|
case 'array':
|
|
if (margin.length === 2) {
|
|
margin = [margin[0], margin[1], margin[0], margin[1]];
|
|
}
|
|
if (margin.length === 4) {
|
|
break;
|
|
}
|
|
default:
|
|
return this.error('Invalid margin array.');
|
|
}
|
|
|
|
// Set the margin property, then update pageSize.
|
|
this.opt.margin = margin;
|
|
}).then(this.setPageSize);
|
|
};
|
|
|
|
Worker.prototype.setPageSize = function setPageSize(pageSize) {
|
|
return this.then(function setPageSize_main() {
|
|
// Retrieve page-size based on jsPDF settings, if not explicitly provided.
|
|
pageSize = pageSize || jsPDF.getPageSize(this.opt.jsPDF);
|
|
|
|
// Add 'inner' field if not present.
|
|
if (!pageSize.hasOwnProperty('inner')) {
|
|
pageSize.inner = {
|
|
width: pageSize.width - this.opt.margin[1] - this.opt.margin[3],
|
|
height: pageSize.height - this.opt.margin[0] - this.opt.margin[2]
|
|
};
|
|
pageSize.inner.px = {
|
|
width: toPx(pageSize.inner.width, pageSize.k),
|
|
height: toPx(pageSize.inner.height, pageSize.k)
|
|
};
|
|
pageSize.inner.ratio = pageSize.inner.height / pageSize.inner.width;
|
|
}
|
|
|
|
// Attach pageSize to this.
|
|
this.prop.pageSize = pageSize;
|
|
});
|
|
};
|
|
|
|
Worker.prototype.setProgress = function setProgress(val, state, n, stack) {
|
|
// Immediately update all progress values.
|
|
if (val != null) this.progress.val = val;
|
|
if (state != null) this.progress.state = state;
|
|
if (n != null) this.progress.n = n;
|
|
if (stack != null) this.progress.stack = stack;
|
|
this.progress.ratio = this.progress.val / this.progress.state;
|
|
|
|
// Return this for command chaining.
|
|
return this;
|
|
};
|
|
|
|
Worker.prototype.updateProgress = function updateProgress(val, state, n, stack) {
|
|
// Immediately update all progress values, using setProgress.
|
|
return this.setProgress(val ? this.progress.val + val : null, state ? state : null, n ? this.progress.n + n : null, stack ? this.progress.stack.concat(stack) : null);
|
|
};
|
|
|
|
/* ----- PROMISE MAPPING ----- */
|
|
|
|
Worker.prototype.then = function then(onFulfilled, onRejected) {
|
|
// Wrap `this` for encapsulation.
|
|
var self = this;
|
|
|
|
return this.thenCore(onFulfilled, onRejected, function then_main(onFulfilled, onRejected) {
|
|
// Update progress while queuing, calling, and resolving `then`.
|
|
self.updateProgress(null, null, 1, [onFulfilled]);
|
|
return Promise$1.prototype.then.call(this, function then_pre(val) {
|
|
self.updateProgress(null, onFulfilled);
|
|
return val;
|
|
}).then(onFulfilled, onRejected).then(function then_post(val) {
|
|
self.updateProgress(1);
|
|
return val;
|
|
});
|
|
});
|
|
};
|
|
|
|
Worker.prototype.thenCore = function thenCore(onFulfilled, onRejected, thenBase) {
|
|
// Handle optional thenBase parameter.
|
|
thenBase = thenBase || Promise$1.prototype.then;
|
|
|
|
// Wrap `this` for encapsulation and bind it to the promise handlers.
|
|
var self = this;
|
|
if (onFulfilled) {
|
|
onFulfilled = onFulfilled.bind(self);
|
|
}
|
|
if (onRejected) {
|
|
onRejected = onRejected.bind(self);
|
|
}
|
|
|
|
// Cast self into a Promise to avoid polyfills recursively defining `then`.
|
|
var isNative = Promise$1.toString().indexOf('[native code]') !== -1 && Promise$1.name === 'Promise';
|
|
var selfPromise = isNative ? self : Worker.convert(_extends({}, self), Promise$1.prototype);
|
|
|
|
// Return the promise, after casting it into a Worker and preserving props.
|
|
var returnVal = thenBase.call(selfPromise, onFulfilled, onRejected);
|
|
return Worker.convert(returnVal, self.__proto__);
|
|
};
|
|
|
|
Worker.prototype.thenExternal = function thenExternal(onFulfilled, onRejected) {
|
|
// Call `then` and return a standard promise (exits the Worker chain).
|
|
return Promise$1.prototype.then.call(this, onFulfilled, onRejected);
|
|
};
|
|
|
|
Worker.prototype.thenList = function thenList(fns) {
|
|
// Queue a series of promise 'factories' into the promise chain.
|
|
var self = this;
|
|
fns.forEach(function thenList_forEach(fn) {
|
|
self = self.thenCore(fn);
|
|
});
|
|
return self;
|
|
};
|
|
|
|
Worker.prototype['catch'] = function (onRejected) {
|
|
// Bind `this` to the promise handler, call `catch`, and return a Worker.
|
|
if (onRejected) {
|
|
onRejected = onRejected.bind(this);
|
|
}
|
|
var returnVal = Promise$1.prototype['catch'].call(this, onRejected);
|
|
return Worker.convert(returnVal, this);
|
|
};
|
|
|
|
Worker.prototype.catchExternal = function catchExternal(onRejected) {
|
|
// Call `catch` and return a standard promise (exits the Worker chain).
|
|
return Promise$1.prototype['catch'].call(this, onRejected);
|
|
};
|
|
|
|
Worker.prototype.error = function error(msg) {
|
|
// Throw the error in the Promise chain.
|
|
return this.then(function error_main() {
|
|
throw new Error(msg);
|
|
});
|
|
};
|
|
|
|
/* ----- ALIASES ----- */
|
|
|
|
Worker.prototype.using = Worker.prototype.set;
|
|
Worker.prototype.saveAs = Worker.prototype.save;
|
|
Worker.prototype.export = Worker.prototype.output;
|
|
Worker.prototype.run = Worker.prototype.then;
|
|
|
|
// Import dependencies.
|
|
// Get dimensions of a PDF page, as determined by jsPDF.
|
|
jsPDF.getPageSize = function (orientation, unit, format) {
|
|
// Decode options object
|
|
if ((typeof orientation === 'undefined' ? 'undefined' : _typeof(orientation)) === 'object') {
|
|
var options = orientation;
|
|
orientation = options.orientation;
|
|
unit = options.unit || unit;
|
|
format = options.format || format;
|
|
}
|
|
|
|
// Default options
|
|
unit = unit || 'mm';
|
|
format = format || 'a4';
|
|
orientation = ('' + (orientation || 'P')).toLowerCase();
|
|
var format_as_string = ('' + format).toLowerCase();
|
|
|
|
// Size in pt of various paper formats
|
|
var pageFormats = {
|
|
'a0': [2383.94, 3370.39], 'a1': [1683.78, 2383.94],
|
|
'a2': [1190.55, 1683.78], 'a3': [841.89, 1190.55],
|
|
'a4': [595.28, 841.89], 'a5': [419.53, 595.28],
|
|
'a6': [297.64, 419.53], 'a7': [209.76, 297.64],
|
|
'a8': [147.40, 209.76], 'a9': [104.88, 147.40],
|
|
'a10': [73.70, 104.88], 'b0': [2834.65, 4008.19],
|
|
'b1': [2004.09, 2834.65], 'b2': [1417.32, 2004.09],
|
|
'b3': [1000.63, 1417.32], 'b4': [708.66, 1000.63],
|
|
'b5': [498.90, 708.66], 'b6': [354.33, 498.90],
|
|
'b7': [249.45, 354.33], 'b8': [175.75, 249.45],
|
|
'b9': [124.72, 175.75], 'b10': [87.87, 124.72],
|
|
'c0': [2599.37, 3676.54], 'c1': [1836.85, 2599.37],
|
|
'c2': [1298.27, 1836.85], 'c3': [918.43, 1298.27],
|
|
'c4': [649.13, 918.43], 'c5': [459.21, 649.13],
|
|
'c6': [323.15, 459.21], 'c7': [229.61, 323.15],
|
|
'c8': [161.57, 229.61], 'c9': [113.39, 161.57],
|
|
'c10': [79.37, 113.39], 'dl': [311.81, 623.62],
|
|
'letter': [612, 792],
|
|
'government-letter': [576, 756],
|
|
'legal': [612, 1008],
|
|
'junior-legal': [576, 360],
|
|
'ledger': [1224, 792],
|
|
'tabloid': [792, 1224],
|
|
'credit-card': [153, 243]
|
|
};
|
|
|
|
// Unit conversion
|
|
switch (unit) {
|
|
case 'pt':
|
|
var k = 1;break;
|
|
case 'mm':
|
|
var k = 72 / 25.4;break;
|
|
case 'cm':
|
|
var k = 72 / 2.54;break;
|
|
case 'in':
|
|
var k = 72;break;
|
|
case 'px':
|
|
var k = 72 / 96;break;
|
|
case 'pc':
|
|
var k = 12;break;
|
|
case 'em':
|
|
var k = 12;break;
|
|
case 'ex':
|
|
var k = 6;break;
|
|
default:
|
|
throw 'Invalid unit: ' + unit;
|
|
}
|
|
|
|
// Dimensions are stored as user units and converted to points on output
|
|
if (pageFormats.hasOwnProperty(format_as_string)) {
|
|
var pageHeight = pageFormats[format_as_string][1] / k;
|
|
var pageWidth = pageFormats[format_as_string][0] / k;
|
|
} else {
|
|
try {
|
|
var pageHeight = format[1];
|
|
var pageWidth = format[0];
|
|
} catch (err) {
|
|
throw new Error('Invalid format: ' + format);
|
|
}
|
|
}
|
|
|
|
// Handle page orientation
|
|
if (orientation === 'p' || orientation === 'portrait') {
|
|
orientation = 'p';
|
|
if (pageWidth > pageHeight) {
|
|
var tmp = pageWidth;
|
|
pageWidth = pageHeight;
|
|
pageHeight = tmp;
|
|
}
|
|
} else if (orientation === 'l' || orientation === 'landscape') {
|
|
orientation = 'l';
|
|
if (pageHeight > pageWidth) {
|
|
var tmp = pageWidth;
|
|
pageWidth = pageHeight;
|
|
pageHeight = tmp;
|
|
}
|
|
} else {
|
|
throw 'Invalid orientation: ' + orientation;
|
|
}
|
|
|
|
// Return information (k is the unit conversion ratio from pts)
|
|
var info = { 'width': pageWidth, 'height': pageHeight, 'unit': unit, 'k': k };
|
|
return info;
|
|
};
|
|
|
|
/* Pagebreak plugin:
|
|
|
|
Adds page-break functionality to the html2pdf library. Page-breaks can be
|
|
enabled by CSS styles, set on individual elements using selectors, or
|
|
avoided from breaking inside all elements.
|
|
|
|
Options on the `opt.pagebreak` object:
|
|
|
|
mode: String or array of strings: 'avoid-all', 'css', and/or 'legacy'
|
|
Default: ['css', 'legacy']
|
|
|
|
before: String or array of CSS selectors for which to add page-breaks
|
|
before each element. Can be a specific element with an ID
|
|
('#myID'), all elements of a type (e.g. 'img'), all of a class
|
|
('.myClass'), or even '*' to match every element.
|
|
|
|
after: Like 'before', but adds a page-break immediately after the element.
|
|
|
|
avoid: Like 'before', but avoids page-breaks on these elements. You can
|
|
enable this feature on every element using the 'avoid-all' mode.
|
|
*/
|
|
|
|
// Refs to original functions.
|
|
var orig = {
|
|
toContainer: Worker.prototype.toContainer
|
|
};
|
|
|
|
// Add pagebreak default options to the Worker template.
|
|
Worker.template.opt.pagebreak = {
|
|
mode: ['css', 'legacy'],
|
|
before: [],
|
|
after: [],
|
|
avoid: []
|
|
};
|
|
|
|
Worker.prototype.toContainer = function toContainer() {
|
|
return orig.toContainer.call(this).then(function toContainer_pagebreak() {
|
|
// Setup root element and inner page height.
|
|
var root = this.prop.container;
|
|
var pxPageHeight = this.prop.pageSize.inner.px.height;
|
|
|
|
// Check all requested modes.
|
|
var modeSrc = [].concat(this.opt.pagebreak.mode);
|
|
var mode = {
|
|
avoidAll: modeSrc.indexOf('avoid-all') !== -1,
|
|
css: modeSrc.indexOf('css') !== -1,
|
|
legacy: modeSrc.indexOf('legacy') !== -1
|
|
};
|
|
|
|
// Get arrays of all explicitly requested elements.
|
|
var select = {};
|
|
var self = this;
|
|
['before', 'after', 'avoid'].forEach(function (key) {
|
|
var all = mode.avoidAll && key === 'avoid';
|
|
select[key] = all ? [] : [].concat(self.opt.pagebreak[key] || []);
|
|
if (select[key].length > 0) {
|
|
select[key] = Array.prototype.slice.call(root.querySelectorAll(select[key].join(', ')));
|
|
}
|
|
});
|
|
|
|
// Get all legacy page-break elements.
|
|
var legacyEls = root.querySelectorAll('.html2pdf__page-break');
|
|
legacyEls = Array.prototype.slice.call(legacyEls);
|
|
|
|
// Loop through all elements.
|
|
var els = root.querySelectorAll('*');
|
|
Array.prototype.forEach.call(els, function pagebreak_loop(el) {
|
|
// Setup pagebreak rules based on legacy and avoidAll modes.
|
|
var rules = {
|
|
before: false,
|
|
after: mode.legacy && legacyEls.indexOf(el) !== -1,
|
|
avoid: mode.avoidAll
|
|
};
|
|
|
|
// Add rules for css mode.
|
|
if (mode.css) {
|
|
// TODO: Check if this is valid with iFrames.
|
|
var style = window.getComputedStyle(el);
|
|
// TODO: Handle 'left' and 'right' correctly.
|
|
// TODO: Add support for 'avoid' on breakBefore/After.
|
|
var breakOpt = ['always', 'page', 'left', 'right'];
|
|
var avoidOpt = ['avoid', 'avoid-page'];
|
|
rules = {
|
|
before: rules.before || breakOpt.indexOf(style.breakBefore || style.pageBreakBefore) !== -1,
|
|
after: rules.after || breakOpt.indexOf(style.breakAfter || style.pageBreakAfter) !== -1,
|
|
avoid: rules.avoid || avoidOpt.indexOf(style.breakInside || style.pageBreakInside) !== -1
|
|
};
|
|
}
|
|
|
|
// Add rules for explicit requests.
|
|
Object.keys(rules).forEach(function (key) {
|
|
rules[key] = rules[key] || select[key].indexOf(el) !== -1;
|
|
});
|
|
|
|
// Get element position on the screen.
|
|
// TODO: Subtract the top of the container from clientRect.top/bottom?
|
|
var clientRect = el.getBoundingClientRect();
|
|
|
|
// Avoid: Check if a break happens mid-element.
|
|
if (rules.avoid && !rules.before) {
|
|
var startPage = Math.floor(clientRect.top / pxPageHeight);
|
|
var endPage = Math.floor(clientRect.bottom / pxPageHeight);
|
|
var nPages = Math.abs(clientRect.bottom - clientRect.top) / pxPageHeight;
|
|
|
|
// Turn on rules.before if the el is broken and is at most one page long.
|
|
if (endPage !== startPage && nPages <= 1) {
|
|
rules.before = true;
|
|
}
|
|
}
|
|
|
|
// Before: Create a padding div to push the element to the next page.
|
|
if (rules.before) {
|
|
var pad = createElement('div', { style: {
|
|
display: 'block',
|
|
height: pxPageHeight - clientRect.top % pxPageHeight + 'px'
|
|
} });
|
|
el.parentNode.insertBefore(pad, el);
|
|
}
|
|
|
|
// After: Create a padding div to fill the remaining page.
|
|
if (rules.after) {
|
|
var pad = createElement('div', { style: {
|
|
display: 'block',
|
|
height: pxPageHeight - clientRect.bottom % pxPageHeight + 'px'
|
|
} });
|
|
el.parentNode.insertBefore(pad, el.nextSibling);
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
// Add hyperlink functionality to the PDF creation.
|
|
|
|
// Main link array, and refs to original functions.
|
|
var linkInfo = [];
|
|
var orig$1 = {
|
|
toContainer: Worker.prototype.toContainer,
|
|
toPdf: Worker.prototype.toPdf
|
|
};
|
|
|
|
Worker.prototype.toContainer = function toContainer() {
|
|
return orig$1.toContainer.call(this).then(function toContainer_hyperlink() {
|
|
// Retrieve hyperlink info if the option is enabled.
|
|
if (this.opt.enableLinks) {
|
|
// Find all anchor tags and get the container's bounds for reference.
|
|
var container = this.prop.container;
|
|
var links = container.querySelectorAll('a');
|
|
var containerRect = unitConvert(container.getBoundingClientRect(), this.prop.pageSize.k);
|
|
linkInfo = [];
|
|
|
|
// Loop through each anchor tag.
|
|
Array.prototype.forEach.call(links, function (link) {
|
|
// Treat each client rect as a separate link (for text-wrapping).
|
|
var clientRects = link.getClientRects();
|
|
for (var i = 0; i < clientRects.length; i++) {
|
|
var clientRect = unitConvert(clientRects[i], this.prop.pageSize.k);
|
|
clientRect.left -= containerRect.left;
|
|
clientRect.top -= containerRect.top;
|
|
|
|
var page = Math.floor(clientRect.top / this.prop.pageSize.inner.height) + 1;
|
|
var top = this.opt.margin[0] + clientRect.top % this.prop.pageSize.inner.height;
|
|
var left = this.opt.margin[1] + clientRect.left;
|
|
|
|
linkInfo.push({ page: page, top: top, left: left, clientRect: clientRect, link: link });
|
|
}
|
|
}, this);
|
|
}
|
|
});
|
|
};
|
|
|
|
Worker.prototype.toPdf = function toPdf() {
|
|
return orig$1.toPdf.call(this).then(function toPdf_hyperlink() {
|
|
// Add hyperlinks if the option is enabled.
|
|
if (this.opt.enableLinks) {
|
|
// Attach each anchor tag based on info from toContainer().
|
|
linkInfo.forEach(function (l) {
|
|
this.prop.pdf.setPage(l.page);
|
|
this.prop.pdf.link(l.left, l.top, l.clientRect.width, l.clientRect.height, { url: l.link.href });
|
|
}, this);
|
|
|
|
// Reset the active page of the PDF to the final page.
|
|
var nPages = this.prop.pdf.internal.getNumberOfPages();
|
|
this.prop.pdf.setPage(nPages);
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Generate a PDF from an HTML element or string using html2canvas and jsPDF.
|
|
*
|
|
* @param {Element|string} source The source element or HTML string.
|
|
* @param {Object=} opt An object of optional settings: 'margin', 'filename',
|
|
* 'image' ('type' and 'quality'), and 'html2canvas' / 'jspdf', which are
|
|
* sent as settings to their corresponding functions.
|
|
*/
|
|
var html2pdf = function html2pdf(src, opt) {
|
|
// Create a new worker with the given options.
|
|
var worker = new html2pdf.Worker(opt);
|
|
|
|
if (src) {
|
|
// If src is specified, perform the traditional 'simple' operation.
|
|
return worker.from(src).save();
|
|
} else {
|
|
// Otherwise, return the worker for new Promise-based operation.
|
|
return worker;
|
|
}
|
|
};
|
|
html2pdf.Worker = Worker;
|
|
|
|
return html2pdf;
|
|
|
|
})));
|