From 4a5f1d1b7aa0e0576fc21c455555bb0923978186 Mon Sep 17 00:00:00 2001 From: Calixte Denizet Date: Sat, 20 Feb 2021 15:23:54 +0100 Subject: [PATCH] JS - Fix setting a color on an annotation - strokeColor corresponds to borderColor; - support fillColor and textColor; - support colors on the different annotations; - fix typo in aforms (+test). --- src/display/annotation_layer.js | 45 +++++++++++++++++++++----- src/scripting_api/aform.js | 2 +- src/scripting_api/field.js | 24 ++++++++++++++ test/integration/scripting_spec.js | 49 +++++++++++++++++++++++++++++ test/pdfs/.gitignore | 1 + test/pdfs/js-colors.pdf | Bin 0 -> 10380 bytes test/unit/scripting_spec.js | 12 +++++++ 7 files changed, 125 insertions(+), 8 deletions(-) create mode 100644 test/pdfs/js-colors.pdf diff --git a/src/display/annotation_layer.js b/src/display/annotation_layer.js index af1d98343..1e0eb863a 100644 --- a/src/display/annotation_layer.js +++ b/src/display/annotation_layer.js @@ -582,6 +582,39 @@ class WidgetAnnotationElement extends AnnotationElement { } } } + + _setColor(event) { + const { detail, target } = event; + const { style } = target; + for (const name of [ + "bgColor", + "fillColor", + "fgColor", + "textColor", + "borderColor", + "strokeColor", + ]) { + let color = detail[name]; + if (!color) { + continue; + } + color = ColorConverters[`${color[0]}_HTML`](color.slice(1)); + switch (name) { + case "bgColor": + case "fillColor": + style.backgroundColor = color; + break; + case "fgColor": + case "textColor": + style.color = color; + break; + case "borderColor": + case "strokeColor": + style.borderColor = color; + break; + } + } + } } class TextWidgetAnnotationElement extends WidgetAnnotationElement { @@ -644,7 +677,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement { } }); - element.addEventListener("updatefromsandbox", function (event) { + element.addEventListener("updatefromsandbox", event => { const { detail } = event; const actions = { value() { @@ -686,16 +719,11 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement { event.target.setSelectionRange(selStart, selEnd); } }, - strokeColor() { - const color = detail.strokeColor; - event.target.style.color = ColorConverters[`${color[0]}_HTML`]( - color.slice(1) - ); - }, }; Object.keys(detail) .filter(name => name in actions) .forEach(name => actions[name]()); + this._setColor(event); }); // Even if the field hasn't any actions @@ -929,6 +957,7 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement { Object.keys(detail) .filter(name => name in actions) .forEach(name => actions[name]()); + this._setColor(event); }); this._setEventListeners( @@ -1018,6 +1047,7 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement { Object.keys(detail) .filter(name => name in actions) .forEach(name => actions[name]()); + this._setColor(event); }); this._setEventListeners( @@ -1226,6 +1256,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement { Object.keys(detail) .filter(name => name in actions) .forEach(name => actions[name]()); + this._setColor(event); }); selectElement.addEventListener("input", event => { diff --git a/src/scripting_api/aform.js b/src/scripting_api/aform.js index ee61a4f80..f5de721cf 100644 --- a/src/scripting_api/aform.js +++ b/src/scripting_api/aform.js @@ -529,7 +529,7 @@ class AForm { event.rc = false; return; } - event.value += cMask.subString(value.length); + event.value += cMask.substring(value.length); return; } diff --git a/src/scripting_api/field.js b/src/scripting_api/field.js index 6fa16adad..3435957a8 100644 --- a/src/scripting_api/field.js +++ b/src/scripting_api/field.js @@ -140,6 +140,14 @@ class Field extends PDFObject { } } + get bgColor() { + return this.fillColor; + } + + set bgColor(color) { + this.fillColor = color; + } + get numItems() { if (!this._isChoice) { throw new Error("Not a choice widget"); @@ -161,6 +169,14 @@ class Field extends PDFObject { } } + get borderColor() { + return this.strokeColor; + } + + set borderColor(color) { + this.strokeColor = color; + } + get textColor() { return this._textColor; } @@ -171,6 +187,14 @@ class Field extends PDFObject { } } + get fgColor() { + return this.textColor; + } + + set fgColor(color) { + this.textColor = color; + } + get value() { return this._value; } diff --git a/test/integration/scripting_spec.js b/test/integration/scripting_spec.js index 2fedfc7a3..ecae8f4df 100644 --- a/test/integration/scripting_spec.js +++ b/test/integration/scripting_spec.js @@ -630,4 +630,53 @@ describe("Interaction", () => { ); }); }); + + describe("in js-colors.pdf", () => { + let pages; + + beforeAll(async () => { + pages = await loadAndWait("js-colors.pdf", "#\\33 4R"); + }); + + it("must changes colors", async () => { + await Promise.all( + pages.map(async ([browserName, page]) => { + for (const [name, ref] of [ + ["Text1", "#\\33 4R"], + ["Check1", "#\\33 5R"], + ["Radio1", "#\\33 7R"], + ["Choice1", "#\\33 8R"], + ]) { + await clearInput(page, "#\\33 4R"); + await page.type("#\\33 4R", `${name}`, { + delay: 10, + }); + await page.click("[data-annotation-id='41R']"); + let color = await page.$eval( + ref, + el => getComputedStyle(el).backgroundColor + ); + expect(color) + .withContext(`In ${browserName}`) + .toEqual("rgb(255, 0, 0)"); + + await page.click("[data-annotation-id='43R']"); + color = await page.$eval(ref, el => getComputedStyle(el).color); + expect(color) + .withContext(`In ${browserName}`) + .toEqual("rgb(0, 255, 0)"); + + await page.click("[data-annotation-id='44R']"); + color = await page.$eval( + ref, + el => getComputedStyle(el)["border-top-color"] + ); + expect(color) + .withContext(`In ${browserName}`) + .toEqual("rgb(0, 0, 255)"); + } + }) + ); + }); + }); }); diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index ddb5fcee3..f5e03e23c 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -245,6 +245,7 @@ !personwithdog.pdf !helloworld-bad.pdf !zerowidthline.pdf +!js-colors.pdf !issue12841_reduced.pdf !bug868745.pdf !mmtype1.pdf diff --git a/test/pdfs/js-colors.pdf b/test/pdfs/js-colors.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5bf827353002352dfa3f38ffb491f4fd1bc8f9cf GIT binary patch literal 10380 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 literal 0 HcmV?d00001 diff --git a/test/unit/scripting_spec.js b/test/unit/scripting_spec.js index 9c5ca4460..9841f895e 100644 --- a/test/unit/scripting_spec.js +++ b/test/unit/scripting_spec.js @@ -1166,6 +1166,18 @@ describe("Scripting", function () { value: "3F?", selRange: [3, 3], }); + + send_queue.delete(refId); + await sandbox.dispatchEventInSandbox({ + id: refId, + value: "3F?", + change: "0", + name: "Keystroke", + willCommit: true, + selStart: 3, + selEnd: 3, + }); + expect(send_queue.has(refId)).toEqual(false); }); });