Skip to content

Commit 6dc8d1f

Browse files
authored
Merge pull request #15057 from Snuffleupagus/issue-15056
Replace element `id`s with custom attributes for Widget-annotations (issue 15056)
2 parents 3ca8d2c + 03757d8 commit 6dc8d1f

File tree

5 files changed

+425
-384
lines changed

5 files changed

+425
-384
lines changed

src/display/annotation_layer.js

+19-11
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,9 @@ class AnnotationElement {
522522
const exportValue =
523523
typeof exportValues === "string" ? exportValues : null;
524524

525-
const domElement = document.getElementById(id);
525+
const domElement = document.querySelector(
526+
`[data-element-id="${id}"]`
527+
);
526528
if (domElement && !GetElementsByNameSet.has(domElement)) {
527529
warn(`_getElementsByName - element not allowed: ${id}`);
528530
continue;
@@ -570,7 +572,7 @@ class LinkAnnotationElement extends AnnotationElement {
570572
render() {
571573
const { data, linkService } = this;
572574
const link = document.createElement("a");
573-
link.setAttribute("id", data.id);
575+
link.setAttribute("data-element-id", data.id);
574576
let isBound = false;
575577

576578
if (data.url) {
@@ -775,8 +777,12 @@ class LinkAnnotationElement extends AnnotationElement {
775777
default:
776778
continue;
777779
}
778-
const domElement = document.getElementById(id);
779-
if (!domElement || !GetElementsByNameSet.has(domElement)) {
780+
781+
const domElement = document.querySelector(`[data-element-id="${id}"]`);
782+
if (!domElement) {
783+
continue;
784+
} else if (!GetElementsByNameSet.has(domElement)) {
785+
warn(`_bindResetFormAction - element not allowed: ${id}`);
780786
continue;
781787
}
782788
domElement.dispatchEvent(new Event("resetform"));
@@ -989,7 +995,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
989995
});
990996
const textContent = storedData.formattedValue || storedData.value || "";
991997
const elementData = {
992-
userValue: null,
998+
userValue: textContent,
993999
formattedValue: null,
9941000
valueOnFocus: "",
9951001
};
@@ -1009,13 +1015,12 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
10091015
}
10101016
}
10111017
GetElementsByNameSet.add(element);
1018+
element.setAttribute("data-element-id", id);
1019+
10121020
element.disabled = this.data.readOnly;
10131021
element.name = this.data.fieldName;
10141022
element.tabIndex = DEFAULT_TAB_INDEX;
10151023

1016-
elementData.userValue = textContent;
1017-
element.setAttribute("id", id);
1018-
10191024
this._setRequired(element, this.data.required);
10201025

10211026
element.addEventListener("input", event => {
@@ -1262,14 +1267,15 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
12621267

12631268
const element = document.createElement("input");
12641269
GetElementsByNameSet.add(element);
1270+
element.setAttribute("data-element-id", id);
1271+
12651272
element.disabled = data.readOnly;
12661273
this._setRequired(element, this.data.required);
12671274
element.type = "checkbox";
12681275
element.name = data.fieldName;
12691276
if (value) {
12701277
element.setAttribute("checked", true);
12711278
}
1272-
element.setAttribute("id", id);
12731279
element.setAttribute("exportValue", data.exportValue);
12741280
element.tabIndex = DEFAULT_TAB_INDEX;
12751281

@@ -1346,14 +1352,15 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
13461352

13471353
const element = document.createElement("input");
13481354
GetElementsByNameSet.add(element);
1355+
element.setAttribute("data-element-id", id);
1356+
13491357
element.disabled = data.readOnly;
13501358
this._setRequired(element, this.data.required);
13511359
element.type = "radio";
13521360
element.name = data.fieldName;
13531361
if (value) {
13541362
element.setAttribute("checked", true);
13551363
}
1356-
element.setAttribute("id", id);
13571364
element.tabIndex = DEFAULT_TAB_INDEX;
13581365

13591366
element.addEventListener("change", event => {
@@ -1463,10 +1470,11 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
14631470

14641471
const selectElement = document.createElement("select");
14651472
GetElementsByNameSet.add(selectElement);
1473+
selectElement.setAttribute("data-element-id", id);
1474+
14661475
selectElement.disabled = this.data.readOnly;
14671476
this._setRequired(selectElement, this.data.required);
14681477
selectElement.name = this.data.fieldName;
1469-
selectElement.setAttribute("id", id);
14701478
selectElement.tabIndex = DEFAULT_TAB_INDEX;
14711479

14721480
let addAnEmptyEntry = this.data.combo && this.data.options.length > 0;

test/integration/annotation_spec.js

+54-51
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,12 @@
1313
* limitations under the License.
1414
*/
1515

16-
const { closePages, loadAndWait } = require("./test_utils.js");
16+
const {
17+
closePages,
18+
getSelector,
19+
getQuerySelector,
20+
loadAndWait,
21+
} = require("./test_utils.js");
1722

1823
describe("Annotation highlight", () => {
1924
describe("annotation-highlight.pdf", () => {
@@ -108,18 +113,14 @@ describe("Text widget", () => {
108113
const base = "hello world";
109114
await Promise.all(
110115
pages.map(async ([browserName, page]) => {
111-
await page.type("#\\32 5R", base);
112-
await page.waitForFunction(
113-
`document.querySelector("#\\\\32 4R").value !== ""`
114-
);
115-
await page.waitForFunction(
116-
`document.querySelector("#\\\\32 6R").value !== ""`
117-
);
116+
await page.type(getSelector("25R"), base);
117+
await page.waitForFunction(`${getQuerySelector("24R")}.value !== ""`);
118+
await page.waitForFunction(`${getQuerySelector("26R")}.value !== ""`);
118119

119-
let text = await page.$eval("#\\32 4R", el => el.value);
120+
let text = await page.$eval(getSelector("24R"), el => el.value);
120121
expect(text).withContext(`In ${browserName}`).toEqual(base);
121122

122-
text = await page.$eval("#\\32 6R", el => el.value);
123+
text = await page.$eval(getSelector("26R"), el => el.value);
123124
expect(text).withContext(`In ${browserName}`).toEqual(base);
124125
})
125126
);
@@ -145,15 +146,15 @@ describe("Annotation and storage", () => {
145146
await Promise.all(
146147
pages.map(async ([browserName, page]) => {
147148
// Text field.
148-
await page.type("#\\36 4R", text1);
149+
await page.type(getSelector("64R"), text1);
149150
// Checkbox.
150151
await page.click("[data-annotation-id='65R']");
151152
// Radio.
152153
await page.click("[data-annotation-id='67R']");
153154

154155
for (const [pageNumber, textId, checkId, radio1Id, radio2Id] of [
155-
[2, "#\\31 8R", "#\\31 9R", "#\\32 1R", "#\\32 0R"],
156-
[5, "#\\32 3R", "#\\32 4R", "#\\32 2R", "#\\32 5R"],
156+
[2, "18R", "19R", "21R", "20R"],
157+
[5, "23R", "24R", "22R", "25R"],
157158
]) {
158159
await page.evaluate(n => {
159160
window.document
@@ -162,34 +163,37 @@ describe("Annotation and storage", () => {
162163
}, pageNumber);
163164

164165
// Need to wait to have a displayed text input.
165-
await page.waitForSelector(textId, {
166+
await page.waitForSelector(getSelector(textId), {
166167
timeout: 0,
167168
});
168169

169-
const text = await page.$eval(textId, el => el.value);
170+
const text = await page.$eval(getSelector(textId), el => el.value);
170171
expect(text).withContext(`In ${browserName}`).toEqual(text1);
171172

172-
let checked = await page.$eval(checkId, el => el.checked);
173+
let checked = await page.$eval(
174+
getSelector(checkId),
175+
el => el.checked
176+
);
173177
expect(checked).toEqual(true);
174178

175-
checked = await page.$eval(radio1Id, el => el.checked);
179+
checked = await page.$eval(getSelector(radio1Id), el => el.checked);
176180
expect(checked).toEqual(false);
177181

178-
checked = await page.$eval(radio2Id, el => el.checked);
182+
checked = await page.$eval(getSelector(radio2Id), el => el.checked);
179183
expect(checked).toEqual(false);
180184
}
181185

182186
// Change data on page 5 and check that other pages changed.
183187
// Text field.
184-
await page.type("#\\32 3R", text2);
188+
await page.type(getSelector("23R"), text2);
185189
// Checkbox.
186190
await page.click("[data-annotation-id='24R']");
187191
// Radio.
188192
await page.click("[data-annotation-id='25R']");
189193

190194
for (const [pageNumber, textId, checkId, radio1Id, radio2Id] of [
191-
[1, "#\\36 4R", "#\\36 5R", "#\\36 7R", "#\\36 8R"],
192-
[2, "#\\31 8R", "#\\31 9R", "#\\32 1R", "#\\32 0R"],
195+
[1, "64R", "65R", "67R", "68R"],
196+
[2, "18R", "19R", "21R", "20R"],
193197
]) {
194198
await page.evaluate(n => {
195199
window.document
@@ -198,22 +202,25 @@ describe("Annotation and storage", () => {
198202
}, pageNumber);
199203

200204
// Need to wait to have a displayed text input.
201-
await page.waitForSelector(textId, {
205+
await page.waitForSelector(getSelector(textId), {
202206
timeout: 0,
203207
});
204208

205-
const text = await page.$eval(textId, el => el.value);
209+
const text = await page.$eval(getSelector(textId), el => el.value);
206210
expect(text)
207211
.withContext(`In ${browserName}`)
208212
.toEqual(text2 + text1);
209213

210-
let checked = await page.$eval(checkId, el => el.checked);
214+
let checked = await page.$eval(
215+
getSelector(checkId),
216+
el => el.checked
217+
);
211218
expect(checked).toEqual(false);
212219

213-
checked = await page.$eval(radio1Id, el => el.checked);
220+
checked = await page.$eval(getSelector(radio1Id), el => el.checked);
214221
expect(checked).toEqual(false);
215222

216-
checked = await page.$eval(radio2Id, el => el.checked);
223+
checked = await page.$eval(getSelector(radio2Id), el => el.checked);
217224
expect(checked).toEqual(false);
218225
}
219226
})
@@ -238,8 +245,8 @@ describe("ResetForm action", () => {
238245
await Promise.all(
239246
pages.map(async ([browserName, page]) => {
240247
const base = "hello world";
241-
for (let i = 3; i <= 7; i++) {
242-
await page.type(`#\\36 ${i}R`, base);
248+
for (let i = 63; i <= 67; i++) {
249+
await page.type(getSelector(`${i}R`), base);
243250
}
244251

245252
const selectors = [69, 71, 75].map(
@@ -249,36 +256,34 @@ describe("ResetForm action", () => {
249256
await page.click(selector);
250257
}
251258

252-
await page.select("#\\37 8R", "b");
253-
await page.select("#\\38 1R", "f");
259+
await page.select(getSelector("78R"), "b");
260+
await page.select(getSelector("81R"), "f");
254261

255262
await page.click("[data-annotation-id='82R']");
256-
await page.waitForFunction(
257-
`document.querySelector("#\\\\36 3R").value === ""`
258-
);
263+
await page.waitForFunction(`${getQuerySelector("63R")}.value === ""`);
259264

260-
for (let i = 3; i <= 8; i++) {
261-
const text = await page.$eval(`#\\36 ${i}R`, el => el.value);
265+
for (let i = 63; i <= 68; i++) {
266+
const text = await page.$eval(getSelector(`${i}R`), el => el.value);
262267
expect(text).withContext(`In ${browserName}`).toEqual("");
263268
}
264269

265270
const ids = [69, 71, 72, 73, 74, 75, 76, 77];
266271
for (const id of ids) {
267272
const checked = await page.$eval(
268-
`#\\3${Math.floor(id / 10)} ${id % 10}R`,
273+
getSelector(`${id}R`),
269274
el => el.checked
270275
);
271276
expect(checked).withContext(`In ${browserName}`).toEqual(false);
272277
}
273278

274279
let selected = await page.$eval(
275-
`#\\37 8R [value="a"]`,
280+
`${getSelector("78R")} [value="a"]`,
276281
el => el.selected
277282
);
278283
expect(selected).withContext(`In ${browserName}`).toEqual(true);
279284

280285
selected = await page.$eval(
281-
`#\\38 1R [value="d"]`,
286+
`${getSelector("81R")} [value="d"]`,
282287
el => el.selected
283288
);
284289
expect(selected).withContext(`In ${browserName}`).toEqual(true);
@@ -290,8 +295,8 @@ describe("ResetForm action", () => {
290295
await Promise.all(
291296
pages.map(async ([browserName, page]) => {
292297
const base = "hello world";
293-
for (let i = 3; i <= 8; i++) {
294-
await page.type(`#\\36 ${i}R`, base);
298+
for (let i = 63; i <= 68; i++) {
299+
await page.type(getSelector(`${i}R`), base);
295300
}
296301

297302
const selectors = [69, 71, 72, 73, 75].map(
@@ -301,24 +306,22 @@ describe("ResetForm action", () => {
301306
await page.click(selector);
302307
}
303308

304-
await page.select("#\\37 8R", "b");
305-
await page.select("#\\38 1R", "f");
309+
await page.select(getSelector("78R"), "b");
310+
await page.select(getSelector("81R"), "f");
306311

307312
await page.click("[data-annotation-id='84R']");
308-
await page.waitForFunction(
309-
`document.querySelector("#\\\\36 3R").value === ""`
310-
);
313+
await page.waitForFunction(`${getQuerySelector("63R")}.value === ""`);
311314

312-
for (let i = 3; i <= 8; i++) {
315+
for (let i = 63; i <= 68; i++) {
313316
const expected = (i - 3) % 2 === 0 ? "" : base;
314-
const text = await page.$eval(`#\\36 ${i}R`, el => el.value);
317+
const text = await page.$eval(getSelector(`${i}R`), el => el.value);
315318
expect(text).withContext(`In ${browserName}`).toEqual(expected);
316319
}
317320

318321
let ids = [69, 72, 73, 74, 76, 77];
319322
for (const id of ids) {
320323
const checked = await page.$eval(
321-
`#\\3${Math.floor(id / 10)} ${id % 10}R`,
324+
getSelector(`${id}R`),
322325
el => el.checked
323326
);
324327
expect(checked)
@@ -329,20 +332,20 @@ describe("ResetForm action", () => {
329332
ids = [71, 75];
330333
for (const id of ids) {
331334
const checked = await page.$eval(
332-
`#\\3${Math.floor(id / 10)} ${id % 10}R`,
335+
getSelector(`${id}R`),
333336
el => el.checked
334337
);
335338
expect(checked).withContext(`In ${browserName}`).toEqual(true);
336339
}
337340

338341
let selected = await page.$eval(
339-
`#\\37 8R [value="a"]`,
342+
`${getSelector("78R")} [value="a"]`,
340343
el => el.selected
341344
);
342345
expect(selected).withContext(`In ${browserName}`).toEqual(true);
343346

344347
selected = await page.$eval(
345-
`#\\38 1R [value="f"]`,
348+
`${getSelector("81R")} [value="f"]`,
346349
el => el.selected
347350
);
348351
expect(selected).withContext(`In ${browserName}`).toEqual(true);

0 commit comments

Comments
 (0)