1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | "use strict";
|
23 |
|
24 | Object.defineProperty(exports, "__esModule", {
|
25 | value: true
|
26 | });
|
27 | exports.AnnotationLayer = void 0;
|
28 |
|
29 | var _util = require("../shared/util.js");
|
30 |
|
31 | var _display_utils = require("./display_utils.js");
|
32 |
|
33 | var _annotation_storage = require("./annotation_storage.js");
|
34 |
|
35 | var _scripting_utils = require("../shared/scripting_utils.js");
|
36 |
|
37 | var _xfa_layer = require("./xfa_layer.js");
|
38 |
|
39 | const DEFAULT_TAB_INDEX = 1000;
|
40 | const GetElementsByNameSet = new WeakSet();
|
41 |
|
42 | class AnnotationElementFactory {
|
43 | static create(parameters) {
|
44 | const subtype = parameters.data.annotationType;
|
45 |
|
46 | switch (subtype) {
|
47 | case _util.AnnotationType.LINK:
|
48 | return new LinkAnnotationElement(parameters);
|
49 |
|
50 | case _util.AnnotationType.TEXT:
|
51 | return new TextAnnotationElement(parameters);
|
52 |
|
53 | case _util.AnnotationType.WIDGET:
|
54 | const fieldType = parameters.data.fieldType;
|
55 |
|
56 | switch (fieldType) {
|
57 | case "Tx":
|
58 | return new TextWidgetAnnotationElement(parameters);
|
59 |
|
60 | case "Btn":
|
61 | if (parameters.data.radioButton) {
|
62 | return new RadioButtonWidgetAnnotationElement(parameters);
|
63 | } else if (parameters.data.checkBox) {
|
64 | return new CheckboxWidgetAnnotationElement(parameters);
|
65 | }
|
66 |
|
67 | return new PushButtonWidgetAnnotationElement(parameters);
|
68 |
|
69 | case "Ch":
|
70 | return new ChoiceWidgetAnnotationElement(parameters);
|
71 | }
|
72 |
|
73 | return new WidgetAnnotationElement(parameters);
|
74 |
|
75 | case _util.AnnotationType.POPUP:
|
76 | return new PopupAnnotationElement(parameters);
|
77 |
|
78 | case _util.AnnotationType.FREETEXT:
|
79 | return new FreeTextAnnotationElement(parameters);
|
80 |
|
81 | case _util.AnnotationType.LINE:
|
82 | return new LineAnnotationElement(parameters);
|
83 |
|
84 | case _util.AnnotationType.SQUARE:
|
85 | return new SquareAnnotationElement(parameters);
|
86 |
|
87 | case _util.AnnotationType.CIRCLE:
|
88 | return new CircleAnnotationElement(parameters);
|
89 |
|
90 | case _util.AnnotationType.POLYLINE:
|
91 | return new PolylineAnnotationElement(parameters);
|
92 |
|
93 | case _util.AnnotationType.CARET:
|
94 | return new CaretAnnotationElement(parameters);
|
95 |
|
96 | case _util.AnnotationType.INK:
|
97 | return new InkAnnotationElement(parameters);
|
98 |
|
99 | case _util.AnnotationType.POLYGON:
|
100 | return new PolygonAnnotationElement(parameters);
|
101 |
|
102 | case _util.AnnotationType.HIGHLIGHT:
|
103 | return new HighlightAnnotationElement(parameters);
|
104 |
|
105 | case _util.AnnotationType.UNDERLINE:
|
106 | return new UnderlineAnnotationElement(parameters);
|
107 |
|
108 | case _util.AnnotationType.SQUIGGLY:
|
109 | return new SquigglyAnnotationElement(parameters);
|
110 |
|
111 | case _util.AnnotationType.STRIKEOUT:
|
112 | return new StrikeOutAnnotationElement(parameters);
|
113 |
|
114 | case _util.AnnotationType.STAMP:
|
115 | return new StampAnnotationElement(parameters);
|
116 |
|
117 | case _util.AnnotationType.FILEATTACHMENT:
|
118 | return new FileAttachmentAnnotationElement(parameters);
|
119 |
|
120 | default:
|
121 | return new AnnotationElement(parameters);
|
122 | }
|
123 | }
|
124 |
|
125 | }
|
126 |
|
127 | class AnnotationElement {
|
128 | constructor(parameters, {
|
129 | isRenderable = false,
|
130 | ignoreBorder = false,
|
131 | createQuadrilaterals = false
|
132 | } = {}) {
|
133 | this.isRenderable = isRenderable;
|
134 | this.data = parameters.data;
|
135 | this.layer = parameters.layer;
|
136 | this.page = parameters.page;
|
137 | this.viewport = parameters.viewport;
|
138 | this.linkService = parameters.linkService;
|
139 | this.downloadManager = parameters.downloadManager;
|
140 | this.imageResourcesPath = parameters.imageResourcesPath;
|
141 | this.renderForms = parameters.renderForms;
|
142 | this.svgFactory = parameters.svgFactory;
|
143 | this.annotationStorage = parameters.annotationStorage;
|
144 | this.enableScripting = parameters.enableScripting;
|
145 | this.hasJSActions = parameters.hasJSActions;
|
146 | this._fieldObjects = parameters.fieldObjects;
|
147 | this._mouseState = parameters.mouseState;
|
148 |
|
149 | if (isRenderable) {
|
150 | this.container = this._createContainer(ignoreBorder);
|
151 | }
|
152 |
|
153 | if (createQuadrilaterals) {
|
154 | this.quadrilaterals = this._createQuadrilaterals(ignoreBorder);
|
155 | }
|
156 | }
|
157 |
|
158 | _createContainer(ignoreBorder = false) {
|
159 | const data = this.data,
|
160 | page = this.page,
|
161 | viewport = this.viewport;
|
162 | const container = document.createElement("section");
|
163 | let width = data.rect[2] - data.rect[0];
|
164 | let height = data.rect[3] - data.rect[1];
|
165 | container.setAttribute("data-annotation-id", data.id);
|
166 |
|
167 | const rect = _util.Util.normalizeRect([data.rect[0], page.view[3] - data.rect[1] + page.view[1], data.rect[2], page.view[3] - data.rect[3] + page.view[1]]);
|
168 |
|
169 | if (data.hasOwnCanvas) {
|
170 | const transform = viewport.transform.slice();
|
171 |
|
172 | const [scaleX, scaleY] = _util.Util.singularValueDecompose2dScale(transform);
|
173 |
|
174 | width = Math.ceil(width * scaleX);
|
175 | height = Math.ceil(height * scaleY);
|
176 | rect[0] *= scaleX;
|
177 | rect[1] *= scaleY;
|
178 |
|
179 | for (let i = 0; i < 4; i++) {
|
180 | transform[i] = Math.sign(transform[i]);
|
181 | }
|
182 |
|
183 | container.style.transform = `matrix(${transform.join(",")})`;
|
184 | } else {
|
185 | container.style.transform = `matrix(${viewport.transform.join(",")})`;
|
186 | }
|
187 |
|
188 | container.style.transformOrigin = `${-rect[0]}px ${-rect[1]}px`;
|
189 |
|
190 | if (!ignoreBorder && data.borderStyle.width > 0) {
|
191 | container.style.borderWidth = `${data.borderStyle.width}px`;
|
192 |
|
193 | if (data.borderStyle.style !== _util.AnnotationBorderStyleType.UNDERLINE) {
|
194 | width -= 2 * data.borderStyle.width;
|
195 | height -= 2 * data.borderStyle.width;
|
196 | }
|
197 |
|
198 | const horizontalRadius = data.borderStyle.horizontalCornerRadius;
|
199 | const verticalRadius = data.borderStyle.verticalCornerRadius;
|
200 |
|
201 | if (horizontalRadius > 0 || verticalRadius > 0) {
|
202 | const radius = `${horizontalRadius}px / ${verticalRadius}px`;
|
203 | container.style.borderRadius = radius;
|
204 | }
|
205 |
|
206 | switch (data.borderStyle.style) {
|
207 | case _util.AnnotationBorderStyleType.SOLID:
|
208 | container.style.borderStyle = "solid";
|
209 | break;
|
210 |
|
211 | case _util.AnnotationBorderStyleType.DASHED:
|
212 | container.style.borderStyle = "dashed";
|
213 | break;
|
214 |
|
215 | case _util.AnnotationBorderStyleType.BEVELED:
|
216 | (0, _util.warn)("Unimplemented border style: beveled");
|
217 | break;
|
218 |
|
219 | case _util.AnnotationBorderStyleType.INSET:
|
220 | (0, _util.warn)("Unimplemented border style: inset");
|
221 | break;
|
222 |
|
223 | case _util.AnnotationBorderStyleType.UNDERLINE:
|
224 | container.style.borderBottomStyle = "solid";
|
225 | break;
|
226 |
|
227 | default:
|
228 | break;
|
229 | }
|
230 |
|
231 | const borderColor = data.borderColor || data.color || null;
|
232 |
|
233 | if (borderColor) {
|
234 | container.style.borderColor = _util.Util.makeHexColor(data.color[0] | 0, data.color[1] | 0, data.color[2] | 0);
|
235 | } else {
|
236 | container.style.borderWidth = 0;
|
237 | }
|
238 | }
|
239 |
|
240 | container.style.left = `${rect[0]}px`;
|
241 | container.style.top = `${rect[1]}px`;
|
242 |
|
243 | if (data.hasOwnCanvas) {
|
244 | container.style.width = container.style.height = "auto";
|
245 | } else {
|
246 | container.style.width = `${width}px`;
|
247 | container.style.height = `${height}px`;
|
248 | }
|
249 |
|
250 | return container;
|
251 | }
|
252 |
|
253 | _createQuadrilaterals(ignoreBorder = false) {
|
254 | if (!this.data.quadPoints) {
|
255 | return null;
|
256 | }
|
257 |
|
258 | const quadrilaterals = [];
|
259 | const savedRect = this.data.rect;
|
260 |
|
261 | for (const quadPoint of this.data.quadPoints) {
|
262 | this.data.rect = [quadPoint[2].x, quadPoint[2].y, quadPoint[1].x, quadPoint[1].y];
|
263 | quadrilaterals.push(this._createContainer(ignoreBorder));
|
264 | }
|
265 |
|
266 | this.data.rect = savedRect;
|
267 | return quadrilaterals;
|
268 | }
|
269 |
|
270 | _createPopup(trigger, data) {
|
271 | let container = this.container;
|
272 |
|
273 | if (this.quadrilaterals) {
|
274 | trigger = trigger || this.quadrilaterals;
|
275 | container = this.quadrilaterals[0];
|
276 | }
|
277 |
|
278 | if (!trigger) {
|
279 | trigger = document.createElement("div");
|
280 | trigger.style.height = container.style.height;
|
281 | trigger.style.width = container.style.width;
|
282 | container.appendChild(trigger);
|
283 | }
|
284 |
|
285 | const popupElement = new PopupElement({
|
286 | container,
|
287 | trigger,
|
288 | color: data.color,
|
289 | titleObj: data.titleObj,
|
290 | modificationDate: data.modificationDate,
|
291 | contentsObj: data.contentsObj,
|
292 | richText: data.richText,
|
293 | hideWrapper: true
|
294 | });
|
295 | const popup = popupElement.render();
|
296 | popup.style.left = container.style.width;
|
297 | container.appendChild(popup);
|
298 | }
|
299 |
|
300 | _renderQuadrilaterals(className) {
|
301 | for (const quadrilateral of this.quadrilaterals) {
|
302 | quadrilateral.className = className;
|
303 | }
|
304 |
|
305 | return this.quadrilaterals;
|
306 | }
|
307 |
|
308 | render() {
|
309 | (0, _util.unreachable)("Abstract method `AnnotationElement.render` called");
|
310 | }
|
311 |
|
312 | _getElementsByName(name, skipId = null) {
|
313 | const fields = [];
|
314 |
|
315 | if (this._fieldObjects) {
|
316 | const fieldObj = this._fieldObjects[name];
|
317 |
|
318 | if (fieldObj) {
|
319 | for (const {
|
320 | page,
|
321 | id,
|
322 | exportValues
|
323 | } of fieldObj) {
|
324 | if (page === -1) {
|
325 | continue;
|
326 | }
|
327 |
|
328 | if (id === skipId) {
|
329 | continue;
|
330 | }
|
331 |
|
332 | const exportValue = typeof exportValues === "string" ? exportValues : null;
|
333 | const domElement = document.getElementById(id);
|
334 |
|
335 | if (domElement && !GetElementsByNameSet.has(domElement)) {
|
336 | (0, _util.warn)(`_getElementsByName - element not allowed: ${id}`);
|
337 | continue;
|
338 | }
|
339 |
|
340 | fields.push({
|
341 | id,
|
342 | exportValue,
|
343 | domElement
|
344 | });
|
345 | }
|
346 | }
|
347 |
|
348 | return fields;
|
349 | }
|
350 |
|
351 | for (const domElement of document.getElementsByName(name)) {
|
352 | const {
|
353 | id,
|
354 | exportValue
|
355 | } = domElement;
|
356 |
|
357 | if (id === skipId) {
|
358 | continue;
|
359 | }
|
360 |
|
361 | if (!GetElementsByNameSet.has(domElement)) {
|
362 | continue;
|
363 | }
|
364 |
|
365 | fields.push({
|
366 | id,
|
367 | exportValue,
|
368 | domElement
|
369 | });
|
370 | }
|
371 |
|
372 | return fields;
|
373 | }
|
374 |
|
375 | static get platform() {
|
376 | const platform = typeof navigator !== "undefined" ? navigator.platform : "";
|
377 | return (0, _util.shadow)(this, "platform", {
|
378 | isWin: platform.includes("Win"),
|
379 | isMac: platform.includes("Mac")
|
380 | });
|
381 | }
|
382 |
|
383 | }
|
384 |
|
385 | class LinkAnnotationElement extends AnnotationElement {
|
386 | constructor(parameters, options = null) {
|
387 | const isRenderable = !!(parameters.data.url || parameters.data.dest || parameters.data.action || parameters.data.isTooltipOnly || parameters.data.resetForm || parameters.data.actions && (parameters.data.actions.Action || parameters.data.actions["Mouse Up"] || parameters.data.actions["Mouse Down"]));
|
388 | super(parameters, {
|
389 | isRenderable,
|
390 | ignoreBorder: !!options?.ignoreBorder,
|
391 | createQuadrilaterals: true
|
392 | });
|
393 | }
|
394 |
|
395 | render() {
|
396 | const {
|
397 | data,
|
398 | linkService
|
399 | } = this;
|
400 | const link = document.createElement("a");
|
401 |
|
402 | if (data.url) {
|
403 | if (!linkService.addLinkAttributes) {
|
404 | (0, _util.warn)("LinkAnnotationElement.render - missing `addLinkAttributes`-method on the `linkService`-instance.");
|
405 | }
|
406 |
|
407 | linkService.addLinkAttributes?.(link, data.url, data.newWindow);
|
408 | } else if (data.action) {
|
409 | this._bindNamedAction(link, data.action);
|
410 | } else if (data.dest) {
|
411 | this._bindLink(link, data.dest);
|
412 | } else {
|
413 | let hasClickAction = false;
|
414 |
|
415 | if (data.actions && (data.actions.Action || data.actions["Mouse Up"] || data.actions["Mouse Down"]) && this.enableScripting && this.hasJSActions) {
|
416 | hasClickAction = true;
|
417 |
|
418 | this._bindJSAction(link, data);
|
419 | }
|
420 |
|
421 | if (data.resetForm) {
|
422 | this._bindResetFormAction(link, data.resetForm);
|
423 | } else if (!hasClickAction) {
|
424 | this._bindLink(link, "");
|
425 | }
|
426 | }
|
427 |
|
428 | if (this.quadrilaterals) {
|
429 | return this._renderQuadrilaterals("linkAnnotation").map((quadrilateral, index) => {
|
430 | const linkElement = index === 0 ? link : link.cloneNode();
|
431 | quadrilateral.appendChild(linkElement);
|
432 | return quadrilateral;
|
433 | });
|
434 | }
|
435 |
|
436 | this.container.className = "linkAnnotation";
|
437 | this.container.appendChild(link);
|
438 | return this.container;
|
439 | }
|
440 |
|
441 | _bindLink(link, destination) {
|
442 | link.href = this.linkService.getDestinationHash(destination);
|
443 |
|
444 | link.onclick = () => {
|
445 | if (destination) {
|
446 | this.linkService.goToDestination(destination);
|
447 | }
|
448 |
|
449 | return false;
|
450 | };
|
451 |
|
452 | if (destination || destination === "") {
|
453 | link.className = "internalLink";
|
454 | }
|
455 | }
|
456 |
|
457 | _bindNamedAction(link, action) {
|
458 | link.href = this.linkService.getAnchorUrl("");
|
459 |
|
460 | link.onclick = () => {
|
461 | this.linkService.executeNamedAction(action);
|
462 | return false;
|
463 | };
|
464 |
|
465 | link.className = "internalLink";
|
466 | }
|
467 |
|
468 | _bindJSAction(link, data) {
|
469 | link.href = this.linkService.getAnchorUrl("");
|
470 | const map = new Map([["Action", "onclick"], ["Mouse Up", "onmouseup"], ["Mouse Down", "onmousedown"]]);
|
471 |
|
472 | for (const name of Object.keys(data.actions)) {
|
473 | const jsName = map.get(name);
|
474 |
|
475 | if (!jsName) {
|
476 | continue;
|
477 | }
|
478 |
|
479 | link[jsName] = () => {
|
480 | this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
|
481 | source: this,
|
482 | detail: {
|
483 | id: data.id,
|
484 | name
|
485 | }
|
486 | });
|
487 | return false;
|
488 | };
|
489 | }
|
490 |
|
491 | if (!link.onclick) {
|
492 | link.onclick = () => false;
|
493 | }
|
494 |
|
495 | link.className = "internalLink";
|
496 | }
|
497 |
|
498 | _bindResetFormAction(link, resetForm) {
|
499 | const otherClickAction = link.onclick;
|
500 |
|
501 | if (!otherClickAction) {
|
502 | link.href = this.linkService.getAnchorUrl("");
|
503 | }
|
504 |
|
505 | link.className = "internalLink";
|
506 |
|
507 | if (!this._fieldObjects) {
|
508 | (0, _util.warn)(`_bindResetFormAction - "resetForm" action not supported, ` + "ensure that the `fieldObjects` parameter is provided.");
|
509 |
|
510 | if (!otherClickAction) {
|
511 | link.onclick = () => false;
|
512 | }
|
513 |
|
514 | return;
|
515 | }
|
516 |
|
517 | link.onclick = () => {
|
518 | if (otherClickAction) {
|
519 | otherClickAction();
|
520 | }
|
521 |
|
522 | const {
|
523 | fields: resetFormFields,
|
524 | refs: resetFormRefs,
|
525 | include
|
526 | } = resetForm;
|
527 | const allFields = [];
|
528 |
|
529 | if (resetFormFields.length !== 0 || resetFormRefs.length !== 0) {
|
530 | const fieldIds = new Set(resetFormRefs);
|
531 |
|
532 | for (const fieldName of resetFormFields) {
|
533 | const fields = this._fieldObjects[fieldName] || [];
|
534 |
|
535 | for (const {
|
536 | id
|
537 | } of fields) {
|
538 | fieldIds.add(id);
|
539 | }
|
540 | }
|
541 |
|
542 | for (const fields of Object.values(this._fieldObjects)) {
|
543 | for (const field of fields) {
|
544 | if (fieldIds.has(field.id) === include) {
|
545 | allFields.push(field);
|
546 | }
|
547 | }
|
548 | }
|
549 | } else {
|
550 | for (const fields of Object.values(this._fieldObjects)) {
|
551 | allFields.push(...fields);
|
552 | }
|
553 | }
|
554 |
|
555 | const storage = this.annotationStorage;
|
556 | const allIds = [];
|
557 |
|
558 | for (const field of allFields) {
|
559 | const {
|
560 | id
|
561 | } = field;
|
562 | allIds.push(id);
|
563 |
|
564 | switch (field.type) {
|
565 | case "text":
|
566 | {
|
567 | const value = field.defaultValue || "";
|
568 | storage.setValue(id, {
|
569 | value,
|
570 | valueAsString: value
|
571 | });
|
572 | break;
|
573 | }
|
574 |
|
575 | case "checkbox":
|
576 | case "radiobutton":
|
577 | {
|
578 | const value = field.defaultValue === field.exportValues;
|
579 | storage.setValue(id, {
|
580 | value
|
581 | });
|
582 | break;
|
583 | }
|
584 |
|
585 | case "combobox":
|
586 | case "listbox":
|
587 | {
|
588 | const value = field.defaultValue || "";
|
589 | storage.setValue(id, {
|
590 | value
|
591 | });
|
592 | break;
|
593 | }
|
594 |
|
595 | default:
|
596 | continue;
|
597 | }
|
598 |
|
599 | const domElement = document.getElementById(id);
|
600 |
|
601 | if (!domElement || !GetElementsByNameSet.has(domElement)) {
|
602 | continue;
|
603 | }
|
604 |
|
605 | domElement.dispatchEvent(new Event("resetform"));
|
606 | }
|
607 |
|
608 | if (this.enableScripting) {
|
609 | this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
|
610 | source: this,
|
611 | detail: {
|
612 | id: "app",
|
613 | ids: allIds,
|
614 | name: "ResetForm"
|
615 | }
|
616 | });
|
617 | }
|
618 |
|
619 | return false;
|
620 | };
|
621 | }
|
622 |
|
623 | }
|
624 |
|
625 | class TextAnnotationElement extends AnnotationElement {
|
626 | constructor(parameters) {
|
627 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
628 | super(parameters, {
|
629 | isRenderable
|
630 | });
|
631 | }
|
632 |
|
633 | render() {
|
634 | this.container.className = "textAnnotation";
|
635 | const image = document.createElement("img");
|
636 | image.style.height = this.container.style.height;
|
637 | image.style.width = this.container.style.width;
|
638 | image.src = this.imageResourcesPath + "annotation-" + this.data.name.toLowerCase() + ".svg";
|
639 | image.alt = "[{{type}} Annotation]";
|
640 | image.dataset.l10nId = "text_annotation_type";
|
641 | image.dataset.l10nArgs = JSON.stringify({
|
642 | type: this.data.name
|
643 | });
|
644 |
|
645 | if (!this.data.hasPopup) {
|
646 | this._createPopup(image, this.data);
|
647 | }
|
648 |
|
649 | this.container.appendChild(image);
|
650 | return this.container;
|
651 | }
|
652 |
|
653 | }
|
654 |
|
655 | class WidgetAnnotationElement extends AnnotationElement {
|
656 | render() {
|
657 | if (this.data.alternativeText) {
|
658 | this.container.title = this.data.alternativeText;
|
659 | }
|
660 |
|
661 | return this.container;
|
662 | }
|
663 |
|
664 | _getKeyModifier(event) {
|
665 | const {
|
666 | isWin,
|
667 | isMac
|
668 | } = AnnotationElement.platform;
|
669 | return isWin && event.ctrlKey || isMac && event.metaKey;
|
670 | }
|
671 |
|
672 | _setEventListener(element, baseName, eventName, valueGetter) {
|
673 | if (baseName.includes("mouse")) {
|
674 | element.addEventListener(baseName, event => {
|
675 | this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
|
676 | source: this,
|
677 | detail: {
|
678 | id: this.data.id,
|
679 | name: eventName,
|
680 | value: valueGetter(event),
|
681 | shift: event.shiftKey,
|
682 | modifier: this._getKeyModifier(event)
|
683 | }
|
684 | });
|
685 | });
|
686 | } else {
|
687 | element.addEventListener(baseName, event => {
|
688 | this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
|
689 | source: this,
|
690 | detail: {
|
691 | id: this.data.id,
|
692 | name: eventName,
|
693 | value: event.target.checked
|
694 | }
|
695 | });
|
696 | });
|
697 | }
|
698 | }
|
699 |
|
700 | _setEventListeners(element, names, getter) {
|
701 | for (const [baseName, eventName] of names) {
|
702 | if (eventName === "Action" || this.data.actions?.[eventName]) {
|
703 | this._setEventListener(element, baseName, eventName, getter);
|
704 | }
|
705 | }
|
706 | }
|
707 |
|
708 | _setBackgroundColor(element) {
|
709 | const color = this.data.backgroundColor || null;
|
710 | element.style.backgroundColor = color === null ? "transparent" : _util.Util.makeHexColor(color[0], color[1], color[2]);
|
711 | }
|
712 |
|
713 | _dispatchEventFromSandbox(actions, jsEvent) {
|
714 | const setColor = (jsName, styleName, event) => {
|
715 | const color = event.detail[jsName];
|
716 | event.target.style[styleName] = _scripting_utils.ColorConverters[`${color[0]}_HTML`](color.slice(1));
|
717 | };
|
718 |
|
719 | const commonActions = {
|
720 | display: event => {
|
721 | const hidden = event.detail.display % 2 === 1;
|
722 | event.target.style.visibility = hidden ? "hidden" : "visible";
|
723 | this.annotationStorage.setValue(this.data.id, {
|
724 | hidden,
|
725 | print: event.detail.display === 0 || event.detail.display === 3
|
726 | });
|
727 | },
|
728 | print: event => {
|
729 | this.annotationStorage.setValue(this.data.id, {
|
730 | print: event.detail.print
|
731 | });
|
732 | },
|
733 | hidden: event => {
|
734 | event.target.style.visibility = event.detail.hidden ? "hidden" : "visible";
|
735 | this.annotationStorage.setValue(this.data.id, {
|
736 | hidden: event.detail.hidden
|
737 | });
|
738 | },
|
739 | focus: event => {
|
740 | setTimeout(() => event.target.focus({
|
741 | preventScroll: false
|
742 | }), 0);
|
743 | },
|
744 | userName: event => {
|
745 | event.target.title = event.detail.userName;
|
746 | },
|
747 | readonly: event => {
|
748 | if (event.detail.readonly) {
|
749 | event.target.setAttribute("readonly", "");
|
750 | } else {
|
751 | event.target.removeAttribute("readonly");
|
752 | }
|
753 | },
|
754 | required: event => {
|
755 | if (event.detail.required) {
|
756 | event.target.setAttribute("required", "");
|
757 | } else {
|
758 | event.target.removeAttribute("required");
|
759 | }
|
760 | },
|
761 | bgColor: event => {
|
762 | setColor("bgColor", "backgroundColor", event);
|
763 | },
|
764 | fillColor: event => {
|
765 | setColor("fillColor", "backgroundColor", event);
|
766 | },
|
767 | fgColor: event => {
|
768 | setColor("fgColor", "color", event);
|
769 | },
|
770 | textColor: event => {
|
771 | setColor("textColor", "color", event);
|
772 | },
|
773 | borderColor: event => {
|
774 | setColor("borderColor", "borderColor", event);
|
775 | },
|
776 | strokeColor: event => {
|
777 | setColor("strokeColor", "borderColor", event);
|
778 | }
|
779 | };
|
780 |
|
781 | for (const name of Object.keys(jsEvent.detail)) {
|
782 | const action = actions[name] || commonActions[name];
|
783 |
|
784 | if (action) {
|
785 | action(jsEvent);
|
786 | }
|
787 | }
|
788 | }
|
789 |
|
790 | }
|
791 |
|
792 | class TextWidgetAnnotationElement extends WidgetAnnotationElement {
|
793 | constructor(parameters) {
|
794 | const isRenderable = parameters.renderForms || !parameters.data.hasAppearance && !!parameters.data.fieldValue;
|
795 | super(parameters, {
|
796 | isRenderable
|
797 | });
|
798 | }
|
799 |
|
800 | setPropertyOnSiblings(base, key, value, keyInStorage) {
|
801 | const storage = this.annotationStorage;
|
802 |
|
803 | for (const element of this._getElementsByName(base.name, base.id)) {
|
804 | if (element.domElement) {
|
805 | element.domElement[key] = value;
|
806 | }
|
807 |
|
808 | storage.setValue(element.id, {
|
809 | [keyInStorage]: value
|
810 | });
|
811 | }
|
812 | }
|
813 |
|
814 | render() {
|
815 | const storage = this.annotationStorage;
|
816 | const id = this.data.id;
|
817 | this.container.className = "textWidgetAnnotation";
|
818 | let element = null;
|
819 |
|
820 | if (this.renderForms) {
|
821 | const storedData = storage.getValue(id, {
|
822 | value: this.data.fieldValue,
|
823 | valueAsString: this.data.fieldValue
|
824 | });
|
825 | const textContent = storedData.valueAsString || storedData.value || "";
|
826 | const elementData = {
|
827 | userValue: null,
|
828 | formattedValue: null,
|
829 | beforeInputSelectionRange: null,
|
830 | beforeInputValue: null
|
831 | };
|
832 |
|
833 | if (this.data.multiLine) {
|
834 | element = document.createElement("textarea");
|
835 | element.textContent = textContent;
|
836 | } else {
|
837 | element = document.createElement("input");
|
838 | element.type = "text";
|
839 | element.setAttribute("value", textContent);
|
840 | }
|
841 |
|
842 | GetElementsByNameSet.add(element);
|
843 | element.disabled = this.data.readOnly;
|
844 | element.name = this.data.fieldName;
|
845 | element.tabIndex = DEFAULT_TAB_INDEX;
|
846 | elementData.userValue = textContent;
|
847 | element.setAttribute("id", id);
|
848 | element.addEventListener("input", event => {
|
849 | storage.setValue(id, {
|
850 | value: event.target.value
|
851 | });
|
852 | this.setPropertyOnSiblings(element, "value", event.target.value, "value");
|
853 | });
|
854 | element.addEventListener("resetform", event => {
|
855 | const defaultValue = this.data.defaultFieldValue || "";
|
856 | element.value = elementData.userValue = defaultValue;
|
857 | delete elementData.formattedValue;
|
858 | });
|
859 |
|
860 | let blurListener = event => {
|
861 | if (elementData.formattedValue) {
|
862 | event.target.value = elementData.formattedValue;
|
863 | }
|
864 |
|
865 | event.target.scrollLeft = 0;
|
866 | elementData.beforeInputSelectionRange = null;
|
867 | };
|
868 |
|
869 | if (this.enableScripting && this.hasJSActions) {
|
870 | element.addEventListener("focus", event => {
|
871 | if (elementData.userValue) {
|
872 | event.target.value = elementData.userValue;
|
873 | }
|
874 | });
|
875 | element.addEventListener("updatefromsandbox", jsEvent => {
|
876 | const actions = {
|
877 | value(event) {
|
878 | elementData.userValue = event.detail.value || "";
|
879 | storage.setValue(id, {
|
880 | value: elementData.userValue.toString()
|
881 | });
|
882 |
|
883 | if (!elementData.formattedValue) {
|
884 | event.target.value = elementData.userValue;
|
885 | }
|
886 | },
|
887 |
|
888 | valueAsString(event) {
|
889 | elementData.formattedValue = event.detail.valueAsString || "";
|
890 |
|
891 | if (event.target !== document.activeElement) {
|
892 | event.target.value = elementData.formattedValue;
|
893 | }
|
894 |
|
895 | storage.setValue(id, {
|
896 | formattedValue: elementData.formattedValue
|
897 | });
|
898 | },
|
899 |
|
900 | selRange(event) {
|
901 | const [selStart, selEnd] = event.detail.selRange;
|
902 |
|
903 | if (selStart >= 0 && selEnd < event.target.value.length) {
|
904 | event.target.setSelectionRange(selStart, selEnd);
|
905 | }
|
906 | }
|
907 |
|
908 | };
|
909 |
|
910 | this._dispatchEventFromSandbox(actions, jsEvent);
|
911 | });
|
912 | element.addEventListener("keydown", event => {
|
913 | elementData.beforeInputValue = event.target.value;
|
914 | let commitKey = -1;
|
915 |
|
916 | if (event.key === "Escape") {
|
917 | commitKey = 0;
|
918 | } else if (event.key === "Enter") {
|
919 | commitKey = 2;
|
920 | } else if (event.key === "Tab") {
|
921 | commitKey = 3;
|
922 | }
|
923 |
|
924 | if (commitKey === -1) {
|
925 | return;
|
926 | }
|
927 |
|
928 | elementData.userValue = event.target.value;
|
929 | this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
|
930 | source: this,
|
931 | detail: {
|
932 | id,
|
933 | name: "Keystroke",
|
934 | value: event.target.value,
|
935 | willCommit: true,
|
936 | commitKey,
|
937 | selStart: event.target.selectionStart,
|
938 | selEnd: event.target.selectionEnd
|
939 | }
|
940 | });
|
941 | });
|
942 | const _blurListener = blurListener;
|
943 | blurListener = null;
|
944 | element.addEventListener("blur", event => {
|
945 | if (this._mouseState.isDown) {
|
946 | elementData.userValue = event.target.value;
|
947 | this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
|
948 | source: this,
|
949 | detail: {
|
950 | id,
|
951 | name: "Keystroke",
|
952 | value: event.target.value,
|
953 | willCommit: true,
|
954 | commitKey: 1,
|
955 | selStart: event.target.selectionStart,
|
956 | selEnd: event.target.selectionEnd
|
957 | }
|
958 | });
|
959 | }
|
960 |
|
961 | _blurListener(event);
|
962 | });
|
963 | element.addEventListener("mousedown", event => {
|
964 | elementData.beforeInputValue = event.target.value;
|
965 | elementData.beforeInputSelectionRange = null;
|
966 | });
|
967 | element.addEventListener("keyup", event => {
|
968 | if (event.target.selectionStart === event.target.selectionEnd) {
|
969 | elementData.beforeInputSelectionRange = null;
|
970 | }
|
971 | });
|
972 | element.addEventListener("select", event => {
|
973 | elementData.beforeInputSelectionRange = [event.target.selectionStart, event.target.selectionEnd];
|
974 | });
|
975 |
|
976 | if (this.data.actions?.Keystroke) {
|
977 | element.addEventListener("input", event => {
|
978 | let selStart = -1;
|
979 | let selEnd = -1;
|
980 |
|
981 | if (elementData.beforeInputSelectionRange) {
|
982 | [selStart, selEnd] = elementData.beforeInputSelectionRange;
|
983 | }
|
984 |
|
985 | this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
|
986 | source: this,
|
987 | detail: {
|
988 | id,
|
989 | name: "Keystroke",
|
990 | value: elementData.beforeInputValue,
|
991 | change: event.data,
|
992 | willCommit: false,
|
993 | selStart,
|
994 | selEnd
|
995 | }
|
996 | });
|
997 | });
|
998 | }
|
999 |
|
1000 | this._setEventListeners(element, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.value);
|
1001 | }
|
1002 |
|
1003 | if (blurListener) {
|
1004 | element.addEventListener("blur", blurListener);
|
1005 | }
|
1006 |
|
1007 | if (this.data.maxLen !== null) {
|
1008 | element.maxLength = this.data.maxLen;
|
1009 | }
|
1010 |
|
1011 | if (this.data.comb) {
|
1012 | const fieldWidth = this.data.rect[2] - this.data.rect[0];
|
1013 | const combWidth = fieldWidth / this.data.maxLen;
|
1014 | element.classList.add("comb");
|
1015 | element.style.letterSpacing = `calc(${combWidth}px - 1ch)`;
|
1016 | }
|
1017 | } else {
|
1018 | element = document.createElement("div");
|
1019 | element.textContent = this.data.fieldValue;
|
1020 | element.style.verticalAlign = "middle";
|
1021 | element.style.display = "table-cell";
|
1022 | }
|
1023 |
|
1024 | this._setTextStyle(element);
|
1025 |
|
1026 | this._setBackgroundColor(element);
|
1027 |
|
1028 | this.container.appendChild(element);
|
1029 | return this.container;
|
1030 | }
|
1031 |
|
1032 | _setTextStyle(element) {
|
1033 | const TEXT_ALIGNMENT = ["left", "center", "right"];
|
1034 | const {
|
1035 | fontSize,
|
1036 | fontColor
|
1037 | } = this.data.defaultAppearanceData;
|
1038 | const style = element.style;
|
1039 |
|
1040 | if (fontSize) {
|
1041 | style.fontSize = `${fontSize}px`;
|
1042 | }
|
1043 |
|
1044 | style.color = _util.Util.makeHexColor(fontColor[0], fontColor[1], fontColor[2]);
|
1045 |
|
1046 | if (this.data.textAlignment !== null) {
|
1047 | style.textAlign = TEXT_ALIGNMENT[this.data.textAlignment];
|
1048 | }
|
1049 | }
|
1050 |
|
1051 | }
|
1052 |
|
1053 | class CheckboxWidgetAnnotationElement extends WidgetAnnotationElement {
|
1054 | constructor(parameters) {
|
1055 | super(parameters, {
|
1056 | isRenderable: parameters.renderForms
|
1057 | });
|
1058 | }
|
1059 |
|
1060 | render() {
|
1061 | const storage = this.annotationStorage;
|
1062 | const data = this.data;
|
1063 | const id = data.id;
|
1064 | let value = storage.getValue(id, {
|
1065 | value: data.exportValue === data.fieldValue
|
1066 | }).value;
|
1067 |
|
1068 | if (typeof value === "string") {
|
1069 | value = value !== "Off";
|
1070 | storage.setValue(id, {
|
1071 | value
|
1072 | });
|
1073 | }
|
1074 |
|
1075 | this.container.className = "buttonWidgetAnnotation checkBox";
|
1076 | const element = document.createElement("input");
|
1077 | GetElementsByNameSet.add(element);
|
1078 | element.disabled = data.readOnly;
|
1079 | element.type = "checkbox";
|
1080 | element.name = data.fieldName;
|
1081 |
|
1082 | if (value) {
|
1083 | element.setAttribute("checked", true);
|
1084 | }
|
1085 |
|
1086 | element.setAttribute("id", id);
|
1087 | element.setAttribute("exportValue", data.exportValue);
|
1088 | element.tabIndex = DEFAULT_TAB_INDEX;
|
1089 | element.addEventListener("change", event => {
|
1090 | const {
|
1091 | name,
|
1092 | checked
|
1093 | } = event.target;
|
1094 |
|
1095 | for (const checkbox of this._getElementsByName(name, id)) {
|
1096 | const curChecked = checked && checkbox.exportValue === data.exportValue;
|
1097 |
|
1098 | if (checkbox.domElement) {
|
1099 | checkbox.domElement.checked = curChecked;
|
1100 | }
|
1101 |
|
1102 | storage.setValue(checkbox.id, {
|
1103 | value: curChecked
|
1104 | });
|
1105 | }
|
1106 |
|
1107 | storage.setValue(id, {
|
1108 | value: checked
|
1109 | });
|
1110 | });
|
1111 | element.addEventListener("resetform", event => {
|
1112 | const defaultValue = data.defaultFieldValue || "Off";
|
1113 | event.target.checked = defaultValue === data.exportValue;
|
1114 | });
|
1115 |
|
1116 | if (this.enableScripting && this.hasJSActions) {
|
1117 | element.addEventListener("updatefromsandbox", jsEvent => {
|
1118 | const actions = {
|
1119 | value(event) {
|
1120 | event.target.checked = event.detail.value !== "Off";
|
1121 | storage.setValue(id, {
|
1122 | value: event.target.checked
|
1123 | });
|
1124 | }
|
1125 |
|
1126 | };
|
1127 |
|
1128 | this._dispatchEventFromSandbox(actions, jsEvent);
|
1129 | });
|
1130 |
|
1131 | this._setEventListeners(element, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked);
|
1132 | }
|
1133 |
|
1134 | this._setBackgroundColor(element);
|
1135 |
|
1136 | this.container.appendChild(element);
|
1137 | return this.container;
|
1138 | }
|
1139 |
|
1140 | }
|
1141 |
|
1142 | class RadioButtonWidgetAnnotationElement extends WidgetAnnotationElement {
|
1143 | constructor(parameters) {
|
1144 | super(parameters, {
|
1145 | isRenderable: parameters.renderForms
|
1146 | });
|
1147 | }
|
1148 |
|
1149 | render() {
|
1150 | this.container.className = "buttonWidgetAnnotation radioButton";
|
1151 | const storage = this.annotationStorage;
|
1152 | const data = this.data;
|
1153 | const id = data.id;
|
1154 | let value = storage.getValue(id, {
|
1155 | value: data.fieldValue === data.buttonValue
|
1156 | }).value;
|
1157 |
|
1158 | if (typeof value === "string") {
|
1159 | value = value !== data.buttonValue;
|
1160 | storage.setValue(id, {
|
1161 | value
|
1162 | });
|
1163 | }
|
1164 |
|
1165 | const element = document.createElement("input");
|
1166 | GetElementsByNameSet.add(element);
|
1167 | element.disabled = data.readOnly;
|
1168 | element.type = "radio";
|
1169 | element.name = data.fieldName;
|
1170 |
|
1171 | if (value) {
|
1172 | element.setAttribute("checked", true);
|
1173 | }
|
1174 |
|
1175 | element.setAttribute("id", id);
|
1176 | element.tabIndex = DEFAULT_TAB_INDEX;
|
1177 | element.addEventListener("change", event => {
|
1178 | const {
|
1179 | name,
|
1180 | checked
|
1181 | } = event.target;
|
1182 |
|
1183 | for (const radio of this._getElementsByName(name, id)) {
|
1184 | storage.setValue(radio.id, {
|
1185 | value: false
|
1186 | });
|
1187 | }
|
1188 |
|
1189 | storage.setValue(id, {
|
1190 | value: checked
|
1191 | });
|
1192 | });
|
1193 | element.addEventListener("resetform", event => {
|
1194 | const defaultValue = data.defaultFieldValue;
|
1195 | event.target.checked = defaultValue !== null && defaultValue !== undefined && defaultValue === data.buttonValue;
|
1196 | });
|
1197 |
|
1198 | if (this.enableScripting && this.hasJSActions) {
|
1199 | const pdfButtonValue = data.buttonValue;
|
1200 | element.addEventListener("updatefromsandbox", jsEvent => {
|
1201 | const actions = {
|
1202 | value: event => {
|
1203 | const checked = pdfButtonValue === event.detail.value;
|
1204 |
|
1205 | for (const radio of this._getElementsByName(event.target.name)) {
|
1206 | const curChecked = checked && radio.id === id;
|
1207 |
|
1208 | if (radio.domElement) {
|
1209 | radio.domElement.checked = curChecked;
|
1210 | }
|
1211 |
|
1212 | storage.setValue(radio.id, {
|
1213 | value: curChecked
|
1214 | });
|
1215 | }
|
1216 | }
|
1217 | };
|
1218 |
|
1219 | this._dispatchEventFromSandbox(actions, jsEvent);
|
1220 | });
|
1221 |
|
1222 | this._setEventListeners(element, [["change", "Validate"], ["change", "Action"], ["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"]], event => event.target.checked);
|
1223 | }
|
1224 |
|
1225 | this._setBackgroundColor(element);
|
1226 |
|
1227 | this.container.appendChild(element);
|
1228 | return this.container;
|
1229 | }
|
1230 |
|
1231 | }
|
1232 |
|
1233 | class PushButtonWidgetAnnotationElement extends LinkAnnotationElement {
|
1234 | constructor(parameters) {
|
1235 | super(parameters, {
|
1236 | ignoreBorder: parameters.data.hasAppearance
|
1237 | });
|
1238 | }
|
1239 |
|
1240 | render() {
|
1241 | const container = super.render();
|
1242 | container.className = "buttonWidgetAnnotation pushButton";
|
1243 |
|
1244 | if (this.data.alternativeText) {
|
1245 | container.title = this.data.alternativeText;
|
1246 | }
|
1247 |
|
1248 | return container;
|
1249 | }
|
1250 |
|
1251 | }
|
1252 |
|
1253 | class ChoiceWidgetAnnotationElement extends WidgetAnnotationElement {
|
1254 | constructor(parameters) {
|
1255 | super(parameters, {
|
1256 | isRenderable: parameters.renderForms
|
1257 | });
|
1258 | }
|
1259 |
|
1260 | render() {
|
1261 | this.container.className = "choiceWidgetAnnotation";
|
1262 | const storage = this.annotationStorage;
|
1263 | const id = this.data.id;
|
1264 | storage.getValue(id, {
|
1265 | value: this.data.fieldValue.length > 0 ? this.data.fieldValue[0] : undefined
|
1266 | });
|
1267 | let {
|
1268 | fontSize
|
1269 | } = this.data.defaultAppearanceData;
|
1270 |
|
1271 | if (!fontSize) {
|
1272 | fontSize = 9;
|
1273 | }
|
1274 |
|
1275 | const fontSizeStyle = `calc(${fontSize}px * var(--zoom-factor))`;
|
1276 | const selectElement = document.createElement("select");
|
1277 | GetElementsByNameSet.add(selectElement);
|
1278 | selectElement.disabled = this.data.readOnly;
|
1279 | selectElement.name = this.data.fieldName;
|
1280 | selectElement.setAttribute("id", id);
|
1281 | selectElement.tabIndex = DEFAULT_TAB_INDEX;
|
1282 | selectElement.style.fontSize = `${fontSize}px`;
|
1283 |
|
1284 | if (!this.data.combo) {
|
1285 | selectElement.size = this.data.options.length;
|
1286 |
|
1287 | if (this.data.multiSelect) {
|
1288 | selectElement.multiple = true;
|
1289 | }
|
1290 | }
|
1291 |
|
1292 | selectElement.addEventListener("resetform", event => {
|
1293 | const defaultValue = this.data.defaultFieldValue;
|
1294 |
|
1295 | for (const option of selectElement.options) {
|
1296 | option.selected = option.value === defaultValue;
|
1297 | }
|
1298 | });
|
1299 |
|
1300 | for (const option of this.data.options) {
|
1301 | const optionElement = document.createElement("option");
|
1302 | optionElement.textContent = option.displayValue;
|
1303 | optionElement.value = option.exportValue;
|
1304 |
|
1305 | if (this.data.combo) {
|
1306 | optionElement.style.fontSize = fontSizeStyle;
|
1307 | }
|
1308 |
|
1309 | if (this.data.fieldValue.includes(option.exportValue)) {
|
1310 | optionElement.setAttribute("selected", true);
|
1311 | }
|
1312 |
|
1313 | selectElement.appendChild(optionElement);
|
1314 | }
|
1315 |
|
1316 | const getValue = (event, isExport) => {
|
1317 | const name = isExport ? "value" : "textContent";
|
1318 | const options = event.target.options;
|
1319 |
|
1320 | if (!event.target.multiple) {
|
1321 | return options.selectedIndex === -1 ? null : options[options.selectedIndex][name];
|
1322 | }
|
1323 |
|
1324 | return Array.prototype.filter.call(options, option => option.selected).map(option => option[name]);
|
1325 | };
|
1326 |
|
1327 | const getItems = event => {
|
1328 | const options = event.target.options;
|
1329 | return Array.prototype.map.call(options, option => {
|
1330 | return {
|
1331 | displayValue: option.textContent,
|
1332 | exportValue: option.value
|
1333 | };
|
1334 | });
|
1335 | };
|
1336 |
|
1337 | if (this.enableScripting && this.hasJSActions) {
|
1338 | selectElement.addEventListener("updatefromsandbox", jsEvent => {
|
1339 | const actions = {
|
1340 | value(event) {
|
1341 | const value = event.detail.value;
|
1342 | const values = new Set(Array.isArray(value) ? value : [value]);
|
1343 |
|
1344 | for (const option of selectElement.options) {
|
1345 | option.selected = values.has(option.value);
|
1346 | }
|
1347 |
|
1348 | storage.setValue(id, {
|
1349 | value: getValue(event, true)
|
1350 | });
|
1351 | },
|
1352 |
|
1353 | multipleSelection(event) {
|
1354 | selectElement.multiple = true;
|
1355 | },
|
1356 |
|
1357 | remove(event) {
|
1358 | const options = selectElement.options;
|
1359 | const index = event.detail.remove;
|
1360 | options[index].selected = false;
|
1361 | selectElement.remove(index);
|
1362 |
|
1363 | if (options.length > 0) {
|
1364 | const i = Array.prototype.findIndex.call(options, option => option.selected);
|
1365 |
|
1366 | if (i === -1) {
|
1367 | options[0].selected = true;
|
1368 | }
|
1369 | }
|
1370 |
|
1371 | storage.setValue(id, {
|
1372 | value: getValue(event, true),
|
1373 | items: getItems(event)
|
1374 | });
|
1375 | },
|
1376 |
|
1377 | clear(event) {
|
1378 | while (selectElement.length !== 0) {
|
1379 | selectElement.remove(0);
|
1380 | }
|
1381 |
|
1382 | storage.setValue(id, {
|
1383 | value: null,
|
1384 | items: []
|
1385 | });
|
1386 | },
|
1387 |
|
1388 | insert(event) {
|
1389 | const {
|
1390 | index,
|
1391 | displayValue,
|
1392 | exportValue
|
1393 | } = event.detail.insert;
|
1394 | const optionElement = document.createElement("option");
|
1395 | optionElement.textContent = displayValue;
|
1396 | optionElement.value = exportValue;
|
1397 | selectElement.insertBefore(optionElement, selectElement.children[index]);
|
1398 | storage.setValue(id, {
|
1399 | value: getValue(event, true),
|
1400 | items: getItems(event)
|
1401 | });
|
1402 | },
|
1403 |
|
1404 | items(event) {
|
1405 | const {
|
1406 | items
|
1407 | } = event.detail;
|
1408 |
|
1409 | while (selectElement.length !== 0) {
|
1410 | selectElement.remove(0);
|
1411 | }
|
1412 |
|
1413 | for (const item of items) {
|
1414 | const {
|
1415 | displayValue,
|
1416 | exportValue
|
1417 | } = item;
|
1418 | const optionElement = document.createElement("option");
|
1419 | optionElement.textContent = displayValue;
|
1420 | optionElement.value = exportValue;
|
1421 | selectElement.appendChild(optionElement);
|
1422 | }
|
1423 |
|
1424 | if (selectElement.options.length > 0) {
|
1425 | selectElement.options[0].selected = true;
|
1426 | }
|
1427 |
|
1428 | storage.setValue(id, {
|
1429 | value: getValue(event, true),
|
1430 | items: getItems(event)
|
1431 | });
|
1432 | },
|
1433 |
|
1434 | indices(event) {
|
1435 | const indices = new Set(event.detail.indices);
|
1436 |
|
1437 | for (const option of event.target.options) {
|
1438 | option.selected = indices.has(option.index);
|
1439 | }
|
1440 |
|
1441 | storage.setValue(id, {
|
1442 | value: getValue(event, true)
|
1443 | });
|
1444 | },
|
1445 |
|
1446 | editable(event) {
|
1447 | event.target.disabled = !event.detail.editable;
|
1448 | }
|
1449 |
|
1450 | };
|
1451 |
|
1452 | this._dispatchEventFromSandbox(actions, jsEvent);
|
1453 | });
|
1454 | selectElement.addEventListener("input", event => {
|
1455 | const exportValue = getValue(event, true);
|
1456 | const value = getValue(event, false);
|
1457 | storage.setValue(id, {
|
1458 | value: exportValue
|
1459 | });
|
1460 | this.linkService.eventBus?.dispatch("dispatcheventinsandbox", {
|
1461 | source: this,
|
1462 | detail: {
|
1463 | id,
|
1464 | name: "Keystroke",
|
1465 | value,
|
1466 | changeEx: exportValue,
|
1467 | willCommit: true,
|
1468 | commitKey: 1,
|
1469 | keyDown: false
|
1470 | }
|
1471 | });
|
1472 | });
|
1473 |
|
1474 | this._setEventListeners(selectElement, [["focus", "Focus"], ["blur", "Blur"], ["mousedown", "Mouse Down"], ["mouseenter", "Mouse Enter"], ["mouseleave", "Mouse Exit"], ["mouseup", "Mouse Up"], ["input", "Action"]], event => event.target.checked);
|
1475 | } else {
|
1476 | selectElement.addEventListener("input", function (event) {
|
1477 | storage.setValue(id, {
|
1478 | value: getValue(event)
|
1479 | });
|
1480 | });
|
1481 | }
|
1482 |
|
1483 | this._setBackgroundColor(selectElement);
|
1484 |
|
1485 | this.container.appendChild(selectElement);
|
1486 | return this.container;
|
1487 | }
|
1488 |
|
1489 | }
|
1490 |
|
1491 | class PopupAnnotationElement extends AnnotationElement {
|
1492 | constructor(parameters) {
|
1493 | const isRenderable = !!(parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1494 | super(parameters, {
|
1495 | isRenderable
|
1496 | });
|
1497 | }
|
1498 |
|
1499 | render() {
|
1500 | const IGNORE_TYPES = ["Line", "Square", "Circle", "PolyLine", "Polygon", "Ink"];
|
1501 | this.container.className = "popupAnnotation";
|
1502 |
|
1503 | if (IGNORE_TYPES.includes(this.data.parentType)) {
|
1504 | return this.container;
|
1505 | }
|
1506 |
|
1507 | const selector = `[data-annotation-id="${this.data.parentId}"]`;
|
1508 | const parentElements = this.layer.querySelectorAll(selector);
|
1509 |
|
1510 | if (parentElements.length === 0) {
|
1511 | return this.container;
|
1512 | }
|
1513 |
|
1514 | const popup = new PopupElement({
|
1515 | container: this.container,
|
1516 | trigger: Array.from(parentElements),
|
1517 | color: this.data.color,
|
1518 | titleObj: this.data.titleObj,
|
1519 | modificationDate: this.data.modificationDate,
|
1520 | contentsObj: this.data.contentsObj,
|
1521 | richText: this.data.richText
|
1522 | });
|
1523 | const page = this.page;
|
1524 |
|
1525 | const rect = _util.Util.normalizeRect([this.data.parentRect[0], page.view[3] - this.data.parentRect[1] + page.view[1], this.data.parentRect[2], page.view[3] - this.data.parentRect[3] + page.view[1]]);
|
1526 |
|
1527 | const popupLeft = rect[0] + this.data.parentRect[2] - this.data.parentRect[0];
|
1528 | const popupTop = rect[1];
|
1529 | this.container.style.transformOrigin = `${-popupLeft}px ${-popupTop}px`;
|
1530 | this.container.style.left = `${popupLeft}px`;
|
1531 | this.container.style.top = `${popupTop}px`;
|
1532 | this.container.appendChild(popup.render());
|
1533 | return this.container;
|
1534 | }
|
1535 |
|
1536 | }
|
1537 |
|
1538 | class PopupElement {
|
1539 | constructor(parameters) {
|
1540 | this.container = parameters.container;
|
1541 | this.trigger = parameters.trigger;
|
1542 | this.color = parameters.color;
|
1543 | this.titleObj = parameters.titleObj;
|
1544 | this.modificationDate = parameters.modificationDate;
|
1545 | this.contentsObj = parameters.contentsObj;
|
1546 | this.richText = parameters.richText;
|
1547 | this.hideWrapper = parameters.hideWrapper || false;
|
1548 | this.pinned = false;
|
1549 | }
|
1550 |
|
1551 | render() {
|
1552 | const BACKGROUND_ENLIGHT = 0.7;
|
1553 | const wrapper = document.createElement("div");
|
1554 | wrapper.className = "popupWrapper";
|
1555 | this.hideElement = this.hideWrapper ? wrapper : this.container;
|
1556 | this.hideElement.hidden = true;
|
1557 | const popup = document.createElement("div");
|
1558 | popup.className = "popup";
|
1559 | const color = this.color;
|
1560 |
|
1561 | if (color) {
|
1562 | const r = BACKGROUND_ENLIGHT * (255 - color[0]) + color[0];
|
1563 | const g = BACKGROUND_ENLIGHT * (255 - color[1]) + color[1];
|
1564 | const b = BACKGROUND_ENLIGHT * (255 - color[2]) + color[2];
|
1565 | popup.style.backgroundColor = _util.Util.makeHexColor(r | 0, g | 0, b | 0);
|
1566 | }
|
1567 |
|
1568 | const title = document.createElement("h1");
|
1569 | title.dir = this.titleObj.dir;
|
1570 | title.textContent = this.titleObj.str;
|
1571 | popup.appendChild(title);
|
1572 |
|
1573 | const dateObject = _display_utils.PDFDateString.toDateObject(this.modificationDate);
|
1574 |
|
1575 | if (dateObject) {
|
1576 | const modificationDate = document.createElement("span");
|
1577 | modificationDate.className = "popupDate";
|
1578 | modificationDate.textContent = "{{date}}, {{time}}";
|
1579 | modificationDate.dataset.l10nId = "annotation_date_string";
|
1580 | modificationDate.dataset.l10nArgs = JSON.stringify({
|
1581 | date: dateObject.toLocaleDateString(),
|
1582 | time: dateObject.toLocaleTimeString()
|
1583 | });
|
1584 | popup.appendChild(modificationDate);
|
1585 | }
|
1586 |
|
1587 | if (this.richText?.str && (!this.contentsObj?.str || this.contentsObj.str === this.richText.str)) {
|
1588 | _xfa_layer.XfaLayer.render({
|
1589 | xfaHtml: this.richText.html,
|
1590 | intent: "richText",
|
1591 | div: popup
|
1592 | });
|
1593 |
|
1594 | popup.lastChild.className = "richText popupContent";
|
1595 | } else {
|
1596 | const contents = this._formatContents(this.contentsObj);
|
1597 |
|
1598 | popup.appendChild(contents);
|
1599 | }
|
1600 |
|
1601 | if (!Array.isArray(this.trigger)) {
|
1602 | this.trigger = [this.trigger];
|
1603 | }
|
1604 |
|
1605 | for (const element of this.trigger) {
|
1606 | element.addEventListener("click", this._toggle.bind(this));
|
1607 | element.addEventListener("mouseover", this._show.bind(this, false));
|
1608 | element.addEventListener("mouseout", this._hide.bind(this, false));
|
1609 | }
|
1610 |
|
1611 | popup.addEventListener("click", this._hide.bind(this, true));
|
1612 | wrapper.appendChild(popup);
|
1613 | return wrapper;
|
1614 | }
|
1615 |
|
1616 | _formatContents({
|
1617 | str,
|
1618 | dir
|
1619 | }) {
|
1620 | const p = document.createElement("p");
|
1621 | p.className = "popupContent";
|
1622 | p.dir = dir;
|
1623 | const lines = str.split(/(?:\r\n?|\n)/);
|
1624 |
|
1625 | for (let i = 0, ii = lines.length; i < ii; ++i) {
|
1626 | const line = lines[i];
|
1627 | p.appendChild(document.createTextNode(line));
|
1628 |
|
1629 | if (i < ii - 1) {
|
1630 | p.appendChild(document.createElement("br"));
|
1631 | }
|
1632 | }
|
1633 |
|
1634 | return p;
|
1635 | }
|
1636 |
|
1637 | _toggle() {
|
1638 | if (this.pinned) {
|
1639 | this._hide(true);
|
1640 | } else {
|
1641 | this._show(true);
|
1642 | }
|
1643 | }
|
1644 |
|
1645 | _show(pin = false) {
|
1646 | if (pin) {
|
1647 | this.pinned = true;
|
1648 | }
|
1649 |
|
1650 | if (this.hideElement.hidden) {
|
1651 | this.hideElement.hidden = false;
|
1652 | this.container.style.zIndex += 1;
|
1653 | }
|
1654 | }
|
1655 |
|
1656 | _hide(unpin = true) {
|
1657 | if (unpin) {
|
1658 | this.pinned = false;
|
1659 | }
|
1660 |
|
1661 | if (!this.hideElement.hidden && !this.pinned) {
|
1662 | this.hideElement.hidden = true;
|
1663 | this.container.style.zIndex -= 1;
|
1664 | }
|
1665 | }
|
1666 |
|
1667 | }
|
1668 |
|
1669 | class FreeTextAnnotationElement extends AnnotationElement {
|
1670 | constructor(parameters) {
|
1671 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1672 | super(parameters, {
|
1673 | isRenderable,
|
1674 | ignoreBorder: true
|
1675 | });
|
1676 | }
|
1677 |
|
1678 | render() {
|
1679 | this.container.className = "freeTextAnnotation";
|
1680 |
|
1681 | if (!this.data.hasPopup) {
|
1682 | this._createPopup(null, this.data);
|
1683 | }
|
1684 |
|
1685 | return this.container;
|
1686 | }
|
1687 |
|
1688 | }
|
1689 |
|
1690 | class LineAnnotationElement extends AnnotationElement {
|
1691 | constructor(parameters) {
|
1692 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1693 | super(parameters, {
|
1694 | isRenderable,
|
1695 | ignoreBorder: true
|
1696 | });
|
1697 | }
|
1698 |
|
1699 | render() {
|
1700 | this.container.className = "lineAnnotation";
|
1701 | const data = this.data;
|
1702 | const width = data.rect[2] - data.rect[0];
|
1703 | const height = data.rect[3] - data.rect[1];
|
1704 | const svg = this.svgFactory.create(width, height);
|
1705 | const line = this.svgFactory.createElement("svg:line");
|
1706 | line.setAttribute("x1", data.rect[2] - data.lineCoordinates[0]);
|
1707 | line.setAttribute("y1", data.rect[3] - data.lineCoordinates[1]);
|
1708 | line.setAttribute("x2", data.rect[2] - data.lineCoordinates[2]);
|
1709 | line.setAttribute("y2", data.rect[3] - data.lineCoordinates[3]);
|
1710 | line.setAttribute("stroke-width", data.borderStyle.width || 1);
|
1711 | line.setAttribute("stroke", "transparent");
|
1712 | line.setAttribute("fill", "transparent");
|
1713 | svg.appendChild(line);
|
1714 | this.container.append(svg);
|
1715 |
|
1716 | this._createPopup(line, data);
|
1717 |
|
1718 | return this.container;
|
1719 | }
|
1720 |
|
1721 | }
|
1722 |
|
1723 | class SquareAnnotationElement extends AnnotationElement {
|
1724 | constructor(parameters) {
|
1725 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1726 | super(parameters, {
|
1727 | isRenderable,
|
1728 | ignoreBorder: true
|
1729 | });
|
1730 | }
|
1731 |
|
1732 | render() {
|
1733 | this.container.className = "squareAnnotation";
|
1734 | const data = this.data;
|
1735 | const width = data.rect[2] - data.rect[0];
|
1736 | const height = data.rect[3] - data.rect[1];
|
1737 | const svg = this.svgFactory.create(width, height);
|
1738 | const borderWidth = data.borderStyle.width;
|
1739 | const square = this.svgFactory.createElement("svg:rect");
|
1740 | square.setAttribute("x", borderWidth / 2);
|
1741 | square.setAttribute("y", borderWidth / 2);
|
1742 | square.setAttribute("width", width - borderWidth);
|
1743 | square.setAttribute("height", height - borderWidth);
|
1744 | square.setAttribute("stroke-width", borderWidth || 1);
|
1745 | square.setAttribute("stroke", "transparent");
|
1746 | square.setAttribute("fill", "transparent");
|
1747 | svg.appendChild(square);
|
1748 | this.container.append(svg);
|
1749 |
|
1750 | this._createPopup(square, data);
|
1751 |
|
1752 | return this.container;
|
1753 | }
|
1754 |
|
1755 | }
|
1756 |
|
1757 | class CircleAnnotationElement extends AnnotationElement {
|
1758 | constructor(parameters) {
|
1759 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1760 | super(parameters, {
|
1761 | isRenderable,
|
1762 | ignoreBorder: true
|
1763 | });
|
1764 | }
|
1765 |
|
1766 | render() {
|
1767 | this.container.className = "circleAnnotation";
|
1768 | const data = this.data;
|
1769 | const width = data.rect[2] - data.rect[0];
|
1770 | const height = data.rect[3] - data.rect[1];
|
1771 | const svg = this.svgFactory.create(width, height);
|
1772 | const borderWidth = data.borderStyle.width;
|
1773 | const circle = this.svgFactory.createElement("svg:ellipse");
|
1774 | circle.setAttribute("cx", width / 2);
|
1775 | circle.setAttribute("cy", height / 2);
|
1776 | circle.setAttribute("rx", width / 2 - borderWidth / 2);
|
1777 | circle.setAttribute("ry", height / 2 - borderWidth / 2);
|
1778 | circle.setAttribute("stroke-width", borderWidth || 1);
|
1779 | circle.setAttribute("stroke", "transparent");
|
1780 | circle.setAttribute("fill", "transparent");
|
1781 | svg.appendChild(circle);
|
1782 | this.container.append(svg);
|
1783 |
|
1784 | this._createPopup(circle, data);
|
1785 |
|
1786 | return this.container;
|
1787 | }
|
1788 |
|
1789 | }
|
1790 |
|
1791 | class PolylineAnnotationElement extends AnnotationElement {
|
1792 | constructor(parameters) {
|
1793 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1794 | super(parameters, {
|
1795 | isRenderable,
|
1796 | ignoreBorder: true
|
1797 | });
|
1798 | this.containerClassName = "polylineAnnotation";
|
1799 | this.svgElementName = "svg:polyline";
|
1800 | }
|
1801 |
|
1802 | render() {
|
1803 | this.container.className = this.containerClassName;
|
1804 | const data = this.data;
|
1805 | const width = data.rect[2] - data.rect[0];
|
1806 | const height = data.rect[3] - data.rect[1];
|
1807 | const svg = this.svgFactory.create(width, height);
|
1808 | let points = [];
|
1809 |
|
1810 | for (const coordinate of data.vertices) {
|
1811 | const x = coordinate.x - data.rect[0];
|
1812 | const y = data.rect[3] - coordinate.y;
|
1813 | points.push(x + "," + y);
|
1814 | }
|
1815 |
|
1816 | points = points.join(" ");
|
1817 | const polyline = this.svgFactory.createElement(this.svgElementName);
|
1818 | polyline.setAttribute("points", points);
|
1819 | polyline.setAttribute("stroke-width", data.borderStyle.width || 1);
|
1820 | polyline.setAttribute("stroke", "transparent");
|
1821 | polyline.setAttribute("fill", "transparent");
|
1822 | svg.appendChild(polyline);
|
1823 | this.container.append(svg);
|
1824 |
|
1825 | this._createPopup(polyline, data);
|
1826 |
|
1827 | return this.container;
|
1828 | }
|
1829 |
|
1830 | }
|
1831 |
|
1832 | class PolygonAnnotationElement extends PolylineAnnotationElement {
|
1833 | constructor(parameters) {
|
1834 | super(parameters);
|
1835 | this.containerClassName = "polygonAnnotation";
|
1836 | this.svgElementName = "svg:polygon";
|
1837 | }
|
1838 |
|
1839 | }
|
1840 |
|
1841 | class CaretAnnotationElement extends AnnotationElement {
|
1842 | constructor(parameters) {
|
1843 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1844 | super(parameters, {
|
1845 | isRenderable,
|
1846 | ignoreBorder: true
|
1847 | });
|
1848 | }
|
1849 |
|
1850 | render() {
|
1851 | this.container.className = "caretAnnotation";
|
1852 |
|
1853 | if (!this.data.hasPopup) {
|
1854 | this._createPopup(null, this.data);
|
1855 | }
|
1856 |
|
1857 | return this.container;
|
1858 | }
|
1859 |
|
1860 | }
|
1861 |
|
1862 | class InkAnnotationElement extends AnnotationElement {
|
1863 | constructor(parameters) {
|
1864 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1865 | super(parameters, {
|
1866 | isRenderable,
|
1867 | ignoreBorder: true
|
1868 | });
|
1869 | this.containerClassName = "inkAnnotation";
|
1870 | this.svgElementName = "svg:polyline";
|
1871 | }
|
1872 |
|
1873 | render() {
|
1874 | this.container.className = this.containerClassName;
|
1875 | const data = this.data;
|
1876 | const width = data.rect[2] - data.rect[0];
|
1877 | const height = data.rect[3] - data.rect[1];
|
1878 | const svg = this.svgFactory.create(width, height);
|
1879 |
|
1880 | for (const inkList of data.inkLists) {
|
1881 | let points = [];
|
1882 |
|
1883 | for (const coordinate of inkList) {
|
1884 | const x = coordinate.x - data.rect[0];
|
1885 | const y = data.rect[3] - coordinate.y;
|
1886 | points.push(`${x},${y}`);
|
1887 | }
|
1888 |
|
1889 | points = points.join(" ");
|
1890 | const polyline = this.svgFactory.createElement(this.svgElementName);
|
1891 | polyline.setAttribute("points", points);
|
1892 | polyline.setAttribute("stroke-width", data.borderStyle.width || 1);
|
1893 | polyline.setAttribute("stroke", "transparent");
|
1894 | polyline.setAttribute("fill", "transparent");
|
1895 |
|
1896 | this._createPopup(polyline, data);
|
1897 |
|
1898 | svg.appendChild(polyline);
|
1899 | }
|
1900 |
|
1901 | this.container.append(svg);
|
1902 | return this.container;
|
1903 | }
|
1904 |
|
1905 | }
|
1906 |
|
1907 | class HighlightAnnotationElement extends AnnotationElement {
|
1908 | constructor(parameters) {
|
1909 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1910 | super(parameters, {
|
1911 | isRenderable,
|
1912 | ignoreBorder: true,
|
1913 | createQuadrilaterals: true
|
1914 | });
|
1915 | }
|
1916 |
|
1917 | render() {
|
1918 | if (!this.data.hasPopup) {
|
1919 | this._createPopup(null, this.data);
|
1920 | }
|
1921 |
|
1922 | if (this.quadrilaterals) {
|
1923 | return this._renderQuadrilaterals("highlightAnnotation");
|
1924 | }
|
1925 |
|
1926 | this.container.className = "highlightAnnotation";
|
1927 | return this.container;
|
1928 | }
|
1929 |
|
1930 | }
|
1931 |
|
1932 | class UnderlineAnnotationElement extends AnnotationElement {
|
1933 | constructor(parameters) {
|
1934 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1935 | super(parameters, {
|
1936 | isRenderable,
|
1937 | ignoreBorder: true,
|
1938 | createQuadrilaterals: true
|
1939 | });
|
1940 | }
|
1941 |
|
1942 | render() {
|
1943 | if (!this.data.hasPopup) {
|
1944 | this._createPopup(null, this.data);
|
1945 | }
|
1946 |
|
1947 | if (this.quadrilaterals) {
|
1948 | return this._renderQuadrilaterals("underlineAnnotation");
|
1949 | }
|
1950 |
|
1951 | this.container.className = "underlineAnnotation";
|
1952 | return this.container;
|
1953 | }
|
1954 |
|
1955 | }
|
1956 |
|
1957 | class SquigglyAnnotationElement extends AnnotationElement {
|
1958 | constructor(parameters) {
|
1959 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1960 | super(parameters, {
|
1961 | isRenderable,
|
1962 | ignoreBorder: true,
|
1963 | createQuadrilaterals: true
|
1964 | });
|
1965 | }
|
1966 |
|
1967 | render() {
|
1968 | if (!this.data.hasPopup) {
|
1969 | this._createPopup(null, this.data);
|
1970 | }
|
1971 |
|
1972 | if (this.quadrilaterals) {
|
1973 | return this._renderQuadrilaterals("squigglyAnnotation");
|
1974 | }
|
1975 |
|
1976 | this.container.className = "squigglyAnnotation";
|
1977 | return this.container;
|
1978 | }
|
1979 |
|
1980 | }
|
1981 |
|
1982 | class StrikeOutAnnotationElement extends AnnotationElement {
|
1983 | constructor(parameters) {
|
1984 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
1985 | super(parameters, {
|
1986 | isRenderable,
|
1987 | ignoreBorder: true,
|
1988 | createQuadrilaterals: true
|
1989 | });
|
1990 | }
|
1991 |
|
1992 | render() {
|
1993 | if (!this.data.hasPopup) {
|
1994 | this._createPopup(null, this.data);
|
1995 | }
|
1996 |
|
1997 | if (this.quadrilaterals) {
|
1998 | return this._renderQuadrilaterals("strikeoutAnnotation");
|
1999 | }
|
2000 |
|
2001 | this.container.className = "strikeoutAnnotation";
|
2002 | return this.container;
|
2003 | }
|
2004 |
|
2005 | }
|
2006 |
|
2007 | class StampAnnotationElement extends AnnotationElement {
|
2008 | constructor(parameters) {
|
2009 | const isRenderable = !!(parameters.data.hasPopup || parameters.data.titleObj?.str || parameters.data.contentsObj?.str || parameters.data.richText?.str);
|
2010 | super(parameters, {
|
2011 | isRenderable,
|
2012 | ignoreBorder: true
|
2013 | });
|
2014 | }
|
2015 |
|
2016 | render() {
|
2017 | this.container.className = "stampAnnotation";
|
2018 |
|
2019 | if (!this.data.hasPopup) {
|
2020 | this._createPopup(null, this.data);
|
2021 | }
|
2022 |
|
2023 | return this.container;
|
2024 | }
|
2025 |
|
2026 | }
|
2027 |
|
2028 | class FileAttachmentAnnotationElement extends AnnotationElement {
|
2029 | constructor(parameters) {
|
2030 | super(parameters, {
|
2031 | isRenderable: true
|
2032 | });
|
2033 | const {
|
2034 | filename,
|
2035 | content
|
2036 | } = this.data.file;
|
2037 | this.filename = (0, _display_utils.getFilenameFromUrl)(filename);
|
2038 | this.content = content;
|
2039 | this.linkService.eventBus?.dispatch("fileattachmentannotation", {
|
2040 | source: this,
|
2041 | id: (0, _util.stringToPDFString)(filename),
|
2042 | filename,
|
2043 | content
|
2044 | });
|
2045 | }
|
2046 |
|
2047 | render() {
|
2048 | this.container.className = "fileAttachmentAnnotation";
|
2049 | const trigger = document.createElement("div");
|
2050 | trigger.style.height = this.container.style.height;
|
2051 | trigger.style.width = this.container.style.width;
|
2052 | trigger.addEventListener("dblclick", this._download.bind(this));
|
2053 |
|
2054 | if (!this.data.hasPopup && (this.data.titleObj?.str || this.data.contentsObj?.str || this.data.richText)) {
|
2055 | this._createPopup(trigger, this.data);
|
2056 | }
|
2057 |
|
2058 | this.container.appendChild(trigger);
|
2059 | return this.container;
|
2060 | }
|
2061 |
|
2062 | _download() {
|
2063 | this.downloadManager?.openOrDownloadData(this.container, this.content, this.filename);
|
2064 | }
|
2065 |
|
2066 | }
|
2067 |
|
2068 | class AnnotationLayer {
|
2069 | static render(parameters) {
|
2070 | const sortedAnnotations = [],
|
2071 | popupAnnotations = [];
|
2072 |
|
2073 | for (const data of parameters.annotations) {
|
2074 | if (!data) {
|
2075 | continue;
|
2076 | }
|
2077 |
|
2078 | if (data.annotationType === _util.AnnotationType.POPUP) {
|
2079 | popupAnnotations.push(data);
|
2080 | continue;
|
2081 | }
|
2082 |
|
2083 | sortedAnnotations.push(data);
|
2084 | }
|
2085 |
|
2086 | if (popupAnnotations.length) {
|
2087 | sortedAnnotations.push(...popupAnnotations);
|
2088 | }
|
2089 |
|
2090 | const div = parameters.div;
|
2091 |
|
2092 | for (const data of sortedAnnotations) {
|
2093 | const element = AnnotationElementFactory.create({
|
2094 | data,
|
2095 | layer: div,
|
2096 | page: parameters.page,
|
2097 | viewport: parameters.viewport,
|
2098 | linkService: parameters.linkService,
|
2099 | downloadManager: parameters.downloadManager,
|
2100 | imageResourcesPath: parameters.imageResourcesPath || "",
|
2101 | renderForms: parameters.renderForms !== false,
|
2102 | svgFactory: new _display_utils.DOMSVGFactory(),
|
2103 | annotationStorage: parameters.annotationStorage || new _annotation_storage.AnnotationStorage(),
|
2104 | enableScripting: parameters.enableScripting,
|
2105 | hasJSActions: parameters.hasJSActions,
|
2106 | fieldObjects: parameters.fieldObjects,
|
2107 | mouseState: parameters.mouseState || {
|
2108 | isDown: false
|
2109 | }
|
2110 | });
|
2111 |
|
2112 | if (element.isRenderable) {
|
2113 | const rendered = element.render();
|
2114 |
|
2115 | if (data.hidden) {
|
2116 | rendered.style.visibility = "hidden";
|
2117 | }
|
2118 |
|
2119 | if (Array.isArray(rendered)) {
|
2120 | for (const renderedElement of rendered) {
|
2121 | div.appendChild(renderedElement);
|
2122 | }
|
2123 | } else {
|
2124 | if (element instanceof PopupAnnotationElement) {
|
2125 | div.prepend(rendered);
|
2126 | } else {
|
2127 | div.appendChild(rendered);
|
2128 | }
|
2129 | }
|
2130 | }
|
2131 | }
|
2132 |
|
2133 | this.#setAnnotationCanvasMap(div, parameters.annotationCanvasMap);
|
2134 | }
|
2135 |
|
2136 | static update(parameters) {
|
2137 | const {
|
2138 | page,
|
2139 | viewport,
|
2140 | annotations,
|
2141 | annotationCanvasMap,
|
2142 | div
|
2143 | } = parameters;
|
2144 | const transform = viewport.transform;
|
2145 | const matrix = `matrix(${transform.join(",")})`;
|
2146 | let scale, ownMatrix;
|
2147 |
|
2148 | for (const data of annotations) {
|
2149 | const elements = div.querySelectorAll(`[data-annotation-id="${data.id}"]`);
|
2150 |
|
2151 | if (elements) {
|
2152 | for (const element of elements) {
|
2153 | if (data.hasOwnCanvas) {
|
2154 | const rect = _util.Util.normalizeRect([data.rect[0], page.view[3] - data.rect[1] + page.view[1], data.rect[2], page.view[3] - data.rect[3] + page.view[1]]);
|
2155 |
|
2156 | if (!ownMatrix) {
|
2157 | scale = Math.abs(transform[0] || transform[1]);
|
2158 | const ownTransform = transform.slice();
|
2159 |
|
2160 | for (let i = 0; i < 4; i++) {
|
2161 | ownTransform[i] = Math.sign(ownTransform[i]);
|
2162 | }
|
2163 |
|
2164 | ownMatrix = `matrix(${ownTransform.join(",")})`;
|
2165 | }
|
2166 |
|
2167 | const left = rect[0] * scale;
|
2168 | const top = rect[1] * scale;
|
2169 | element.style.left = `${left}px`;
|
2170 | element.style.top = `${top}px`;
|
2171 | element.style.transformOrigin = `${-left}px ${-top}px`;
|
2172 | element.style.transform = ownMatrix;
|
2173 | } else {
|
2174 | element.style.transform = matrix;
|
2175 | }
|
2176 | }
|
2177 | }
|
2178 | }
|
2179 |
|
2180 | this.#setAnnotationCanvasMap(div, annotationCanvasMap);
|
2181 | div.hidden = false;
|
2182 | }
|
2183 |
|
2184 | static #setAnnotationCanvasMap(div, annotationCanvasMap) {
|
2185 | if (!annotationCanvasMap) {
|
2186 | return;
|
2187 | }
|
2188 |
|
2189 | for (const [id, canvas] of annotationCanvasMap) {
|
2190 | const element = div.querySelector(`[data-annotation-id="${id}"]`);
|
2191 |
|
2192 | if (!element) {
|
2193 | continue;
|
2194 | }
|
2195 |
|
2196 | const {
|
2197 | firstChild
|
2198 | } = element;
|
2199 |
|
2200 | if (firstChild.nodeName === "CANVAS") {
|
2201 | element.replaceChild(canvas, firstChild);
|
2202 | } else {
|
2203 | element.insertBefore(canvas, firstChild);
|
2204 | }
|
2205 | }
|
2206 |
|
2207 | annotationCanvasMap.clear();
|
2208 | }
|
2209 |
|
2210 | }
|
2211 |
|
2212 | exports.AnnotationLayer = AnnotationLayer; |
\ | No newline at end of file |