Button widget annotations: improve unit tests, simplify code and remove labels
Modern browsers support styling radio buttons and checkboxes with CSS. This makes the implementation much easier, and the fallback for older browsers is still decent.
This commit is contained in:
parent
77148c7880
commit
a428899b3c
@ -773,17 +773,18 @@ 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.checkBox = !this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
|
||||
if (this.data.checkBox) {
|
||||
if (!isName(this.data.fieldValue)) {
|
||||
return;
|
||||
}
|
||||
this.data.fieldValue = this.data.fieldValue.name;
|
||||
} else {
|
||||
warn('Button widget annotation: field value is not a `Name` object.');
|
||||
}
|
||||
|
||||
if (this.data.radio) {
|
||||
this.data.radioButton = this.hasFieldFlag(AnnotationFieldFlag.RADIO) &&
|
||||
!this.hasFieldFlag(AnnotationFieldFlag.PUSHBUTTON);
|
||||
if (this.data.radioButton) {
|
||||
this.data.fieldValue = this.data.buttonValue = null;
|
||||
|
||||
// The parent field's `V` entry holds a `Name` object with the appearance
|
||||
|
@ -77,14 +77,12 @@ AnnotationElementFactory.prototype =
|
||||
case 'Tx':
|
||||
return new TextWidgetAnnotationElement(parameters);
|
||||
case 'Btn':
|
||||
if (!parameters.data.pushbutton) {
|
||||
if (parameters.data.radio) {
|
||||
if (parameters.data.radioButton) {
|
||||
return new RadioButtonWidgetAnnotationElement(parameters);
|
||||
} else {
|
||||
} else if (parameters.data.checkBox) {
|
||||
return new CheckboxWidgetAnnotationElement(parameters);
|
||||
}
|
||||
} else {
|
||||
warn('Unimplemented push button');
|
||||
warn('Unimplemented button widget annotation: pushbutton');
|
||||
}
|
||||
break;
|
||||
case 'Ch':
|
||||
@ -152,7 +150,6 @@ var AnnotationElement = (function AnnotationElementClosure() {
|
||||
var height = data.rect[3] - data.rect[1];
|
||||
|
||||
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
|
||||
// position on subsequent calls to `_createContainer` (see issue 6804).
|
||||
@ -568,15 +565,11 @@ var CheckboxWidgetAnnotationElement =
|
||||
var element = document.createElement('input');
|
||||
element.disabled = this.data.readOnly;
|
||||
element.type = 'checkbox';
|
||||
element.id = this.data.fieldName;
|
||||
if (this.data.fieldValue && this.data.fieldValue !== 'Off') {
|
||||
element.checked = true;
|
||||
element.setAttribute('checked', true);
|
||||
}
|
||||
this.container.appendChild(element);
|
||||
element = document.createElement('label');
|
||||
element.htmlFor = this.data.fieldName;
|
||||
this.container.appendChild(element);
|
||||
|
||||
this.container.appendChild(element);
|
||||
return this.container;
|
||||
}
|
||||
});
|
||||
@ -608,22 +601,16 @@ var RadioButtonWidgetAnnotationElement =
|
||||
this.container.className = 'buttonWidgetAnnotation radioButton';
|
||||
|
||||
var element = document.createElement('input');
|
||||
var id = this.data.fieldName + '.' + this.data.buttonValue;
|
||||
element.disabled = this.data.readOnly;
|
||||
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;
|
||||
element.setAttribute('checked', true);
|
||||
}
|
||||
this.container.appendChild(element);
|
||||
element = document.createElement('label');
|
||||
element.htmlFor = id;
|
||||
this.container.appendChild(element);
|
||||
|
||||
this.container.appendChild(element);
|
||||
return this.container;
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
return RadioButtonWidgetAnnotationElement;
|
||||
|
@ -15,6 +15,11 @@
|
||||
|
||||
/* Used for annotation layer tests */
|
||||
|
||||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.annotationLayer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
@ -46,8 +51,8 @@
|
||||
.annotationLayer .textWidgetAnnotation input,
|
||||
.annotationLayer .textWidgetAnnotation textarea,
|
||||
.annotationLayer .choiceWidgetAnnotation select,
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox label,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton label {
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input {
|
||||
background-color: rgba(0, 54, 255, 0.13);
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
@ -67,8 +72,8 @@
|
||||
.annotationLayer .textWidgetAnnotation input[disabled],
|
||||
.annotationLayer .textWidgetAnnotation textarea[disabled],
|
||||
.annotationLayer .choiceWidgetAnnotation select[disabled],
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input[disabled] + label,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input[disabled] + label {
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input[disabled],
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input[disabled] {
|
||||
background: none;
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
@ -79,19 +84,12 @@
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox label,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton label {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton label {
|
||||
border-radius: 50%;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
-ms-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.annotationLayer .popupAnnotation {
|
||||
|
@ -869,94 +869,62 @@ describe('Annotation layer', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('CheckboxWidgetAnnotation', function() {
|
||||
var checkboxWidgetDict;
|
||||
describe('ButtonWidgetAnnotation', function() {
|
||||
var buttonWidgetDict;
|
||||
|
||||
beforeEach(function (done) {
|
||||
checkboxWidgetDict = new Dict();
|
||||
checkboxWidgetDict.set('Type', Name.get('Annot'));
|
||||
checkboxWidgetDict.set('Subtype', Name.get('Widget'));
|
||||
checkboxWidgetDict.set('FT', Name.get('Btn'));
|
||||
buttonWidgetDict = new Dict();
|
||||
buttonWidgetDict.set('Type', Name.get('Annot'));
|
||||
buttonWidgetDict.set('Subtype', Name.get('Widget'));
|
||||
buttonWidgetDict.set('FT', Name.get('Btn'));
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
checkboxWidgetDict = null;
|
||||
buttonWidgetDict = null;
|
||||
});
|
||||
|
||||
it('should have proper flags',
|
||||
function() {
|
||||
var checkboxWidgetRef = new Ref(124, 0);
|
||||
it('should handle checkboxes', function() {
|
||||
buttonWidgetDict.set('V', Name.get('1'));
|
||||
|
||||
var buttonWidgetRef = new Ref(124, 0);
|
||||
var xref = new XRefMock([
|
||||
{ ref: checkboxWidgetRef, data: checkboxWidgetDict, }
|
||||
{ ref: buttonWidgetRef, data: buttonWidgetDict, }
|
||||
]);
|
||||
|
||||
var checkboxWidgetAnnotation =
|
||||
annotationFactory.create(xref, checkboxWidgetRef);
|
||||
expect(checkboxWidgetAnnotation.data.radio).toEqual(false);
|
||||
expect(checkboxWidgetAnnotation.data.pushbutton).toEqual(false);
|
||||
expect(checkboxWidgetAnnotation.data.fieldValue).toEqual(null);
|
||||
var buttonWidgetAnnotation =
|
||||
annotationFactory.create(xref, buttonWidgetRef);
|
||||
expect(buttonWidgetAnnotation.data.checkBox).toEqual(true);
|
||||
expect(buttonWidgetAnnotation.data.fieldValue).toEqual('1');
|
||||
expect(buttonWidgetAnnotation.data.radioButton).toEqual(false);
|
||||
});
|
||||
|
||||
it('should have a proper value',
|
||||
function() {
|
||||
checkboxWidgetDict.set('V', Name.get('1'));
|
||||
it('should handle radio buttons', function() {
|
||||
var parentDict = new Dict();
|
||||
parentDict.set('V', Name.get('1'));
|
||||
|
||||
var checkboxWidgetRef = new Ref(124, 0);
|
||||
var normalAppearanceStateDict = new Dict();
|
||||
normalAppearanceStateDict.set('2', null);
|
||||
|
||||
var appearanceStatesDict = new Dict();
|
||||
appearanceStatesDict.set('N', normalAppearanceStateDict);
|
||||
|
||||
buttonWidgetDict.set('Ff', AnnotationFieldFlag.RADIO);
|
||||
buttonWidgetDict.set('Parent', parentDict);
|
||||
buttonWidgetDict.set('AP', appearanceStatesDict);
|
||||
|
||||
var buttonWidgetRef = new Ref(124, 0);
|
||||
var xref = new XRefMock([
|
||||
{ ref: checkboxWidgetRef, data: checkboxWidgetDict, }
|
||||
{ ref: buttonWidgetRef, data: buttonWidgetDict, }
|
||||
]);
|
||||
|
||||
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');
|
||||
var buttonWidgetAnnotation =
|
||||
annotationFactory.create(xref, buttonWidgetRef);
|
||||
expect(buttonWidgetAnnotation.data.checkBox).toEqual(false);
|
||||
expect(buttonWidgetAnnotation.data.radioButton).toEqual(true);
|
||||
expect(buttonWidgetAnnotation.data.fieldValue).toEqual('1');
|
||||
expect(buttonWidgetAnnotation.data.buttonValue).toEqual('2');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -43,7 +43,9 @@
|
||||
|
||||
.annotationLayer .textWidgetAnnotation input,
|
||||
.annotationLayer .textWidgetAnnotation textarea,
|
||||
.annotationLayer .choiceWidgetAnnotation select {
|
||||
.annotationLayer .choiceWidgetAnnotation select,
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input {
|
||||
background-color: rgba(0, 54, 255, 0.13);
|
||||
border: 1px solid transparent;
|
||||
box-sizing: border-box;
|
||||
@ -63,8 +65,8 @@
|
||||
.annotationLayer .textWidgetAnnotation input[disabled],
|
||||
.annotationLayer .textWidgetAnnotation textarea[disabled],
|
||||
.annotationLayer .choiceWidgetAnnotation select[disabled],
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input[disabled] + label,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input[disabled] + label {
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input[disabled],
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input[disabled] {
|
||||
background: none;
|
||||
border: 1px solid transparent;
|
||||
cursor: not-allowed;
|
||||
@ -72,7 +74,9 @@
|
||||
|
||||
.annotationLayer .textWidgetAnnotation input:hover,
|
||||
.annotationLayer .textWidgetAnnotation textarea:hover,
|
||||
.annotationLayer .choiceWidgetAnnotation select:hover {
|
||||
.annotationLayer .choiceWidgetAnnotation select:hover,
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input:hover,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input:hover {
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
@ -99,66 +103,12 @@
|
||||
width: 115%;
|
||||
}
|
||||
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox label,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton 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 .buttonWidgetAnnotation.checkBox input,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
}
|
||||
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton label {
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox label:hover,
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox label:focus,
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input:focus + label,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton label:hover,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton label:focus,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input:focus + label {
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox input:checked + label:before,
|
||||
.annotationLayer .buttonWidgetAnnotation.radioButton input:checked + label:before {
|
||||
content: '';
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.annotationLayer .buttonWidgetAnnotation.checkBox 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 .buttonWidgetAnnotation.radioButton 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%;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
-ms-appearance: none;
|
||||
appearance: none;
|
||||
}
|
||||
|
||||
.annotationLayer .popupWrapper {
|
||||
|
Loading…
x
Reference in New Issue
Block a user