Simple AcroForms support
This commit is contained in:
parent
112115c013
commit
f3ee85efab
60
src/core.js
60
src/core.js
@ -265,26 +265,40 @@ var Page = (function pagePage() {
|
||||
}
|
||||
},
|
||||
getLinks: function pageGetLinks() {
|
||||
var links = [];
|
||||
var annotations = pageGetAnnotations();
|
||||
var i, n = annotations.length;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (annotations[i].type != 'Link')
|
||||
continue;
|
||||
links.push(annotations[i]);
|
||||
}
|
||||
return links;
|
||||
},
|
||||
getAnnotations: function pageGetAnnotations() {
|
||||
var xref = this.xref;
|
||||
var annotations = xref.fetchIfRef(this.annotations) || [];
|
||||
var i, n = annotations.length;
|
||||
var links = [];
|
||||
var items = [];
|
||||
for (i = 0; i < n; ++i) {
|
||||
var annotation = xref.fetch(annotations[i]);
|
||||
if (!isDict(annotation))
|
||||
continue;
|
||||
var subtype = annotation.get('Subtype');
|
||||
if (!isName(subtype) || subtype.name != 'Link')
|
||||
if (!isName(subtype))
|
||||
continue;
|
||||
var rect = annotation.get('Rect');
|
||||
var topLeftCorner = this.rotatePoint(rect[0], rect[1]);
|
||||
var bottomRightCorner = this.rotatePoint(rect[2], rect[3]);
|
||||
|
||||
var link = {};
|
||||
link.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
|
||||
link.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
|
||||
link.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
|
||||
link.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
|
||||
var item = {};
|
||||
item.type = subtype.name;
|
||||
item.x = Math.min(topLeftCorner.x, bottomRightCorner.x);
|
||||
item.y = Math.min(topLeftCorner.y, bottomRightCorner.y);
|
||||
item.width = Math.abs(topLeftCorner.x - bottomRightCorner.x);
|
||||
item.height = Math.abs(topLeftCorner.y - bottomRightCorner.y);
|
||||
switch (subtype.name) {
|
||||
case 'Link':
|
||||
var a = this.xref.fetchIfRef(annotation.get('A'));
|
||||
if (a) {
|
||||
switch (a.get('S').name) {
|
||||
@ -302,9 +316,36 @@ var Page = (function pagePage() {
|
||||
var dest = annotation.get('Dest');
|
||||
link.dest = isName(dest) ? dest.name : dest;
|
||||
}
|
||||
links.push(link);
|
||||
break;
|
||||
case 'Widget':
|
||||
var fieldType = annotation.get('FT');
|
||||
if (!isName(fieldType))
|
||||
break;
|
||||
item.fieldType = fieldType.name;
|
||||
var fieldName = [];
|
||||
var name = stringToPDFString(annotation.get('T'));
|
||||
if (name)
|
||||
fieldName.push(name)
|
||||
var parent = xref.fetchIfRef(annotation.get('Parent'));
|
||||
while (parent) {
|
||||
name = stringToPDFString(parent.get('T'));
|
||||
if (name)
|
||||
fieldName.unshift(name);
|
||||
parent = xref.fetchIfRef(parent.get('Parent'));
|
||||
}
|
||||
return links;
|
||||
item.fullName = fieldName.join('.');
|
||||
var alternativeText = stringToPDFString(annotation.get('TU') || '');
|
||||
item.alternativeText = alternativeText;
|
||||
var da = annotation.get('DA') || '';
|
||||
var m = /([\d\.]+)\sTf/.exec(da);
|
||||
if (m)
|
||||
item.fontSize = parseFloat(m[1]);
|
||||
item.flags = annotation.get('Ff') || 0;
|
||||
break;
|
||||
}
|
||||
items.push(item);
|
||||
}
|
||||
return items;
|
||||
},
|
||||
startRendering: function pageStartRendering(ctx, callback) {
|
||||
this.ctx = ctx;
|
||||
@ -342,6 +383,7 @@ var PDFDocModel = (function pdfDoc() {
|
||||
assertWellFormed(stream.length > 0, 'stream must have data');
|
||||
this.stream = stream;
|
||||
this.setup();
|
||||
this.acroForm = this.xref.fetchIfRef(this.catalog.catDict.get('AcroForm'));
|
||||
}
|
||||
|
||||
function find(stream, needle, limit, backwards) {
|
||||
|
@ -231,6 +231,23 @@ canvas {
|
||||
-webkit-box-shadow: 0px 2px 10px #ff0;
|
||||
}
|
||||
|
||||
.page > .inputHint {
|
||||
opacity: 0.2;
|
||||
background: #ccc;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.page > .inputControl {
|
||||
background: transparent;
|
||||
border: 0px none;
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.page > .inputControl[type='checkbox'] {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#viewer {
|
||||
margin: 44px 0px 0px;
|
||||
padding: 8px 0px;
|
||||
@ -281,6 +298,10 @@ canvas {
|
||||
display: block;
|
||||
page-break-after: always;
|
||||
}
|
||||
|
||||
.inputHint {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#loading {
|
||||
|
@ -33,6 +33,7 @@ var PDFView = {
|
||||
thumbnails: [],
|
||||
currentScale: kDefaultScale,
|
||||
initialBookmark: document.location.hash.substring(1),
|
||||
formFields: [],
|
||||
|
||||
setScale: function pdfViewSetScale(val, resetAutoSettings) {
|
||||
var pages = this.pages;
|
||||
@ -362,7 +363,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
div.removeAttribute('data-loaded');
|
||||
};
|
||||
|
||||
function setupLinks(content, scale) {
|
||||
function setupAnnotations(content, scale) {
|
||||
function bindLink(link, dest) {
|
||||
link.href = PDFView.getDestinationHash(dest);
|
||||
link.onclick = function pageViewSetupLinksOnclick() {
|
||||
@ -371,18 +372,82 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
return false;
|
||||
};
|
||||
}
|
||||
function bindInputItem(input, item) {
|
||||
if (input.name in PDFView.formFields) {
|
||||
var value = PDFView.formFields[input.name];
|
||||
if (input.type == 'checkbox')
|
||||
input.checked = value;
|
||||
else if (!input.type || input.type == 'text')
|
||||
input.value = value;
|
||||
}
|
||||
input.onchange = function pageViewSetupInputOnBlur() {
|
||||
if (input.type == 'checkbox')
|
||||
PDFView.formFields[input.name] = input.checked;
|
||||
else if (!input.type || input.type == 'text')
|
||||
PDFView.formFields[input.name] = input.value;
|
||||
};
|
||||
}
|
||||
function createElementWithStyle(tagName, item) {
|
||||
var element = document.createElement(tagName);
|
||||
element.style.left = (Math.floor(item.x - view.x) * scale) + 'px';
|
||||
element.style.top = (Math.floor(item.y - view.y) * scale) + 'px';
|
||||
element.style.width = Math.ceil(item.width * scale) + 'px';
|
||||
element.style.height = Math.ceil(item.height * scale) + 'px';
|
||||
return element;
|
||||
}
|
||||
function assignFontStyle(element, item) {
|
||||
var fontStyles = '';
|
||||
if ('fontSize' in item)
|
||||
fontStyles += 'font-size: ' + Math.round(item.fontSize * scale) + 'px';
|
||||
element.setAttribute('style', element.getAttribute('style') + fontStyles);
|
||||
}
|
||||
|
||||
var links = content.getLinks();
|
||||
for (var i = 0; i < links.length; i++) {
|
||||
var link = document.createElement('a');
|
||||
link.style.left = (Math.floor(links[i].x - view.x) * scale) + 'px';
|
||||
link.style.top = (Math.floor(links[i].y - view.y) * scale) + 'px';
|
||||
link.style.width = Math.ceil(links[i].width * scale) + 'px';
|
||||
link.style.height = Math.ceil(links[i].height * scale) + 'px';
|
||||
link.href = links[i].url || '';
|
||||
if (!links[i].url)
|
||||
bindLink(link, ('dest' in links[i]) ? links[i].dest : null);
|
||||
var items = content.getAnnotations();
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
var item = items[i];
|
||||
switch (item.type) {
|
||||
case 'Link':
|
||||
var link = createElementWithStyle('a', item);
|
||||
link.href = item.url || '';
|
||||
if (!item.url)
|
||||
bindLink(link, ('dest' in item) ? item.dest : null);
|
||||
div.appendChild(link);
|
||||
break;
|
||||
case 'Widget':
|
||||
if (item.fieldType != 'Tx' && item.fieldType != 'Btn' &&
|
||||
item.fieldType != 'Ch')
|
||||
break;
|
||||
var inputDiv = createElementWithStyle('div', item);
|
||||
inputDiv.className = 'inputHint';
|
||||
div.appendChild(inputDiv);
|
||||
var input;
|
||||
if (item.fieldType == 'Tx') {
|
||||
input = createElementWithStyle('input', item);
|
||||
}
|
||||
if (item.fieldType == 'Btn') {
|
||||
input = createElementWithStyle('input', item);
|
||||
if (item.flags & 32768) {
|
||||
input.type = 'radio';
|
||||
TODO('radio button is not supported');
|
||||
} else if (item.flags & 65536) {
|
||||
input.type = 'button';
|
||||
TODO('pushbutton is not supported');
|
||||
} else {
|
||||
input.type = 'checkbox';
|
||||
}
|
||||
}
|
||||
if (item.fieldType == 'Ch') {
|
||||
input = createElementWithStyle('select', item);
|
||||
TODO('select box is not supported');
|
||||
}
|
||||
input.className = 'inputControl';
|
||||
input.name = item.fullName;
|
||||
input.title = item.alternativeText;
|
||||
assignFontStyle(input, item);
|
||||
bindInputItem(input, item);
|
||||
div.appendChild(input);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -489,7 +554,7 @@ var PageView = function pageView(container, content, id, pageWidth, pageHeight,
|
||||
stats.begin = Date.now();
|
||||
this.content.startRendering(ctx, this.updateStats);
|
||||
|
||||
setupLinks(this.content, this.scale);
|
||||
setupAnnotations(this.content, this.scale);
|
||||
div.setAttribute('data-loaded', true);
|
||||
|
||||
return true;
|
||||
@ -738,6 +803,8 @@ window.addEventListener('pagechange', function pagechange(evt) {
|
||||
|
||||
window.addEventListener('keydown', function keydown(evt) {
|
||||
var curElement = document.activeElement;
|
||||
if (curElement && curElement.tagName == 'INPUT')
|
||||
return;
|
||||
var controlsElement = document.getElementById('controls');
|
||||
while (curElement) {
|
||||
if (curElement === controlsElement)
|
||||
|
Loading…
Reference in New Issue
Block a user