mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-08-04 05:17:24 +02:00
Merge pull request #21687 from calixteman/fix/quad-regex-delete-word
Scan backwards to delete a word in a text field
This commit is contained in:
commit
d0779c411e
@ -1811,11 +1811,21 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
switch (event.inputType) {
|
switch (event.inputType) {
|
||||||
// https://rawgit.com/w3c/input-events/v1/index.html#interface-InputEvent-Attributes
|
// https://rawgit.com/w3c/input-events/v1/index.html#interface-InputEvent-Attributes
|
||||||
case "deleteWordBackward": {
|
case "deleteWordBackward": {
|
||||||
const match = value
|
// The previous unanchored regex could take quadratic time, so
|
||||||
.substring(0, selectionStart)
|
// scan backwards over the trailing non-word characters and
|
||||||
.match(/\w*\W*$/);
|
// then the word.
|
||||||
if (match) {
|
const wordCharPattern = /\w/;
|
||||||
selStart -= match[0].length;
|
while (
|
||||||
|
selStart > 0 &&
|
||||||
|
!wordCharPattern.test(value[selStart - 1])
|
||||||
|
) {
|
||||||
|
selStart--;
|
||||||
|
}
|
||||||
|
while (
|
||||||
|
selStart > 0 &&
|
||||||
|
wordCharPattern.test(value[selStart - 1])
|
||||||
|
) {
|
||||||
|
selStart--;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1204,6 +1204,69 @@ describe("Interaction", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("must efficiently delete a word from a large field", async () => {
|
||||||
|
const nonWordLength = 200000;
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
await waitForScripting(page);
|
||||||
|
|
||||||
|
const result = await page.$eval(
|
||||||
|
getSelector("27R"),
|
||||||
|
(element, length) => {
|
||||||
|
element.value = `${"!".repeat(length)}a`;
|
||||||
|
element.setSelectionRange(
|
||||||
|
element.value.length,
|
||||||
|
element.value.length
|
||||||
|
);
|
||||||
|
|
||||||
|
const eventBus = window.PDFViewerApplication.eventBus;
|
||||||
|
const eventBusPrototype = Object.getPrototypeOf(eventBus);
|
||||||
|
const originalDispatch = eventBusPrototype.dispatch;
|
||||||
|
let selection;
|
||||||
|
eventBusPrototype.dispatch = function (eventName, data) {
|
||||||
|
if (
|
||||||
|
this === eventBus &&
|
||||||
|
eventName === "dispatcheventinsandbox"
|
||||||
|
) {
|
||||||
|
const { selEnd, selStart } = data.detail;
|
||||||
|
selection = { selEnd, selStart };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
originalDispatch.call(this, eventName, data);
|
||||||
|
};
|
||||||
|
|
||||||
|
const event = new InputEvent("beforeinput", {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
inputType: "deleteWordBackward",
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
const startTime = performance.now();
|
||||||
|
element.dispatchEvent(event);
|
||||||
|
return {
|
||||||
|
duration: performance.now() - startTime,
|
||||||
|
selection,
|
||||||
|
};
|
||||||
|
} finally {
|
||||||
|
eventBusPrototype.dispatch = originalDispatch;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
nonWordLength
|
||||||
|
);
|
||||||
|
expect(result.selection)
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toEqual({
|
||||||
|
selEnd: nonWordLength + 1,
|
||||||
|
selStart: nonWordLength,
|
||||||
|
});
|
||||||
|
expect(result.duration)
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toBeLessThan(1000);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("must check that an infinite loop is not triggered", async () => {
|
it("must check that an infinite loop is not triggered", async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user