Merge pull request #12635 from calixteman/js_display_evts
JS -- Send events to the sandbox from annotation layer
This commit is contained in:
commit
3c603fb28b
@ -365,7 +365,11 @@ class LinkAnnotationElement extends AnnotationElement {
|
|||||||
parameters.data.url ||
|
parameters.data.url ||
|
||||||
parameters.data.dest ||
|
parameters.data.dest ||
|
||||||
parameters.data.action ||
|
parameters.data.action ||
|
||||||
parameters.data.isTooltipOnly
|
parameters.data.isTooltipOnly ||
|
||||||
|
(parameters.data.actions &&
|
||||||
|
(parameters.data.actions.Action ||
|
||||||
|
parameters.data.actions.MouseUp ||
|
||||||
|
parameters.data.actions.MouseDown))
|
||||||
);
|
);
|
||||||
super(parameters, { isRenderable, createQuadrilaterals: true });
|
super(parameters, { isRenderable, createQuadrilaterals: true });
|
||||||
}
|
}
|
||||||
@ -387,6 +391,13 @@ class LinkAnnotationElement extends AnnotationElement {
|
|||||||
this._bindNamedAction(link, data.action);
|
this._bindNamedAction(link, data.action);
|
||||||
} else if (data.dest) {
|
} else if (data.dest) {
|
||||||
this._bindLink(link, data.dest);
|
this._bindLink(link, data.dest);
|
||||||
|
} else if (
|
||||||
|
data.actions &&
|
||||||
|
(data.actions.Action || data.actions.MouseUp || data.actions.MouseDown) &&
|
||||||
|
this.enableScripting &&
|
||||||
|
this.hasJSActions
|
||||||
|
) {
|
||||||
|
this._bindJSAction(link);
|
||||||
} else {
|
} else {
|
||||||
this._bindLink(link, "");
|
this._bindLink(link, "");
|
||||||
}
|
}
|
||||||
@ -443,6 +454,42 @@ class LinkAnnotationElement extends AnnotationElement {
|
|||||||
};
|
};
|
||||||
link.className = "internalLink";
|
link.className = "internalLink";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bind JS actions to the link element.
|
||||||
|
*
|
||||||
|
* @private
|
||||||
|
* @param {Object} link
|
||||||
|
* @param {Object} data
|
||||||
|
* @memberof LinkAnnotationElement
|
||||||
|
*/
|
||||||
|
_bindJSAction(link) {
|
||||||
|
link.href = this.linkService.getAnchorUrl("#");
|
||||||
|
const { data } = this;
|
||||||
|
const map = new Map([
|
||||||
|
["Action", "onclick"],
|
||||||
|
["MouseUp", "onmouseup"],
|
||||||
|
["MouseDown", "onmousedown"],
|
||||||
|
]);
|
||||||
|
for (const name of Object.keys(data.actions)) {
|
||||||
|
const jsName = map.get(name);
|
||||||
|
if (!jsName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
link[jsName] = () => {
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("dispatchEventInSandbox", {
|
||||||
|
detail: {
|
||||||
|
id: data.id,
|
||||||
|
name,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
link.className = "internalLink";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TextAnnotationElement extends AnnotationElement {
|
class TextAnnotationElement extends AnnotationElement {
|
||||||
@ -488,6 +535,53 @@ class WidgetAnnotationElement extends AnnotationElement {
|
|||||||
|
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_getKeyModifier(event) {
|
||||||
|
return (
|
||||||
|
(navigator.platform.includes("Win") && event.ctrlKey) ||
|
||||||
|
(navigator.platform.includes("Mac") && event.metaKey)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_setEventListener(element, baseName, eventName, valueGetter) {
|
||||||
|
if (this.data.actions && eventName.replace(" ", "") in this.data.actions) {
|
||||||
|
if (baseName.includes("mouse")) {
|
||||||
|
// Mouse events
|
||||||
|
element.addEventListener(baseName, event => {
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("dispatchEventInSandbox", {
|
||||||
|
detail: {
|
||||||
|
id: this.data.id,
|
||||||
|
name: eventName,
|
||||||
|
value: valueGetter(event),
|
||||||
|
shift: event.shiftKey,
|
||||||
|
modifier: this._getKeyModifier(event),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Non mouse event
|
||||||
|
element.addEventListener(baseName, event => {
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("dispatchEventInSandbox", {
|
||||||
|
detail: {
|
||||||
|
id: this.data.id,
|
||||||
|
name: eventName,
|
||||||
|
value: event.target.checked,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_setEventListeners(element, names, getter) {
|
||||||
|
for (const [baseName, eventName] of names) {
|
||||||
|
this._setEventListener(element, baseName, eventName, getter);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
||||||
@ -496,6 +590,7 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
parameters.renderInteractiveForms ||
|
parameters.renderInteractiveForms ||
|
||||||
(!parameters.data.hasAppearance && !!parameters.data.fieldValue);
|
(!parameters.data.hasAppearance && !!parameters.data.fieldValue);
|
||||||
super(parameters, { isRenderable });
|
super(parameters, { isRenderable });
|
||||||
|
this.mouseState = parameters.mouseState;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
@ -513,6 +608,12 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
const textContent = storage.getOrCreateValue(id, {
|
const textContent = storage.getOrCreateValue(id, {
|
||||||
value: this.data.fieldValue,
|
value: this.data.fieldValue,
|
||||||
}).value;
|
}).value;
|
||||||
|
const elementData = {
|
||||||
|
userValue: null,
|
||||||
|
formattedValue: null,
|
||||||
|
beforeInputSelectionRange: null,
|
||||||
|
beforeInputValue: null,
|
||||||
|
};
|
||||||
|
|
||||||
if (this.data.multiLine) {
|
if (this.data.multiLine) {
|
||||||
element = document.createElement("textarea");
|
element = document.createElement("textarea");
|
||||||
@ -523,104 +624,196 @@ class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
element.setAttribute("value", textContent);
|
element.setAttribute("value", textContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
element.userValue = textContent;
|
elementData.userValue = textContent;
|
||||||
element.setAttribute("id", id);
|
element.setAttribute("id", id);
|
||||||
|
|
||||||
element.addEventListener("input", function (event) {
|
element.addEventListener("input", function (event) {
|
||||||
storage.setValue(id, { value: event.target.value });
|
storage.setValue(id, { value: event.target.value });
|
||||||
});
|
});
|
||||||
|
|
||||||
element.addEventListener("blur", function (event) {
|
let blurListener = event => {
|
||||||
|
if (elementData.formattedValue) {
|
||||||
|
event.target.value = elementData.formattedValue;
|
||||||
|
}
|
||||||
event.target.setSelectionRange(0, 0);
|
event.target.setSelectionRange(0, 0);
|
||||||
});
|
elementData.beforeInputSelectionRange = null;
|
||||||
|
};
|
||||||
|
|
||||||
if (this.enableScripting && this.hasJSActions) {
|
if (this.enableScripting && this.hasJSActions) {
|
||||||
element.addEventListener("focus", event => {
|
element.addEventListener("focus", event => {
|
||||||
if (event.target.userValue) {
|
if (elementData.userValue) {
|
||||||
event.target.value = event.target.userValue;
|
event.target.value = elementData.userValue;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.data.actions) {
|
element.addEventListener("updateFromSandbox", function (event) {
|
||||||
element.addEventListener("updateFromSandbox", function (event) {
|
const { detail } = event;
|
||||||
const detail = event.detail;
|
const actions = {
|
||||||
const actions = {
|
value() {
|
||||||
value() {
|
elementData.userValue = detail.value || "";
|
||||||
const value = detail.value;
|
storage.setValue(id, { value: elementData.userValue.toString() });
|
||||||
if (value === undefined || value === null) {
|
},
|
||||||
// remove data
|
valueAsString() {
|
||||||
event.target.userValue = "";
|
elementData.formattedValue = detail.valueAsString || "";
|
||||||
} else {
|
if (event.target !== document.activeElement) {
|
||||||
event.target.userValue = value;
|
// Input hasn't the focus so display formatted string
|
||||||
}
|
event.target.value = elementData.formattedValue;
|
||||||
},
|
|
||||||
valueAsString() {
|
|
||||||
const value = detail.valueAsString;
|
|
||||||
if (value === undefined || value === null) {
|
|
||||||
// remove data
|
|
||||||
event.target.value = "";
|
|
||||||
} else {
|
|
||||||
event.target.value = value;
|
|
||||||
}
|
|
||||||
storage.setValue(id, event.target.value);
|
|
||||||
},
|
|
||||||
focus() {
|
|
||||||
event.target.focus({ preventScroll: false });
|
|
||||||
},
|
|
||||||
userName() {
|
|
||||||
const tooltip = detail.userName;
|
|
||||||
event.target.title = tooltip;
|
|
||||||
},
|
|
||||||
hidden() {
|
|
||||||
event.target.style.display = detail.hidden ? "none" : "block";
|
|
||||||
},
|
|
||||||
editable() {
|
|
||||||
event.target.disabled = !detail.editable;
|
|
||||||
},
|
|
||||||
selRange() {
|
|
||||||
const [selStart, selEnd] = detail.selRange;
|
|
||||||
if (selStart >= 0 && selEnd < event.target.value.length) {
|
|
||||||
event.target.setSelectionRange(selStart, selEnd);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
strokeColor() {
|
|
||||||
const color = detail.strokeColor;
|
|
||||||
event.target.style.color = ColorConverters[`${color[0]}_HTML`](
|
|
||||||
color.slice(1)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
};
|
|
||||||
for (const name of Object.keys(detail)) {
|
|
||||||
if (name in actions) {
|
|
||||||
actions[name]();
|
|
||||||
}
|
}
|
||||||
|
storage.setValue(id, {
|
||||||
|
formattedValue: elementData.formattedValue,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
focus() {
|
||||||
|
setTimeout(() => event.target.focus({ preventScroll: false }), 0);
|
||||||
|
},
|
||||||
|
userName() {
|
||||||
|
// tooltip
|
||||||
|
event.target.title = detail.userName;
|
||||||
|
},
|
||||||
|
hidden() {
|
||||||
|
event.target.style.visibility = detail.hidden
|
||||||
|
? "hidden"
|
||||||
|
: "visible";
|
||||||
|
storage.setValue(id, { hidden: detail.hidden });
|
||||||
|
},
|
||||||
|
editable() {
|
||||||
|
event.target.disabled = !detail.editable;
|
||||||
|
},
|
||||||
|
selRange() {
|
||||||
|
const [selStart, selEnd] = detail.selRange;
|
||||||
|
if (selStart >= 0 && selEnd < event.target.value.length) {
|
||||||
|
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]());
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.data.actions) {
|
||||||
|
// Even if the field hasn't any actions
|
||||||
|
// leaving it can still trigger some actions with Calculate
|
||||||
|
element.addEventListener("keydown", event => {
|
||||||
|
elementData.beforeInputValue = event.target.value;
|
||||||
|
// if the key is one of Escape, Enter or Tab
|
||||||
|
// then the data are committed
|
||||||
|
let commitKey = -1;
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
commitKey = 0;
|
||||||
|
} else if (event.key === "Enter") {
|
||||||
|
commitKey = 2;
|
||||||
|
} else if (event.key === "Tab") {
|
||||||
|
commitKey = 3;
|
||||||
|
}
|
||||||
|
if (commitKey === -1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Save the entered value
|
||||||
|
elementData.userValue = event.target.value;
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("dispatchEventInSandbox", {
|
||||||
|
detail: {
|
||||||
|
id,
|
||||||
|
name: "Keystroke",
|
||||||
|
value: event.target.value,
|
||||||
|
willCommit: true,
|
||||||
|
commitKey,
|
||||||
|
selStart: event.target.selectionStart,
|
||||||
|
selEnd: event.target.selectionEnd,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
const _blurListener = blurListener;
|
||||||
|
blurListener = null;
|
||||||
|
element.addEventListener("blur", event => {
|
||||||
|
if (this.mouseState.isDown) {
|
||||||
|
// Focus out using the mouse: data are committed
|
||||||
|
elementData.userValue = event.target.value;
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("dispatchEventInSandbox", {
|
||||||
|
detail: {
|
||||||
|
id,
|
||||||
|
name: "Keystroke",
|
||||||
|
value: event.target.value,
|
||||||
|
willCommit: true,
|
||||||
|
commitKey: 1,
|
||||||
|
selStart: event.target.selectionStart,
|
||||||
|
selEnd: event.target.selectionEnd,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
_blurListener(event);
|
||||||
|
});
|
||||||
|
element.addEventListener("mousedown", event => {
|
||||||
|
elementData.beforeInputValue = event.target.value;
|
||||||
|
elementData.beforeInputSelectionRange = null;
|
||||||
|
});
|
||||||
|
element.addEventListener("keyup", event => {
|
||||||
|
// keyup is triggered after input
|
||||||
|
if (event.target.selectionStart === event.target.selectionEnd) {
|
||||||
|
elementData.beforeInputSelectionRange = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
element.addEventListener("select", event => {
|
||||||
|
elementData.beforeInputSelectionRange = [
|
||||||
|
event.target.selectionStart,
|
||||||
|
event.target.selectionEnd,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
for (const eventType of Object.keys(this.data.actions)) {
|
if ("Keystroke" in this.data.actions) {
|
||||||
switch (eventType) {
|
// We should use beforeinput but this
|
||||||
case "Format":
|
// event isn't available in Firefox
|
||||||
element.addEventListener("change", function (event) {
|
element.addEventListener("input", event => {
|
||||||
window.dispatchEvent(
|
let selStart = -1;
|
||||||
new CustomEvent("dispatchEventInSandbox", {
|
let selEnd = -1;
|
||||||
detail: {
|
if (elementData.beforeInputSelectionRange) {
|
||||||
id,
|
[selStart, selEnd] = elementData.beforeInputSelectionRange;
|
||||||
name: "Keystroke",
|
}
|
||||||
value: event.target.value,
|
window.dispatchEvent(
|
||||||
willCommit: true,
|
new CustomEvent("dispatchEventInSandbox", {
|
||||||
commitKey: 1,
|
detail: {
|
||||||
selStart: event.target.selectionStart,
|
id,
|
||||||
selEnd: event.target.selectionEnd,
|
name: "Keystroke",
|
||||||
},
|
value: elementData.beforeInputValue,
|
||||||
})
|
change: event.data,
|
||||||
);
|
willCommit: false,
|
||||||
});
|
selStart,
|
||||||
break;
|
selEnd,
|
||||||
}
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._setEventListeners(
|
||||||
|
element,
|
||||||
|
[
|
||||||
|
["focus", "Focus"],
|
||||||
|
["blur", "Blur"],
|
||||||
|
["mousedown", "Mouse Down"],
|
||||||
|
["mouseenter", "Mouse Enter"],
|
||||||
|
["mouseleave", "Mouse Exit"],
|
||||||
|
["mouseup", "MouseUp"],
|
||||||
|
],
|
||||||
|
event => event.target.value
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (blurListener) {
|
||||||
|
element.addEventListener("blur", blurListener);
|
||||||
|
}
|
||||||
|
|
||||||
element.disabled = this.data.readOnly;
|
element.disabled = this.data.readOnly;
|
||||||
element.name = this.data.fieldName;
|
element.name = this.data.fieldName;
|
||||||
|
|
||||||
@ -715,6 +908,7 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
if (value) {
|
if (value) {
|
||||||
element.setAttribute("checked", true);
|
element.setAttribute("checked", true);
|
||||||
}
|
}
|
||||||
|
element.setAttribute("id", id);
|
||||||
|
|
||||||
element.addEventListener("change", function (event) {
|
element.addEventListener("change", function (event) {
|
||||||
const name = event.target.name;
|
const name = event.target.name;
|
||||||
@ -730,6 +924,48 @@ class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
storage.setValue(id, { value: event.target.checked });
|
storage.setValue(id, { value: event.target.checked });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.enableScripting && this.hasJSActions) {
|
||||||
|
element.addEventListener("updateFromSandbox", event => {
|
||||||
|
const { detail } = event;
|
||||||
|
const actions = {
|
||||||
|
value() {
|
||||||
|
event.target.checked = detail.value !== "Off";
|
||||||
|
storage.setValue(id, { value: event.target.checked });
|
||||||
|
},
|
||||||
|
focus() {
|
||||||
|
setTimeout(() => event.target.focus({ preventScroll: false }), 0);
|
||||||
|
},
|
||||||
|
hidden() {
|
||||||
|
event.target.style.visibility = detail.hidden
|
||||||
|
? "hidden"
|
||||||
|
: "visible";
|
||||||
|
storage.setValue(id, { hidden: detail.hidden });
|
||||||
|
},
|
||||||
|
editable() {
|
||||||
|
event.target.disabled = !detail.editable;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Object.keys(detail)
|
||||||
|
.filter(name => name in actions)
|
||||||
|
.forEach(name => actions[name]());
|
||||||
|
});
|
||||||
|
|
||||||
|
this._setEventListeners(
|
||||||
|
element,
|
||||||
|
[
|
||||||
|
["change", "Validate"],
|
||||||
|
["change", "Action"],
|
||||||
|
["focus", "Focus"],
|
||||||
|
["blur", "Blur"],
|
||||||
|
["mousedown", "Mouse Down"],
|
||||||
|
["mouseenter", "Mouse Enter"],
|
||||||
|
["mouseleave", "Mouse Exit"],
|
||||||
|
["mouseup", "MouseUp"],
|
||||||
|
],
|
||||||
|
event => event.target.checked
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.container.appendChild(element);
|
this.container.appendChild(element);
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
@ -756,20 +992,69 @@ class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
if (value) {
|
if (value) {
|
||||||
element.setAttribute("checked", true);
|
element.setAttribute("checked", true);
|
||||||
}
|
}
|
||||||
|
element.setAttribute("pdfButtonValue", data.buttonValue);
|
||||||
|
element.setAttribute("id", id);
|
||||||
|
|
||||||
element.addEventListener("change", function (event) {
|
element.addEventListener("change", function (event) {
|
||||||
const name = event.target.name;
|
const target = event.target;
|
||||||
for (const radio of document.getElementsByName(name)) {
|
for (const radio of document.getElementsByName(event.target.name)) {
|
||||||
if (radio !== event.target) {
|
if (radio !== target) {
|
||||||
storage.setValue(
|
storage.setValue(radio.getAttribute("id"), { value: false });
|
||||||
radio.parentNode.getAttribute("data-annotation-id"),
|
|
||||||
{ value: false }
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
storage.setValue(id, { value: event.target.checked });
|
storage.setValue(id, { value: target.checked });
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this.enableScripting && this.hasJSActions) {
|
||||||
|
element.addEventListener("updateFromSandbox", event => {
|
||||||
|
const { detail } = event;
|
||||||
|
const actions = {
|
||||||
|
value() {
|
||||||
|
const fieldValue = detail.value;
|
||||||
|
for (const radio of document.getElementsByName(event.target.name)) {
|
||||||
|
const radioId = radio.getAttribute("id");
|
||||||
|
if (fieldValue === radio.getAttribute("pdfButtonValue")) {
|
||||||
|
radio.setAttribute("checked", true);
|
||||||
|
storage.setValue(radioId, { value: true });
|
||||||
|
} else {
|
||||||
|
storage.setValue(radioId, { value: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focus() {
|
||||||
|
setTimeout(() => event.target.focus({ preventScroll: false }), 0);
|
||||||
|
},
|
||||||
|
hidden() {
|
||||||
|
event.target.style.visibility = detail.hidden
|
||||||
|
? "hidden"
|
||||||
|
: "visible";
|
||||||
|
storage.setValue(id, { hidden: detail.hidden });
|
||||||
|
},
|
||||||
|
editable() {
|
||||||
|
event.target.disabled = !detail.editable;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Object.keys(detail)
|
||||||
|
.filter(name => name in actions)
|
||||||
|
.forEach(name => actions[name]());
|
||||||
|
});
|
||||||
|
|
||||||
|
this._setEventListeners(
|
||||||
|
element,
|
||||||
|
[
|
||||||
|
["change", "Validate"],
|
||||||
|
["change", "Action"],
|
||||||
|
["focus", "Focus"],
|
||||||
|
["blur", "Blur"],
|
||||||
|
["mousedown", "Mouse Down"],
|
||||||
|
["mouseenter", "Mouse Enter"],
|
||||||
|
["mouseleave", "Mouse Exit"],
|
||||||
|
["mouseup", "MouseUp"],
|
||||||
|
],
|
||||||
|
event => event.target.checked
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this.container.appendChild(element);
|
this.container.appendChild(element);
|
||||||
return this.container;
|
return this.container;
|
||||||
}
|
}
|
||||||
@ -816,6 +1101,7 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
const selectElement = document.createElement("select");
|
const selectElement = document.createElement("select");
|
||||||
selectElement.disabled = this.data.readOnly;
|
selectElement.disabled = this.data.readOnly;
|
||||||
selectElement.name = this.data.fieldName;
|
selectElement.name = this.data.fieldName;
|
||||||
|
selectElement.setAttribute("id", id);
|
||||||
|
|
||||||
if (!this.data.combo) {
|
if (!this.data.combo) {
|
||||||
// List boxes have a size and (optionally) multiple selection.
|
// List boxes have a size and (optionally) multiple selection.
|
||||||
@ -836,11 +1122,77 @@ class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
|
|||||||
selectElement.appendChild(optionElement);
|
selectElement.appendChild(optionElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
selectElement.addEventListener("input", function (event) {
|
function getValue(event) {
|
||||||
const options = event.target.options;
|
const options = event.target.options;
|
||||||
const value = options[options.selectedIndex].value;
|
return options[options.selectedIndex].value;
|
||||||
storage.setValue(id, { value });
|
}
|
||||||
});
|
|
||||||
|
if (this.enableScripting && this.hasJSActions) {
|
||||||
|
selectElement.addEventListener("updateFromSandbox", event => {
|
||||||
|
const { detail } = event;
|
||||||
|
const actions = {
|
||||||
|
value() {
|
||||||
|
const options = event.target.options;
|
||||||
|
const value = detail.value;
|
||||||
|
const i = options.indexOf(value);
|
||||||
|
if (i !== -1) {
|
||||||
|
options.selectedIndex = i;
|
||||||
|
storage.setValue(id, { value });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
focus() {
|
||||||
|
setTimeout(() => event.target.focus({ preventScroll: false }), 0);
|
||||||
|
},
|
||||||
|
hidden() {
|
||||||
|
event.target.style.visibility = detail.hidden
|
||||||
|
? "hidden"
|
||||||
|
: "visible";
|
||||||
|
storage.setValue(id, { hidden: detail.hidden });
|
||||||
|
},
|
||||||
|
editable() {
|
||||||
|
event.target.disabled = !detail.editable;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
Object.keys(detail)
|
||||||
|
.filter(name => name in actions)
|
||||||
|
.forEach(name => actions[name]());
|
||||||
|
});
|
||||||
|
|
||||||
|
selectElement.addEventListener("input", function (event) {
|
||||||
|
const value = getValue(event);
|
||||||
|
storage.setValue(id, { value });
|
||||||
|
|
||||||
|
window.dispatchEvent(
|
||||||
|
new CustomEvent("dispatchEventInSandbox", {
|
||||||
|
detail: {
|
||||||
|
id,
|
||||||
|
name: "Keystroke",
|
||||||
|
changeEx: value,
|
||||||
|
willCommit: true,
|
||||||
|
commitKey: 1,
|
||||||
|
keyDown: false,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
this._setEventListeners(
|
||||||
|
selectElement,
|
||||||
|
[
|
||||||
|
["focus", "Focus"],
|
||||||
|
["blur", "Blur"],
|
||||||
|
["mousedown", "Mouse Down"],
|
||||||
|
["mouseenter", "Mouse Enter"],
|
||||||
|
["mouseleave", "Mouse Exit"],
|
||||||
|
["mouseup", "MouseUp"],
|
||||||
|
],
|
||||||
|
event => event.target.checked
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
selectElement.addEventListener("input", function (event) {
|
||||||
|
storage.setValue(id, { value: getValue(event) });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this.container.appendChild(selectElement);
|
this.container.appendChild(selectElement);
|
||||||
return this.container;
|
return this.container;
|
||||||
@ -1599,6 +1951,7 @@ class AnnotationLayer {
|
|||||||
parameters.annotationStorage || new AnnotationStorage(),
|
parameters.annotationStorage || new AnnotationStorage(),
|
||||||
enableScripting: parameters.enableScripting,
|
enableScripting: parameters.enableScripting,
|
||||||
hasJSActions: parameters.hasJSActions,
|
hasJSActions: parameters.hasJSActions,
|
||||||
|
mouseState: parameters.mouseState,
|
||||||
});
|
});
|
||||||
if (element.isRenderable) {
|
if (element.isRenderable) {
|
||||||
const rendered = element.render();
|
const rendered = element.render();
|
||||||
|
@ -913,6 +913,7 @@ class Doc extends PDFObject {
|
|||||||
const field = this.getField(fieldName);
|
const field = this.getField(fieldName);
|
||||||
if (field) {
|
if (field) {
|
||||||
field.value = field.defaultValue;
|
field.value = field.defaultValue;
|
||||||
|
field.valueAsString = field.value;
|
||||||
mustCalculate = true;
|
mustCalculate = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -920,6 +921,7 @@ class Doc extends PDFObject {
|
|||||||
mustCalculate = this._fields.size !== 0;
|
mustCalculate = this._fields.size !== 0;
|
||||||
for (const field of this._fields.values()) {
|
for (const field of this._fields.values()) {
|
||||||
field.value = field.defaultValue;
|
field.value = field.defaultValue;
|
||||||
|
field.valueAsString = field.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mustCalculate) {
|
if (mustCalculate) {
|
||||||
|
@ -66,7 +66,9 @@ class Field extends PDFObject {
|
|||||||
this.type = data.type;
|
this.type = data.type;
|
||||||
this.userName = data.userName;
|
this.userName = data.userName;
|
||||||
this.value = data.value || "";
|
this.value = data.value || "";
|
||||||
this.valueAsString = data.valueAsString;
|
|
||||||
|
// Need getter/setter
|
||||||
|
this._valueAsString = data.valueAsString;
|
||||||
|
|
||||||
// Private
|
// Private
|
||||||
this._document = data.doc;
|
this._document = data.doc;
|
||||||
@ -107,6 +109,28 @@ class Field extends PDFObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get valueAsString() {
|
||||||
|
return this._valueAsString;
|
||||||
|
}
|
||||||
|
|
||||||
|
set valueAsString(val) {
|
||||||
|
this._valueAsString = val ? val.toString() : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
_getFunction(code, actionName) {
|
||||||
|
try {
|
||||||
|
// This eval is running in a sandbox so it's safe to use Function
|
||||||
|
// eslint-disable-next-line no-new-func
|
||||||
|
return Function("event", `with (this) {${code}}`).bind(this._document);
|
||||||
|
} catch (error) {
|
||||||
|
const value =
|
||||||
|
`"${error.toString()}" for action ` +
|
||||||
|
`"${actionName}" in object ${this._id}.`;
|
||||||
|
this._send({ command: "error", value });
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
setAction(cTrigger, cScript) {
|
setAction(cTrigger, cScript) {
|
||||||
if (typeof cTrigger !== "string" || typeof cScript !== "string") {
|
if (typeof cTrigger !== "string" || typeof cScript !== "string") {
|
||||||
return;
|
return;
|
||||||
@ -114,10 +138,10 @@ class Field extends PDFObject {
|
|||||||
if (!(cTrigger in this._actions)) {
|
if (!(cTrigger in this._actions)) {
|
||||||
this._actions[cTrigger] = [];
|
this._actions[cTrigger] = [];
|
||||||
}
|
}
|
||||||
this._actions[cTrigger].push(
|
const fun = this._getFunction(cScript, cTrigger);
|
||||||
// eslint-disable-next-line no-new-func
|
if (fun) {
|
||||||
Function("event", `with (this) {${cScript}}`).bind(this._document)
|
this._actions[cTrigger].push(fun);
|
||||||
);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setFocus() {
|
setFocus() {
|
||||||
@ -127,16 +151,13 @@ class Field extends PDFObject {
|
|||||||
_createActionsMap(actions) {
|
_createActionsMap(actions) {
|
||||||
const actionsMap = new Map();
|
const actionsMap = new Map();
|
||||||
if (actions) {
|
if (actions) {
|
||||||
const doc = this._document;
|
|
||||||
for (const [eventType, actionsForEvent] of Object.entries(actions)) {
|
for (const [eventType, actionsForEvent] of Object.entries(actions)) {
|
||||||
// This stuff is running in a sandbox so it's safe to use Function
|
const functions = actionsForEvent
|
||||||
actionsMap.set(
|
.map(action => this._getFunction(action, eventType))
|
||||||
eventType,
|
.filter(fun => !!fun);
|
||||||
actionsForEvent.map(action =>
|
if (functions.length > 0) {
|
||||||
// eslint-disable-next-line no-new-func
|
actionsMap.set(eventType, functions);
|
||||||
Function("event", `with (this) {${action}}`).bind(doc)
|
}
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return actionsMap;
|
return actionsMap;
|
||||||
|
@ -54,7 +54,7 @@ class ProxyHandler {
|
|||||||
obj[prop] = value;
|
obj[prop] = value;
|
||||||
if (obj._send && obj._id !== null && typeof old !== "function") {
|
if (obj._send && obj._id !== null && typeof old !== "function") {
|
||||||
const data = { id: obj._id };
|
const data = { id: obj._id };
|
||||||
data[prop] = value;
|
data[prop] = obj[prop];
|
||||||
|
|
||||||
// send the updated value to the other side
|
// send the updated value to the other side
|
||||||
obj._send(data);
|
obj._send(data);
|
||||||
|
@ -27,6 +27,44 @@ describe("Interaction", () => {
|
|||||||
await closePages(pages);
|
await closePages(pages);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("must show a text field and then make in invisible when content is removed", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
let visibility = await page.$eval(
|
||||||
|
"#\\34 27R",
|
||||||
|
el => getComputedStyle(el).visibility
|
||||||
|
);
|
||||||
|
expect(visibility).withContext(`In ${browserName}`).toEqual("hidden");
|
||||||
|
|
||||||
|
await page.type("#\\34 16R", "3.14159", { delay: 200 });
|
||||||
|
await page.click("#\\34 19R");
|
||||||
|
|
||||||
|
visibility = await page.$eval(
|
||||||
|
"#\\34 27R",
|
||||||
|
el => getComputedStyle(el).visibility
|
||||||
|
);
|
||||||
|
expect(visibility)
|
||||||
|
.withContext(`In ${browserName}`)
|
||||||
|
.toEqual("visible");
|
||||||
|
|
||||||
|
// Clear the textfield
|
||||||
|
await page.click("#\\34 16R");
|
||||||
|
await page.keyboard.down("Control");
|
||||||
|
await page.keyboard.press("A");
|
||||||
|
await page.keyboard.up("Control");
|
||||||
|
await page.keyboard.press("Backspace");
|
||||||
|
// and leave it
|
||||||
|
await page.click("#\\34 19R");
|
||||||
|
|
||||||
|
visibility = await page.$eval(
|
||||||
|
"#\\34 27R",
|
||||||
|
el => getComputedStyle(el).visibility
|
||||||
|
);
|
||||||
|
expect(visibility).withContext(`In ${browserName}`).toEqual("hidden");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("must format the field with 2 digits and leave field with a click", async () => {
|
it("must format the field with 2 digits and leave field with a click", async () => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
pages.map(async ([browserName, page]) => {
|
pages.map(async ([browserName, page]) => {
|
||||||
@ -34,6 +72,35 @@ describe("Interaction", () => {
|
|||||||
await page.click("#\\34 19R");
|
await page.click("#\\34 19R");
|
||||||
const text = await page.$eval("#\\34 16R", el => el.value);
|
const text = await page.$eval("#\\34 16R", el => el.value);
|
||||||
expect(text).withContext(`In ${browserName}`).toEqual("3,14");
|
expect(text).withContext(`In ${browserName}`).toEqual("3,14");
|
||||||
|
|
||||||
|
const sum = await page.$eval("#\\34 27R", el => el.value);
|
||||||
|
expect(sum).withContext(`In ${browserName}`).toEqual("3,14");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must format the field with 2 digits, leave field with a click and again", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
await page.type("#\\34 48R", "61803", { delay: 200 });
|
||||||
|
await page.click("#\\34 19R");
|
||||||
|
let text = await page.$eval("#\\34 48R", el => el.value);
|
||||||
|
expect(text).withContext(`In ${browserName}`).toEqual("61.803,00");
|
||||||
|
|
||||||
|
await page.click("#\\34 48R");
|
||||||
|
text = await page.$eval("#\\34 48R", el => el.value);
|
||||||
|
expect(text).withContext(`In ${browserName}`).toEqual("61803");
|
||||||
|
|
||||||
|
// Clear the textfield
|
||||||
|
await page.keyboard.down("Control");
|
||||||
|
await page.keyboard.press("A");
|
||||||
|
await page.keyboard.up("Control");
|
||||||
|
await page.keyboard.press("Backspace");
|
||||||
|
|
||||||
|
await page.type("#\\34 48R", "1.61803", { delay: 200 });
|
||||||
|
await page.click("#\\34 19R");
|
||||||
|
text = await page.$eval("#\\34 48R", el => el.value);
|
||||||
|
expect(text).withContext(`In ${browserName}`).toEqual("1,62");
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -45,6 +112,67 @@ describe("Interaction", () => {
|
|||||||
await page.keyboard.press("Tab");
|
await page.keyboard.press("Tab");
|
||||||
const text = await page.$eval("#\\34 22R", el => el.value);
|
const text = await page.$eval("#\\34 22R", el => el.value);
|
||||||
expect(text).withContext(`In ${browserName}`).toEqual("2,72");
|
expect(text).withContext(`In ${browserName}`).toEqual("2,72");
|
||||||
|
|
||||||
|
const sum = await page.$eval("#\\34 27R", el => el.value);
|
||||||
|
expect(sum).withContext(`In ${browserName}`).toEqual("5,86");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must format the field with 2 digits and hit ESC", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
let sum = await page.$eval("#\\34 71R", el => el.value);
|
||||||
|
expect(sum).withContext(`In ${browserName}`).toEqual("4,24");
|
||||||
|
|
||||||
|
await page.type("#\\34 36R", "0.69314", { delay: 200 });
|
||||||
|
await page.keyboard.press("Escape");
|
||||||
|
const text = await page.$eval("#\\34 36R", el => el.value);
|
||||||
|
expect(text).withContext(`In ${browserName}`).toEqual("0.69314");
|
||||||
|
|
||||||
|
sum = await page.$eval("#\\34 71R", el => el.value);
|
||||||
|
expect(sum).withContext(`In ${browserName}`).toEqual("3,55");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must format the field with 2 digits on key ENTER", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
await page.type("#\\34 19R", "0.577215", { delay: 200 });
|
||||||
|
await page.keyboard.press("Enter");
|
||||||
|
const text = await page.$eval("#\\34 19R", el => el.value);
|
||||||
|
expect(text).toEqual("0.577215");
|
||||||
|
|
||||||
|
const sum = await page.$eval("#\\34 27R", el => el.value);
|
||||||
|
expect(sum).toEqual("6,44");
|
||||||
|
})
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("must reset all", async () => {
|
||||||
|
await Promise.all(
|
||||||
|
pages.map(async ([browserName, page]) => {
|
||||||
|
// this field has no actions but it must be cleared on reset
|
||||||
|
await page.type("#\\34 05R", "employee", { delay: 200 });
|
||||||
|
|
||||||
|
// click on reset button
|
||||||
|
await page.click("[data-annotation-id='402R']");
|
||||||
|
|
||||||
|
let text = await page.$eval("#\\34 16R", el => el.value);
|
||||||
|
expect(text).toEqual("");
|
||||||
|
|
||||||
|
text = await page.$eval("#\\34 22R", el => el.value);
|
||||||
|
expect(text).toEqual("");
|
||||||
|
|
||||||
|
text = await page.$eval("#\\34 19R", el => el.value);
|
||||||
|
expect(text).toEqual("");
|
||||||
|
|
||||||
|
text = await page.$eval("#\\34 05R", el => el.value);
|
||||||
|
expect(text).toEqual("");
|
||||||
|
|
||||||
|
const sum = await page.$eval("#\\34 27R", el => el.value);
|
||||||
|
expect(sum).toEqual("");
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -84,7 +84,7 @@ describe("Scripting", function () {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
const number = 123;
|
const number = 123;
|
||||||
const expected = ((number - 1) * number) / 2;
|
const expected = (((number - 1) * number) / 2).toString();
|
||||||
const refId = getId();
|
const refId = getId();
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
@ -1094,7 +1094,7 @@ describe("Scripting", function () {
|
|||||||
expect(send_queue.get(refIds[3])).toEqual({
|
expect(send_queue.get(refIds[3])).toEqual({
|
||||||
id: refIds[3],
|
id: refIds[3],
|
||||||
value: 1,
|
value: 1,
|
||||||
valueAsString: 1,
|
valueAsString: "1",
|
||||||
});
|
});
|
||||||
|
|
||||||
await sandbox.dispatchEventInSandbox({
|
await sandbox.dispatchEventInSandbox({
|
||||||
@ -1107,7 +1107,7 @@ describe("Scripting", function () {
|
|||||||
expect(send_queue.get(refIds[3])).toEqual({
|
expect(send_queue.get(refIds[3])).toEqual({
|
||||||
id: refIds[3],
|
id: refIds[3],
|
||||||
value: 3,
|
value: 3,
|
||||||
valueAsString: 3,
|
valueAsString: "3",
|
||||||
});
|
});
|
||||||
|
|
||||||
await sandbox.dispatchEventInSandbox({
|
await sandbox.dispatchEventInSandbox({
|
||||||
@ -1120,7 +1120,7 @@ describe("Scripting", function () {
|
|||||||
expect(send_queue.get(refIds[3])).toEqual({
|
expect(send_queue.get(refIds[3])).toEqual({
|
||||||
id: refIds[3],
|
id: refIds[3],
|
||||||
value: 6,
|
value: 6,
|
||||||
valueAsString: 6,
|
valueAsString: "6",
|
||||||
});
|
});
|
||||||
|
|
||||||
done();
|
done();
|
||||||
|
@ -47,6 +47,7 @@ class AnnotationLayerBuilder {
|
|||||||
l10n = NullL10n,
|
l10n = NullL10n,
|
||||||
enableScripting = false,
|
enableScripting = false,
|
||||||
hasJSActionsPromise = null,
|
hasJSActionsPromise = null,
|
||||||
|
mouseState = null,
|
||||||
}) {
|
}) {
|
||||||
this.pageDiv = pageDiv;
|
this.pageDiv = pageDiv;
|
||||||
this.pdfPage = pdfPage;
|
this.pdfPage = pdfPage;
|
||||||
@ -58,6 +59,7 @@ class AnnotationLayerBuilder {
|
|||||||
this.annotationStorage = annotationStorage;
|
this.annotationStorage = annotationStorage;
|
||||||
this.enableScripting = enableScripting;
|
this.enableScripting = enableScripting;
|
||||||
this._hasJSActionsPromise = hasJSActionsPromise;
|
this._hasJSActionsPromise = hasJSActionsPromise;
|
||||||
|
this._mouseState = mouseState;
|
||||||
|
|
||||||
this.div = null;
|
this.div = null;
|
||||||
this._cancelled = false;
|
this._cancelled = false;
|
||||||
@ -93,6 +95,7 @@ class AnnotationLayerBuilder {
|
|||||||
annotationStorage: this.annotationStorage,
|
annotationStorage: this.annotationStorage,
|
||||||
enableScripting: this.enableScripting,
|
enableScripting: this.enableScripting,
|
||||||
hasJSActions,
|
hasJSActions,
|
||||||
|
mouseState: this._mouseState,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.div) {
|
if (this.div) {
|
||||||
@ -139,6 +142,7 @@ class DefaultAnnotationLayerFactory {
|
|||||||
* @param {IL10n} l10n
|
* @param {IL10n} l10n
|
||||||
* @param {boolean} [enableScripting]
|
* @param {boolean} [enableScripting]
|
||||||
* @param {Promise<boolean>} [hasJSActionsPromise]
|
* @param {Promise<boolean>} [hasJSActionsPromise]
|
||||||
|
* @param {Object} [mouseState]
|
||||||
* @returns {AnnotationLayerBuilder}
|
* @returns {AnnotationLayerBuilder}
|
||||||
*/
|
*/
|
||||||
createAnnotationLayerBuilder(
|
createAnnotationLayerBuilder(
|
||||||
@ -149,7 +153,8 @@ class DefaultAnnotationLayerFactory {
|
|||||||
renderInteractiveForms = true,
|
renderInteractiveForms = true,
|
||||||
l10n = NullL10n,
|
l10n = NullL10n,
|
||||||
enableScripting = false,
|
enableScripting = false,
|
||||||
hasJSActionsPromise = null
|
hasJSActionsPromise = null,
|
||||||
|
mouseState = null
|
||||||
) {
|
) {
|
||||||
return new AnnotationLayerBuilder({
|
return new AnnotationLayerBuilder({
|
||||||
pageDiv,
|
pageDiv,
|
||||||
@ -161,6 +166,7 @@ class DefaultAnnotationLayerFactory {
|
|||||||
annotationStorage,
|
annotationStorage,
|
||||||
enableScripting,
|
enableScripting,
|
||||||
hasJSActionsPromise,
|
hasJSActionsPromise,
|
||||||
|
mouseState,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
web/app.js
13
web/app.js
@ -258,6 +258,7 @@ const PDFViewerApplication = {
|
|||||||
_wheelUnusedTicks: 0,
|
_wheelUnusedTicks: 0,
|
||||||
_idleCallbacks: new Set(),
|
_idleCallbacks: new Set(),
|
||||||
_scriptingInstance: null,
|
_scriptingInstance: null,
|
||||||
|
_mouseState: Object.create(null),
|
||||||
|
|
||||||
// Called once when the document is loaded.
|
// Called once when the document is loaded.
|
||||||
async initialize(appConfig) {
|
async initialize(appConfig) {
|
||||||
@ -501,6 +502,7 @@ const PDFViewerApplication = {
|
|||||||
useOnlyCssZoom: AppOptions.get("useOnlyCssZoom"),
|
useOnlyCssZoom: AppOptions.get("useOnlyCssZoom"),
|
||||||
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
|
maxCanvasPixels: AppOptions.get("maxCanvasPixels"),
|
||||||
enableScripting: AppOptions.get("enableScripting"),
|
enableScripting: AppOptions.get("enableScripting"),
|
||||||
|
mouseState: this._mouseState,
|
||||||
});
|
});
|
||||||
pdfRenderingQueue.setViewer(this.pdfViewer);
|
pdfRenderingQueue.setViewer(this.pdfViewer);
|
||||||
pdfLinkService.setViewer(this.pdfViewer);
|
pdfLinkService.setViewer(this.pdfViewer);
|
||||||
@ -1538,6 +1540,17 @@ const PDFViewerApplication = {
|
|||||||
dispatchEventInSandbox
|
dispatchEventInSandbox
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const mouseDown = event => {
|
||||||
|
this._mouseState.isDown = true;
|
||||||
|
};
|
||||||
|
const mouseUp = event => {
|
||||||
|
this._mouseState.isDown = false;
|
||||||
|
};
|
||||||
|
window.addEventListener("mousedown", mouseDown);
|
||||||
|
this._scriptingInstance.events.set("mousedown", mouseDown);
|
||||||
|
window.addEventListener("mouseup", mouseUp);
|
||||||
|
this._scriptingInstance.events.set("mouseup", mouseUp);
|
||||||
|
|
||||||
const dispatchEventName = generateRandomStringForSandbox(objects);
|
const dispatchEventName = generateRandomStringForSandbox(objects);
|
||||||
|
|
||||||
if (!this._contentLength) {
|
if (!this._contentLength) {
|
||||||
|
@ -79,6 +79,7 @@ const DEFAULT_CACHE_SIZE = 10;
|
|||||||
* @property {IL10n} l10n - Localization service.
|
* @property {IL10n} l10n - Localization service.
|
||||||
* @property {boolean} [enableScripting] - Enable embedded script execution.
|
* @property {boolean} [enableScripting] - Enable embedded script execution.
|
||||||
* The default value is `false`.
|
* The default value is `false`.
|
||||||
|
* @property {Object} [mouseState] - The mouse button state.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function PDFPageViewBuffer(size) {
|
function PDFPageViewBuffer(size) {
|
||||||
@ -194,6 +195,7 @@ class BaseViewer {
|
|||||||
this.maxCanvasPixels = options.maxCanvasPixels;
|
this.maxCanvasPixels = options.maxCanvasPixels;
|
||||||
this.l10n = options.l10n || NullL10n;
|
this.l10n = options.l10n || NullL10n;
|
||||||
this.enableScripting = options.enableScripting || false;
|
this.enableScripting = options.enableScripting || false;
|
||||||
|
this.mouseState = options.mouseState || null;
|
||||||
|
|
||||||
this.defaultRenderingQueue = !options.renderingQueue;
|
this.defaultRenderingQueue = !options.renderingQueue;
|
||||||
if (this.defaultRenderingQueue) {
|
if (this.defaultRenderingQueue) {
|
||||||
@ -533,6 +535,7 @@ class BaseViewer {
|
|||||||
maxCanvasPixels: this.maxCanvasPixels,
|
maxCanvasPixels: this.maxCanvasPixels,
|
||||||
l10n: this.l10n,
|
l10n: this.l10n,
|
||||||
enableScripting: this.enableScripting,
|
enableScripting: this.enableScripting,
|
||||||
|
mouseState: this.mouseState,
|
||||||
});
|
});
|
||||||
this._pages.push(pageView);
|
this._pages.push(pageView);
|
||||||
}
|
}
|
||||||
@ -1265,6 +1268,7 @@ class BaseViewer {
|
|||||||
* @param {IL10n} l10n
|
* @param {IL10n} l10n
|
||||||
* @param {boolean} [enableScripting]
|
* @param {boolean} [enableScripting]
|
||||||
* @param {Promise<boolean>} [hasJSActionsPromise]
|
* @param {Promise<boolean>} [hasJSActionsPromise]
|
||||||
|
* @param {Object} [mouseState]
|
||||||
* @returns {AnnotationLayerBuilder}
|
* @returns {AnnotationLayerBuilder}
|
||||||
*/
|
*/
|
||||||
createAnnotationLayerBuilder(
|
createAnnotationLayerBuilder(
|
||||||
@ -1275,7 +1279,8 @@ class BaseViewer {
|
|||||||
renderInteractiveForms = false,
|
renderInteractiveForms = false,
|
||||||
l10n = NullL10n,
|
l10n = NullL10n,
|
||||||
enableScripting = false,
|
enableScripting = false,
|
||||||
hasJSActionsPromise = null
|
hasJSActionsPromise = null,
|
||||||
|
mouseState = null
|
||||||
) {
|
) {
|
||||||
return new AnnotationLayerBuilder({
|
return new AnnotationLayerBuilder({
|
||||||
pageDiv,
|
pageDiv,
|
||||||
@ -1290,6 +1295,7 @@ class BaseViewer {
|
|||||||
enableScripting,
|
enableScripting,
|
||||||
hasJSActionsPromise:
|
hasJSActionsPromise:
|
||||||
hasJSActionsPromise || this.pdfDocument?.hasJSActions(),
|
hasJSActionsPromise || this.pdfDocument?.hasJSActions(),
|
||||||
|
mouseState,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,6 +188,7 @@ class IPDFAnnotationLayerFactory {
|
|||||||
* @param {IL10n} l10n
|
* @param {IL10n} l10n
|
||||||
* @param {boolean} [enableScripting]
|
* @param {boolean} [enableScripting]
|
||||||
* @param {Promise<boolean>} [hasJSActionsPromise]
|
* @param {Promise<boolean>} [hasJSActionsPromise]
|
||||||
|
* @param {Object} [mouseState]
|
||||||
* @returns {AnnotationLayerBuilder}
|
* @returns {AnnotationLayerBuilder}
|
||||||
*/
|
*/
|
||||||
createAnnotationLayerBuilder(
|
createAnnotationLayerBuilder(
|
||||||
@ -198,7 +199,8 @@ class IPDFAnnotationLayerFactory {
|
|||||||
renderInteractiveForms = true,
|
renderInteractiveForms = true,
|
||||||
l10n = undefined,
|
l10n = undefined,
|
||||||
enableScripting = false,
|
enableScripting = false,
|
||||||
hasJSActionsPromise = null
|
hasJSActionsPromise = null,
|
||||||
|
mouseState = null
|
||||||
) {}
|
) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,6 +63,7 @@ import { viewerCompatibilityParams } from "./viewer_compatibility.js";
|
|||||||
* @property {IL10n} l10n - Localization service.
|
* @property {IL10n} l10n - Localization service.
|
||||||
* @property {boolean} [enableScripting] - Enable embedded script execution.
|
* @property {boolean} [enableScripting] - Enable embedded script execution.
|
||||||
* The default value is `false`.
|
* The default value is `false`.
|
||||||
|
* @property {Object} [mouseState] - The mouse button state.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const MAX_CANVAS_PIXELS = viewerCompatibilityParams.maxCanvasPixels || 16777216;
|
const MAX_CANVAS_PIXELS = viewerCompatibilityParams.maxCanvasPixels || 16777216;
|
||||||
@ -109,6 +110,7 @@ class PDFPageView {
|
|||||||
this.enableWebGL = options.enableWebGL || false;
|
this.enableWebGL = options.enableWebGL || false;
|
||||||
this.l10n = options.l10n || NullL10n;
|
this.l10n = options.l10n || NullL10n;
|
||||||
this.enableScripting = options.enableScripting || false;
|
this.enableScripting = options.enableScripting || false;
|
||||||
|
this.mouseState = options.mouseState || null;
|
||||||
|
|
||||||
this.paintTask = null;
|
this.paintTask = null;
|
||||||
this.paintedViewportMap = new WeakMap();
|
this.paintedViewportMap = new WeakMap();
|
||||||
@ -551,7 +553,8 @@ class PDFPageView {
|
|||||||
this.renderInteractiveForms,
|
this.renderInteractiveForms,
|
||||||
this.l10n,
|
this.l10n,
|
||||||
this.enableScripting,
|
this.enableScripting,
|
||||||
/* hasJSActionsPromise = */ null
|
/* hasJSActionsPromise = */ null,
|
||||||
|
this.mouseState
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
this._renderAnnotationLayer();
|
this._renderAnnotationLayer();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user