Skip to content

Commit

Permalink
Merge pull request mozilla#12108 from calixteman/radio
Browse files Browse the repository at this point in the history
Add support for radios printing
  • Loading branch information
timvandermeij authored Aug 2, 2020
2 parents 277a92d + f22e702 commit 5a66c56
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 41 deletions.
9 changes: 6 additions & 3 deletions src/core/annotation.js
Original file line number Diff line number Diff line change
Expand Up @@ -1078,16 +1078,19 @@ class ButtonWidgetAnnotation extends WidgetAnnotation {
if (!isDict(appearanceStates)) {
return;
}
const normalAppearanceState = appearanceStates.get("N");
if (!isDict(normalAppearanceState)) {
const normalAppearance = appearanceStates.get("N");
if (!isDict(normalAppearance)) {
return;
}
for (const key of normalAppearanceState.getKeys()) {
for (const key of normalAppearance.getKeys()) {
if (key !== "Off") {
this.data.buttonValue = key;
break;
}
}

this.checkedAppearance = normalAppearance.get(this.data.buttonValue);
this.uncheckedAppearance = normalAppearance.get("Off") || null;
}

_processPushButton(params) {
Expand Down
26 changes: 23 additions & 3 deletions src/display/annotation_layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -586,15 +586,35 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
*/
render() {
this.container.className = "buttonWidgetAnnotation radioButton";
const storage = this.annotationStorage;
const data = this.data;
const id = data.id;
const value = storage.getOrCreateValue(
id,
data.fieldValue === data.buttonValue
);

const element = document.createElement("input");
element.disabled = this.data.readOnly;
element.disabled = data.readOnly;
element.type = "radio";
element.name = this.data.fieldName;
if (this.data.fieldValue === this.data.buttonValue) {
element.name = data.fieldName;
if (value) {
element.setAttribute("checked", true);
}

element.addEventListener("change", function (event) {
const name = event.target.name;
for (const radio of document.getElementsByName(name)) {
if (radio !== event.target) {
storage.setValue(
radio.parentNode.getAttribute("data-annotation-id"),
false
);
}
}
storage.setValue(id, event.target.checked);
});

this.container.appendChild(element);
return this.container;
}
Expand Down
187 changes: 152 additions & 35 deletions test/unit/annotation_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1622,6 +1622,92 @@ describe("annotation", function () {
}, done.fail);
});

it("should render checkboxes for printing", function (done) {
const appearanceStatesDict = new Dict();
const exportValueOptionsDict = new Dict();
const normalAppearanceDict = new Dict();
const checkedAppearanceDict = new Dict();
const uncheckedAppearanceDict = new Dict();

const checkedStream = new StringStream("0.1 0.2 0.3 rg");
checkedStream.dict = checkedAppearanceDict;

const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
uncheckedStream.dict = uncheckedAppearanceDict;

checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
checkedAppearanceDict.set("FormType", 1);
checkedAppearanceDict.set("Matrix", [1, 0, 0, 1, 0, 0]);
normalAppearanceDict.set("Checked", checkedStream);
normalAppearanceDict.set("Off", uncheckedStream);
exportValueOptionsDict.set("Off", 0);
exportValueOptionsDict.set("Checked", 1);
appearanceStatesDict.set("D", exportValueOptionsDict);
appearanceStatesDict.set("N", normalAppearanceDict);

buttonWidgetDict.set("AP", appearanceStatesDict);

const buttonWidgetRef = Ref.get(124, 0);
const xref = new XRefMock([
{ ref: buttonWidgetRef, data: buttonWidgetDict },
]);
const task = new WorkerTask("test print");

AnnotationFactory.create(
xref,
buttonWidgetRef,
pdfManagerMock,
idFactoryMock
)
.then(annotation => {
const annotationStorage = {};
annotationStorage[annotation.data.id] = true;
return Promise.all([
annotation,
annotation.getOperatorList(
partialEvaluator,
task,
false,
annotationStorage
),
]);
}, done.fail)
.then(([annotation, opList]) => {
expect(opList.argsArray.length).toEqual(3);
expect(opList.fnArray).toEqual([
OPS.beginAnnotation,
OPS.setFillRGBColor,
OPS.endAnnotation,
]);
expect(opList.argsArray[1]).toEqual(
new Uint8ClampedArray([26, 51, 76])
);
return annotation;
}, done.fail)
.then(annotation => {
const annotationStorage = {};
annotationStorage[annotation.data.id] = false;
return annotation.getOperatorList(
partialEvaluator,
task,
false,
annotationStorage
);
}, done.fail)
.then(opList => {
expect(opList.argsArray.length).toEqual(3);
expect(opList.fnArray).toEqual([
OPS.beginAnnotation,
OPS.setFillRGBColor,
OPS.endAnnotation,
]);
expect(opList.argsArray[1]).toEqual(
new Uint8ClampedArray([76, 51, 26])
);
done();
}, done.fail);
});

it("should handle radio buttons with a field value", function (done) {
const parentDict = new Dict();
parentDict.set("V", Name.get("1"));
Expand Down Expand Up @@ -1656,24 +1742,60 @@ describe("annotation", function () {
}, done.fail);
});

it("should render checkboxes for printing", function (done) {
it("should handle radio buttons without a field value", function (done) {
const normalAppearanceStateDict = new Dict();
normalAppearanceStateDict.set("2", null);

const appearanceStatesDict = new Dict();
appearanceStatesDict.set("N", normalAppearanceStateDict);

buttonWidgetDict.set("Ff", AnnotationFieldFlag.RADIO);
buttonWidgetDict.set("AP", appearanceStatesDict);

const buttonWidgetRef = Ref.get(124, 0);
const xref = new XRefMock([
{ ref: buttonWidgetRef, data: buttonWidgetDict },
]);

AnnotationFactory.create(
xref,
buttonWidgetRef,
pdfManagerMock,
idFactoryMock
).then(({ data }) => {
expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.checkBox).toEqual(false);
expect(data.radioButton).toEqual(true);
expect(data.fieldValue).toEqual(null);
expect(data.buttonValue).toEqual("2");
done();
}, done.fail);
});

it("should render radio buttons for printing", function (done) {
const appearanceStatesDict = new Dict();
const exportValueOptionsDict = new Dict();
const normalAppearanceDict = new Dict();
const checkedAppearanceDict = new Dict();
const uncheckedAppearanceDict = new Dict();

const stream = new StringStream("0.1 0.2 0.3 rg");
stream.dict = checkedAppearanceDict;
const checkedStream = new StringStream("0.1 0.2 0.3 rg");
checkedStream.dict = checkedAppearanceDict;

const uncheckedStream = new StringStream("0.3 0.2 0.1 rg");
uncheckedStream.dict = uncheckedAppearanceDict;

checkedAppearanceDict.set("BBox", [0, 0, 8, 8]);
checkedAppearanceDict.set("FormType", 1);
checkedAppearanceDict.set("Matrix", [1, 0, 0, 1, 0, 0]);
normalAppearanceDict.set("Checked", stream);
normalAppearanceDict.set("Checked", checkedStream);
normalAppearanceDict.set("Off", uncheckedStream);
exportValueOptionsDict.set("Off", 0);
exportValueOptionsDict.set("Checked", 1);
appearanceStatesDict.set("D", exportValueOptionsDict);
appearanceStatesDict.set("N", normalAppearanceDict);

buttonWidgetDict.set("Ff", AnnotationFieldFlag.RADIO);
buttonWidgetDict.set("AP", appearanceStatesDict);

const buttonWidgetRef = Ref.get(124, 0);
Expand All @@ -1691,6 +1813,31 @@ describe("annotation", function () {
.then(annotation => {
const annotationStorage = {};
annotationStorage[annotation.data.id] = true;
return Promise.all([
annotation,
annotation.getOperatorList(
partialEvaluator,
task,
false,
annotationStorage
),
]);
}, done.fail)
.then(([annotation, opList]) => {
expect(opList.argsArray.length).toEqual(3);
expect(opList.fnArray).toEqual([
OPS.beginAnnotation,
OPS.setFillRGBColor,
OPS.endAnnotation,
]);
expect(opList.argsArray[1]).toEqual(
new Uint8ClampedArray([26, 51, 76])
);
return annotation;
}, done.fail)
.then(annotation => {
const annotationStorage = {};
annotationStorage[annotation.data.id] = false;
return annotation.getOperatorList(
partialEvaluator,
task,
Expand All @@ -1706,41 +1853,11 @@ describe("annotation", function () {
OPS.endAnnotation,
]);
expect(opList.argsArray[1]).toEqual(
new Uint8ClampedArray([26, 51, 76])
new Uint8ClampedArray([76, 51, 26])
);
done();
}, done.fail);
});

it("should handle radio buttons without a field value", function (done) {
const normalAppearanceStateDict = new Dict();
normalAppearanceStateDict.set("2", null);

const appearanceStatesDict = new Dict();
appearanceStatesDict.set("N", normalAppearanceStateDict);

buttonWidgetDict.set("Ff", AnnotationFieldFlag.RADIO);
buttonWidgetDict.set("AP", appearanceStatesDict);

const buttonWidgetRef = Ref.get(124, 0);
const xref = new XRefMock([
{ ref: buttonWidgetRef, data: buttonWidgetDict },
]);

AnnotationFactory.create(
xref,
buttonWidgetRef,
pdfManagerMock,
idFactoryMock
).then(({ data }) => {
expect(data.annotationType).toEqual(AnnotationType.WIDGET);
expect(data.checkBox).toEqual(false);
expect(data.radioButton).toEqual(true);
expect(data.fieldValue).toEqual(null);
expect(data.buttonValue).toEqual("2");
done();
}, done.fail);
});
});

describe("ChoiceWidgetAnnotation", function () {
Expand Down

0 comments on commit 5a66c56

Please sign in to comment.