Button widget annotations: implement checkboxes and radio buttons
This commit is contained in:
parent
d0893b0c48
commit
ba012c7a68
@ -106,6 +106,8 @@ AnnotationFactory.prototype = /** @lends AnnotationFactory.prototype */ {
|
|||||||
switch (fieldType) {
|
switch (fieldType) {
|
||||||
case 'Tx':
|
case 'Tx':
|
||||||
return new TextWidgetAnnotation(parameters);
|
return new TextWidgetAnnotation(parameters);
|
||||||
|
case 'Btn':
|
||||||
|
return new ButtonWidgetAnnotation(parameters);
|
||||||
case 'Ch':
|
case 'Ch':
|
||||||
return new ChoiceWidgetAnnotation(parameters);
|
return new ChoiceWidgetAnnotation(parameters);
|
||||||
}
|
}
|
||||||
@ -767,6 +769,59 @@ var TextWidgetAnnotation = (function TextWidgetAnnotationClosure() {
|
|||||||
return TextWidgetAnnotation;
|
return TextWidgetAnnotation;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
var ButtonWidgetAnnotation = (function ButtonWidgetAnnotationClosure() {
|
||||||
|
function ButtonWidgetAnnotation(params) {
|
||||||
|
WidgetAnnotation.call(this, params);
|
||||||
|
|
||||||
|
this.data.pushbutton = this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
|
||||||
|
this.data.radio = !this.data.pushbutton &&
|
||||||
|
this.hasFieldFlag(AnnotationFieldFlag.RADIO);
|
||||||
|
if (isName(this.data.fieldValue)) {
|
||||||
|
this.data.fieldValue = this.data.fieldValue.name;
|
||||||
|
}
|
||||||
|
// Get the value of the radio button
|
||||||
|
if (this.data.radio) {
|
||||||
|
// Generate a unique ID in case no value is found
|
||||||
|
this.data.buttonValue = Math.random().toString(16).slice(2);
|
||||||
|
var appearanceState = params.dict.get('AP');
|
||||||
|
if (isDict(appearanceState)) {
|
||||||
|
var appearances = appearanceState.get('N');
|
||||||
|
if (isDict(appearances) && appearances.has('Off')) {
|
||||||
|
var keys = appearances.getKeys();
|
||||||
|
for (var i = 0, ii = keys.length; i < ii; i++) {
|
||||||
|
if (keys[i] !== 'Off') {
|
||||||
|
this.data.buttonValue = keys[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Util.inherit(ButtonWidgetAnnotation, WidgetAnnotation, {
|
||||||
|
getOperatorList:
|
||||||
|
function ButtonWidgetAnnotation_getOperatorList(evaluator, task,
|
||||||
|
renderForms) {
|
||||||
|
var operatorList = new OperatorList();
|
||||||
|
|
||||||
|
// Do not render form elements on the canvas when interactive forms are
|
||||||
|
// enabled. The display layer is responsible for rendering them instead.
|
||||||
|
if (renderForms) {
|
||||||
|
return Promise.resolve(operatorList);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.appearance) {
|
||||||
|
return Annotation.prototype.getOperatorList.call(this, evaluator, task,
|
||||||
|
renderForms);
|
||||||
|
}
|
||||||
|
return Promise.resolve(operatorList);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return ButtonWidgetAnnotation;
|
||||||
|
})();
|
||||||
|
|
||||||
var ChoiceWidgetAnnotation = (function ChoiceWidgetAnnotationClosure() {
|
var ChoiceWidgetAnnotation = (function ChoiceWidgetAnnotationClosure() {
|
||||||
function ChoiceWidgetAnnotation(params) {
|
function ChoiceWidgetAnnotation(params) {
|
||||||
WidgetAnnotation.call(this, params);
|
WidgetAnnotation.call(this, params);
|
||||||
|
@ -76,6 +76,17 @@ AnnotationElementFactory.prototype =
|
|||||||
switch (fieldType) {
|
switch (fieldType) {
|
||||||
case 'Tx':
|
case 'Tx':
|
||||||
return new TextWidgetAnnotationElement(parameters);
|
return new TextWidgetAnnotationElement(parameters);
|
||||||
|
case 'Btn':
|
||||||
|
if (!parameters.data.pushbutton) {
|
||||||
|
if (parameters.data.radio) {
|
||||||
|
return new RadioButtonWidgetAnnotationElement(parameters);
|
||||||
|
} else {
|
||||||
|
return new CheckboxWidgetAnnotationElement(parameters);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
warn('Unimplemented push button');
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'Ch':
|
case 'Ch':
|
||||||
return new ChoiceWidgetAnnotationElement(parameters);
|
return new ChoiceWidgetAnnotationElement(parameters);
|
||||||
}
|
}
|
||||||
@ -141,6 +152,7 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
|||||||
var height = data.rect[3] - data.rect[1];
|
var height = data.rect[3] - data.rect[1];
|
||||||
|
|
||||||
container.setAttribute('data-annotation-id', data.id);
|
container.setAttribute('data-annotation-id', data.id);
|
||||||
|
container.setAttribute('data-annotation-name', data.fieldName);
|
||||||
|
|
||||||
// Do *not* modify `data.rect`, since that will corrupt the annotation
|
// Do *not* modify `data.rect`, since that will corrupt the annotation
|
||||||
// position on subsequent calls to `_createContainer` (see issue 6804).
|
// position on subsequent calls to `_createContainer` (see issue 6804).
|
||||||
@ -531,6 +543,91 @@ var TextWidgetAnnotationElement = (
|
|||||||
})();
|
})();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @class
|
||||||
|
* @alias CheckboxWidgetAnnotationElement
|
||||||
|
*/
|
||||||
|
var CheckboxWidgetAnnotationElement =
|
||||||
|
(function CheckboxWidgetAnnotationElementClosure() {
|
||||||
|
function CheckboxWidgetAnnotationElement(parameters) {
|
||||||
|
WidgetAnnotationElement.call(this, parameters,
|
||||||
|
parameters.renderInteractiveForms);
|
||||||
|
}
|
||||||
|
|
||||||
|
Util.inherit(CheckboxWidgetAnnotationElement, WidgetAnnotationElement, {
|
||||||
|
/**
|
||||||
|
* Render the checkbox widget annotation's HTML element
|
||||||
|
* in the empty container.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof CheckboxWidgetAnnotationElement
|
||||||
|
* @returns {HTMLSectionElement}
|
||||||
|
*/
|
||||||
|
render: function CheckboxWidgetAnnotationElement_render() {
|
||||||
|
this.container.className = 'checkboxWidgetAnnotation';
|
||||||
|
|
||||||
|
var element = document.createElement('input');
|
||||||
|
element.type = 'checkbox';
|
||||||
|
element.id = this.data.fieldName;
|
||||||
|
if (this.data.fieldValue && this.data.fieldValue !== 'Off') {
|
||||||
|
element.checked = true;
|
||||||
|
}
|
||||||
|
this.container.appendChild(element);
|
||||||
|
element = document.createElement('label');
|
||||||
|
element.htmlFor = this.data.fieldName;
|
||||||
|
this.container.appendChild(element);
|
||||||
|
|
||||||
|
return this.container;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return CheckboxWidgetAnnotationElement;
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @class
|
||||||
|
* @alias RadioButtonWidgetAnnotationElement
|
||||||
|
*/
|
||||||
|
var RadioButtonWidgetAnnotationElement =
|
||||||
|
(function RadioButtonWidgetAnnotationElementClosure() {
|
||||||
|
function RadioButtonWidgetAnnotationElement(parameters) {
|
||||||
|
WidgetAnnotationElement.call(this, parameters,
|
||||||
|
parameters.renderInteractiveForms);
|
||||||
|
}
|
||||||
|
|
||||||
|
Util.inherit(RadioButtonWidgetAnnotationElement, WidgetAnnotationElement, {
|
||||||
|
/**
|
||||||
|
* Render the radio button widget annotation's HTML element
|
||||||
|
* in the empty container.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
* @memberof RadioButtonWidgetAnnotationElement
|
||||||
|
* @returns {HTMLSectionElement}
|
||||||
|
*/
|
||||||
|
render: function RadioButtonWidgetAnnotationElement_render() {
|
||||||
|
this.container.className = 'radioButtonWidgetAnnotation';
|
||||||
|
|
||||||
|
var element = document.createElement('input');
|
||||||
|
var id = this.data.fieldName + '.' + this.data.buttonValue;
|
||||||
|
element.type = 'radio';
|
||||||
|
element.id = id;
|
||||||
|
element.name = this.data.fieldName;
|
||||||
|
element.value = this.data.buttonValue;
|
||||||
|
if (this.data.fieldValue === this.data.buttonValue) {
|
||||||
|
element.checked = true;
|
||||||
|
}
|
||||||
|
this.container.appendChild(element);
|
||||||
|
element = document.createElement('label');
|
||||||
|
element.htmlFor = id;
|
||||||
|
this.container.appendChild(element);
|
||||||
|
|
||||||
|
return this.container;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
return RadioButtonWidgetAnnotationElement;
|
||||||
|
})();
|
||||||
|
|
||||||
|
/**
|
||||||
* @class
|
* @class
|
||||||
* @alias ChoiceWidgetAnnotationElement
|
* @alias ChoiceWidgetAnnotationElement
|
||||||
*/
|
*/
|
||||||
|
@ -869,6 +869,97 @@ describe('Annotation layer', function() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('CheckboxWidgetAnnotation', function() {
|
||||||
|
var checkboxWidgetDict;
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
checkboxWidgetDict = new Dict();
|
||||||
|
checkboxWidgetDict.set('Type', Name.get('Annot'));
|
||||||
|
checkboxWidgetDict.set('Subtype', Name.get('Widget'));
|
||||||
|
checkboxWidgetDict.set('FT', Name.get('Btn'));
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
checkboxWidgetDict = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have proper flags',
|
||||||
|
function() {
|
||||||
|
var checkboxWidgetRef = new Ref(124, 0);
|
||||||
|
var xref = new XRefMock([
|
||||||
|
{ ref: checkboxWidgetRef, data: checkboxWidgetDict, }
|
||||||
|
]);
|
||||||
|
|
||||||
|
var checkboxWidgetAnnotation =
|
||||||
|
annotationFactory.create(xref, checkboxWidgetRef);
|
||||||
|
expect(checkboxWidgetAnnotation.data.radio).toEqual(false);
|
||||||
|
expect(checkboxWidgetAnnotation.data.pushbutton).toEqual(false);
|
||||||
|
expect(checkboxWidgetAnnotation.data.fieldValue).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a proper value',
|
||||||
|
function() {
|
||||||
|
checkboxWidgetDict.set('V', Name.get('1'));
|
||||||
|
|
||||||
|
var checkboxWidgetRef = new Ref(124, 0);
|
||||||
|
var xref = new XRefMock([
|
||||||
|
{ ref: checkboxWidgetRef, data: checkboxWidgetDict, }
|
||||||
|
]);
|
||||||
|
|
||||||
|
var checkboxWidgetAnnotation =
|
||||||
|
annotationFactory.create(xref, checkboxWidgetRef);
|
||||||
|
expect(checkboxWidgetAnnotation.data.fieldValue).toEqual('1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RadioButtonWidgetAnnotation', function() {
|
||||||
|
var radioButtonWidgetDict;
|
||||||
|
|
||||||
|
beforeEach(function (done) {
|
||||||
|
radioButtonWidgetDict = new Dict();
|
||||||
|
radioButtonWidgetDict.set('Type', Name.get('Annot'));
|
||||||
|
radioButtonWidgetDict.set('Subtype', Name.get('Widget'));
|
||||||
|
radioButtonWidgetDict.set('FT', Name.get('Btn'));
|
||||||
|
radioButtonWidgetDict.set('Ff', AnnotationFieldFlag.RADIO);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
radioButtonWidgetDict = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have proper flags',
|
||||||
|
function() {
|
||||||
|
var radioButtonWidgetRef = new Ref(124, 0);
|
||||||
|
var xref = new XRefMock([
|
||||||
|
{ ref: radioButtonWidgetRef, data: radioButtonWidgetDict, }
|
||||||
|
]);
|
||||||
|
|
||||||
|
var radioButtonWidgetAnnotation =
|
||||||
|
annotationFactory.create(xref, radioButtonWidgetRef);
|
||||||
|
expect(radioButtonWidgetAnnotation.data.radio).toEqual(true);
|
||||||
|
expect(radioButtonWidgetAnnotation.data.pushbutton).toEqual(false);
|
||||||
|
expect(radioButtonWidgetAnnotation.data.fieldValue).toEqual(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have a proper value',
|
||||||
|
function() {
|
||||||
|
radioButtonWidgetDict.set('V', Name.get('1'));
|
||||||
|
|
||||||
|
var radioButtonWidgetRef = new Ref(124, 0);
|
||||||
|
var xref = new XRefMock([
|
||||||
|
{ ref: radioButtonWidgetRef, data: radioButtonWidgetDict, }
|
||||||
|
]);
|
||||||
|
|
||||||
|
var radioButtonWidgetAnnotation =
|
||||||
|
annotationFactory.create(xref, radioButtonWidgetRef);
|
||||||
|
expect(radioButtonWidgetAnnotation.data.fieldValue).toEqual('1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('ChoiceWidgetAnnotation', function() {
|
describe('ChoiceWidgetAnnotation', function() {
|
||||||
var choiceWidgetDict;
|
var choiceWidgetDict;
|
||||||
|
|
||||||
|
@ -97,6 +97,68 @@
|
|||||||
width: 115%;
|
width: 115%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.annotationLayer .checkboxWidgetAnnotation label,
|
||||||
|
.annotationLayer .radioButtonWidgetAnnotation label {
|
||||||
|
background-color: rgba(0, 54, 255, 0.13);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
box-sizing: border-box;
|
||||||
|
cursor: pointer;
|
||||||
|
height: 100%;
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotationLayer .checkboxWidgetAnnotation input,
|
||||||
|
.annotationLayer .radioButtonWidgetAnnotation input {
|
||||||
|
position: absolute;
|
||||||
|
left: -9999px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotationLayer .radioButtonWidgetAnnotation label {
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotationLayer .checkboxWidgetAnnotation label:hover,
|
||||||
|
.annotationLayer .radioButtonWidgetAnnotation label:hover,
|
||||||
|
.annotationLayer .checkboxWidgetAnnotation label:focus,
|
||||||
|
.annotationLayer .radioButtonWidgetAnnotation label:focus,
|
||||||
|
.annotationLayer .checkboxWidgetAnnotation input:focus + label,
|
||||||
|
.annotationLayer .radioButtonWidgetAnnotation input:focus + label {
|
||||||
|
border: 1px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotationLayer .checkboxWidgetAnnotation input:checked + label:before,
|
||||||
|
.annotationLayer .radioButtonWidgetAnnotation input:checked + label:before {
|
||||||
|
content: '';
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotationLayer .checkboxWidgetAnnotation input:checked + label:before {
|
||||||
|
border-bottom: 1px solid #000;
|
||||||
|
border-left: 1px solid #000;
|
||||||
|
height: 25%;
|
||||||
|
-webkit-transform: translate(-50%, -65%) rotateZ(-45deg);
|
||||||
|
-moz-transform: translate(-50%, -65%) rotateZ(-45deg);
|
||||||
|
-o-transform: translate(-50%, -65%) rotateZ(-45deg);
|
||||||
|
-ms-transform: translate(-50%, -65%) rotateZ(-45deg);
|
||||||
|
transform: translate(-50%, -65%) rotateZ(-45deg);
|
||||||
|
width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.annotationLayer .radioButtonWidgetAnnotation input:checked + label:before {
|
||||||
|
background-color: #000;
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 50%;
|
||||||
|
-webkit-transform: translate(-50%, -50%);
|
||||||
|
-moz-transform: translate(-50%, -50%);
|
||||||
|
-o-transform: translate(-50%, -50%);
|
||||||
|
-ms-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
width: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
.annotationLayer .popupWrapper {
|
.annotationLayer .popupWrapper {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
width: 20em;
|
width: 20em;
|
||||||
|
Loading…
Reference in New Issue
Block a user