annotation_layer.js 64 KB

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