2
0

annotation_layer.js 68 KB

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