annotation_layer.js 62 KB

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