: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
value = value !== data.buttonValue;
for (const radio of this._getElementsByName(data.fieldName, id)) {
storage.setValue(radio.id, {
const element = document.createElement("input");
GetElementsByNameSet.add(element);
element.setAttribute("data-element-id", id);
element.disabled = data.readOnly;
this._setRequired(element, this.data.required);
element.name = data.fieldName;
element.setAttribute("checked", true);
element.tabIndex = DEFAULT_TAB_INDEX;
element.addEventListener("change", event => {
for (const radio of this._getElementsByName(name, id)) {
storage.setValue(radio.id, {
element.addEventListener("resetform", event => {
const defaultValue = data.defaultFieldValue;
event.target.checked = defaultValue !== null && defaultValue !== undefined && defaultValue === data.buttonValue;
if (this.enableScripting && this.hasJSActions) {
const pdfButtonValue = data.buttonValue;
element.addEventListener("updatefromsandbox", jsEvent => {
const checked = pdfButtonValue === event.detail.value;
for (const radio of this._getElementsByName(event.target.name)) {
const curChecked = checked && radio.id === id;
radio.domElement.checked = curChecked;
storage.setValue(radio.id, {
this._dispatchEventFromSandbox(actions, jsEvent);
this._setEventListeners(element, null, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked);
this._setBackgroundColor(element);
this._setDefaultPropertiesFromJS(element);
this.container.append(element);
class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
constructor(parameters) {
ignoreBorder: parameters.data.hasAppearance
const container = super.render();
container.classList.add("buttonWidgetAnnotation", "pushButton");
const linkElement = container.lastChild;
if (this.enableScripting && this.hasJSActions && linkElement) {
this._setDefaultPropertiesFromJS(linkElement);
linkElement.addEventListener("updatefromsandbox", jsEvent => {
this._dispatchEventFromSandbox({}, jsEvent);
class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
constructor(parameters) {
isRenderable: parameters.renderForms
this.container.classList.add("choiceWidgetAnnotation");
const storage = this.annotationStorage;
const storedData = storage.getValue(id, {
value: this.data.fieldValue
const selectElement = document.createElement("select");
GetElementsByNameSet.add(selectElement);
selectElement.setAttribute("data-element-id", id);
selectElement.disabled = this.data.readOnly;
this._setRequired(selectElement, this.data.required);
selectElement.name = this.data.fieldName;
selectElement.tabIndex = DEFAULT_TAB_INDEX;
let addAnEmptyEntry = this.data.combo && this.data.options.length > 0;
selectElement.size = this.data.options.length;
if (this.data.multiSelect) {
selectElement.multiple = true;
selectElement.addEventListener("resetform", event => {
const defaultValue = this.data.defaultFieldValue;
for (const option of selectElement.options) {
option.selected = option.value === defaultValue;
for (const option of this.data.options) {
const optionElement = document.createElement("option");
optionElement.textContent = option.displayValue;
optionElement.value = option.exportValue;
if (storedData.value.includes(option.exportValue)) {
optionElement.setAttribute("selected", true);
selectElement.append(optionElement);
let removeEmptyEntry = null;
const noneOptionElement = document.createElement("option");
noneOptionElement.value = " ";
noneOptionElement.setAttribute("hidden", true);
noneOptionElement.setAttribute("selected", true);
selectElement.prepend(noneOptionElement);
removeEmptyEntry = () => {
noneOptionElement.remove();
selectElement.removeEventListener("input", removeEmptyEntry);
selectElement.addEventListener("input", removeEmptyEntry);
const getValue = isExport => {
const name = isExport ? "value" : "textContent";
return options.selectedIndex === -1 ? null : options[options.selectedIndex][name];
return Array.prototype.filter.call(options, option => option.selected).map(option => option[name]);
let selectedValues = getValue(false);
const getItems = event => {
const options = event.target.options;
return Array.prototype.map.call(options, option => ({
displayValue: option.textContent,
exportValue: option.value
if (this.enableScripting && this.hasJSActions) {
selectElement.addEventListener("updatefromsandbox", jsEvent => {
const value = event.detail.value;
const values = new Set(Array.isArray(value) ? value : [value]);
for (const option of selectElement.options) {
option.selected = values.has(option.value);
selectedValues = getValue(false);
multipleSelection(event) {
selectElement.multiple = true;
const options = selectElement.options;
const index = event.detail.remove;
options[index].selected = false;
selectElement.remove(index);
if (options.length > 0) {
const i = Array.prototype.findIndex.call(options, option => option.selected);
options[0].selected = true;
selectedValues = getValue(false);
while (selectElement.length !== 0) {
selectedValues = getValue(false);
const selectChild = selectElement.children[index];
const optionElement = document.createElement("option");
optionElement.textContent = displayValue;
optionElement.value = exportValue;
selectChild.before(optionElement);
selectElement.append(optionElement);
selectedValues = getValue(false);
while (selectElement.length !== 0) {
for (const item of items) {
const optionElement = document.createElement("option");
optionElement.textContent = displayValue;
optionElement.value = exportValue;
selectElement.append(optionElement);
if (selectElement.options.length > 0) {
selectElement.options[0].selected = true;
selectedValues = getValue(false);
const indices = new Set(event.detail.indices);
for (const option of event.target.options) {
option.selected = indices.has(option.index);
selectedValues = getValue(false);
event.target.disabled = !event.detail.editable;
this._dispatchEventFromSandbox(actions, jsEvent);
selectElement.addEventListener("input", event => {
const exportValue = getValue(true);
const change = getValue(false);
this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
this._setEventListeners(selectElement, null, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"], ["input", "Action"], ["input", "Validate"]], event => event.target.value);
selectElement.addEventListener("input", function (event) {
this._setTextStyle(selectElement);
this._setBackgroundColor(selectElement);
this._setDefaultPropertiesFromJS(selectElement);
this.container.append(selectElement);
class PopupAnnotationElement extends AnnotationElement {
constructor(parameters) {
isRenderable: AnnotationElement._hasPopupData(data)
this.elements = elements;
this.container.classList.add("popupAnnotation");
const popup = this.popup = new PopupElement({
container: this.container,
titleObj: this.data.titleObj,
modificationDate: this.data.modificationDate,
contentsObj: this.data.contentsObj,
richText: this.data.richText,
parentRect: this.data.parentRect || null,
for (const element of this.elements) {
elementIds.push(element.data.id);
element.addHighlightArea();
this.container.setAttribute("aria-controls", elementIds.map(id => `${AnnotationPrefix}${id}`).join(","));
#boundKeyDown = this.#keyDown.bind(this);
#boundHide = this.#hide.bind(this);
#boundShow = this.#show.bind(this);
#boundToggle = this.#toggle.bind(this);
this.#container = container;
this.#titleObj = titleObj;
this.#contentsObj = contentsObj;
this.#richText = richText;
this.#parentRect = parentRect;
this.#elements = elements;
this.#dateObj = PDFDateString.toDateObject(modificationDate);
this.trigger = elements.flatMap(e => e.getElementsToTriggerPopup());
for (const element of this.trigger) {
element.addEventListener("click", this.#boundToggle);
element.addEventListener("mouseenter", this.#boundShow);
element.addEventListener("mouseleave", this.#boundHide);
element.classList.add("popupTriggerArea");
for (const element of elements) {
element.container?.addEventListener("keydown", this.#boundKeyDown);
this.#container.hidden = true;
const popup = this.#popup = document.createElement("div");
popup.className = "popup";
const baseColor = popup.style.outlineColor = Util.makeHexColor(...this.#color);
if (CSS.supports("background-color", "color-mix(in srgb, red 30%, white)")) {
popup.style.backgroundColor = `color-mix(in srgb, ${baseColor} 30%, white)`;
const BACKGROUND_ENLIGHT = 0.7;
popup.style.backgroundColor = Util.makeHexColor(...this.#color.map(c => Math.floor(BACKGROUND_ENLIGHT * (255 - c) + c)));
const header = document.createElement("span");
header.className = "header";
const title = document.createElement("h1");
const modificationDate = document.createElement("span");
modificationDate.classList.add("popupDate");
modificationDate.setAttribute("data-l10n-id", "pdfjs-annotation-date-string");
modificationDate.setAttribute("data-l10n-args", JSON.stringify({
date: this.#dateObj.toLocaleDateString(),
time: this.#dateObj.toLocaleTimeString()
header.append(modificationDate);
popup.lastChild.classList.add("richText", "popupContent");
const contents = this._formatContents(this.#contentsObj);
this.#container.append(popup);
const richText = this.#richText;
const contentsObj = this.#contentsObj;
if (richText?.str && (!contentsObj?.str || contentsObj.str === richText.str)) {
return this.#richText.html || null;
return this.#html?.attributes?.style?.fontSize || 0;
return this.#html?.attributes?.style?.color || null;
#makePopupContent(text) {
fontSize: this.#fontSize ? `calc(${this.#fontSize}px * var(--scale-factor))` : ""
for (const line of text.split("\n")) {
attributes: lineAttributes