ViewerFormFiller.cs
  1. //
  2. // This code is part of Document Solutions for PDF demos.
  3. // Copyright (c) MESCIUS inc. All rights reserved.
  4. //
  5. using System.IO;
  6. using System.Collections.Generic;
  7. using GrapeCity.Documents.Pdf;
  8.  
  9. namespace DsPdfWeb.Demos
  10. {
  11. //
  12. // This sample demonstrates using the GcPdfViewer's Form Filler.
  13. // It loads an example Commercial Rental Application Form.
  14. // To make form input more convenient, we customize the appearance and
  15. // behavior of the Form Filler dialog using the formFiller option.
  16. // After loading the document - the Form Filler dialog is displayed
  17. // using the client side showFormFiller method.
  18.  
  19. // This and other samples in this section demonstrate the features of GcPdfViewer
  20. // (a JavaScript PDF viewer control included with DsPdf), mainly the ability
  21. // to change PDF files (add or edit annotations and AcroForm fields, rotate pages etc.)
  22. // when the JS viewer on the client is supported by DsPdf running on the server.
  23. //
  24. // To enable the editing features of the viewer, its supportApi property must be set
  25. // to a URL on the server that implements all or some of the edit supporting APIs
  26. // that are known to/expected by the viewer. This DsPdf demo site provides those APIs,
  27. // which makes it possible to demonstrate the editing when you open the PDF viewer
  28. // in this sample. When you download this sample, in addition to the .NET Core
  29. // console app project that generates the sample PDF, an ASP.NET Core project is
  30. // also included in the download zip (located in the GcPdfViewerWeb sub-folder of the
  31. // downloaded zip), which also provides the necessary APIs. In particular, it includes
  32. // a project that implements the APIs and provides them via a special controller.
  33. // It is actually the same controller that is used by this DsPdf demo site, and which
  34. // can be used in any ASP.NET Core site to enable the viewer editing features.
  35. //
  36. // Look at the following files in the sample download zip for more info:
  37. // - GcPdfViewerWeb\SupportApiDemo: the sample ASP.NET Core web site.
  38. // - GcPdfViewerWeb\SupportApiDemo.sln: solution to build/run the sample web site.
  39. // - GcPdfViewerWeb\SupportApi: support API implementation (can be used in any site).
  40. // - GcPdfViewerWeb\SupportApi\Controllers\GcPdfViewerController.cs: support API controller.
  41. //
  42. // Please note that this and other samples in this section are only available in C# at this time.
  43. //
  44. public class ViewerFormFiller
  45. {
  46. public void CreatePDF(Stream stream)
  47. {
  48. CreatePDF(stream, 0);
  49. }
  50.  
  51. public void CreatePDF(Stream stream, int _)
  52. {
  53. var doc = new GcPdfDocument();
  54. using var fs = File.OpenRead(Path.Combine("Resources", "PDFs", "Commercial-Rental-Application-Form.pdf"));
  55. doc.Load(fs);
  56. doc.Save(stream);
  57. }
  58.  
  59. public const string JS_CODE = @"
  60. var requiredPhonePattern = '^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$';
  61. var requiredPhoneValidationMessage = 'Valid formats: 1234567890, (123)456-7890,\n 123-456-7890, 123.456.7890, +31636363634, 075-63546725';
  62. var optionalPhonePattern = '^$|^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$';
  63. var optionalPhoneValidationMessage = 'Field is optional, valid formats:\n 1234567890, (123)456-7890,\n 123-456-7890, 123.456.7890, +31636363634, 075-63546725';
  64. var ovnPark_FieldValue_On = 'Has overnight parking.', ovnPark_FieldValue_Off = 'NO';
  65. var updatingFieldsFlag = false;
  66. function combineTwoFieldsIntoOneValue(destfieldName, fieldName2, formFiller) {
  67. var addr1 = formFiller.getFieldByName(destfieldName);
  68. var addr2 = formFiller.getFieldByName(fieldName2);
  69. if(addr1 && addr2) {
  70. if(addr2.fieldValue) {
  71. addr1.fieldValue = addr1.fieldValue + '\n' + addr2.fieldValue;
  72. addr2.fieldValue = '';
  73. formFiller.onFieldChanged(addr1);
  74. formFiller.onFieldChanged(addr2);
  75. }
  76. }
  77. }
  78. function splitFieldValueIntoTwoFields(srcfieldName, fieldName2, formFiller) {
  79. var addr1 = formFiller.getFieldByName(srcfieldName);
  80. var addr2 = formFiller.getFieldByName(fieldName2);
  81. if(addr1 && addr2) {
  82. var s = addr1.fieldValue;
  83. var nlInd = s.indexOf('\n');
  84. if(nlInd !== -1) {
  85. var firstPart = s.substring(0, nlInd);
  86. var secondPart = s.substr(nlInd + 1);
  87. addr1.fieldValue = firstPart;
  88. addr2.fieldValue = secondPart;
  89. } else {
  90. addr2.fieldValue = '';
  91. }
  92. formFiller.onFieldChanged(addr1);
  93. formFiller.onFieldChanged(addr2);
  94. }
  95. }
  96. function createPdfViewer(selector, baseOptions) {
  97. var options = baseOptions || {};
  98. // Form Filler options for 'RentalApplicationForm' document:
  99. var formFiller_RentalApplicationForm = {
  100. onInitialize: function(formFiller) {
  101. combineTwoFieldsIntoOneValue('Addr1', 'Addr2', formFiller);
  102. combineTwoFieldsIntoOneValue('BusAddr1', 'BusAddr2', formFiller);
  103. var ovnParkField = formFiller.getFieldByName('OvnPark');
  104. if(ovnParkField.fieldValue) {
  105. var ovnPark_LowVal = (ovnParkField.fieldValue || '').toLowerCase();
  106. if(!ovnPark_LowVal || ovnPark_LowVal.indexOf('no') !== -1 || ovnPark_LowVal === 'off' || ovnPark_LowVal === 'false') {
  107. ovnParkField.fieldValue = 'Off';
  108. formFiller.onFieldChanged(ovnParkField);
  109. } else {
  110. ovnPark_FieldValue_On = ovnParkField.fieldValue;// remember current On value.
  111. ovnParkField.fieldValue = 'On';
  112. formFiller.onFieldChanged(ovnParkField);
  113. }
  114. }
  115. },
  116. beforeApplyChanges: function(formFiller) {
  117. splitFieldValueIntoTwoFields('Addr1', 'Addr2', formFiller);
  118. splitFieldValueIntoTwoFields('BusAddr1', 'BusAddr2', formFiller);
  119. var ovnParkField = formFiller.getFieldByName('OvnPark');
  120. if(ovnParkField.fieldName === 'OvnPark') {
  121. if(ovnParkField.fieldValue === 'On') {
  122. ovnParkField.fieldValue = ovnPark_FieldValue_On;
  123. } else {
  124. ovnParkField.fieldValue = ovnPark_FieldValue_Off;
  125. }
  126. }
  127. return true;
  128. },
  129. beforeFieldChange: function(changedField, formFiller) {
  130. if(updatingFieldsFlag)
  131. return true;
  132. var setFieldValue = function(chkboxFieldName, newVal) {
  133. var tmpField = formFiller.getFieldByName(chkboxFieldName);
  134. if(tmpField.fieldValue !== newVal) {
  135. tmpField.fieldValue = newVal;
  136. formFiller.onFieldChanged(tmpField);
  137. }
  138. };
  139. updatingFieldsFlag = true;
  140. try {
  141. var fieldName = changedField.fieldName;
  142. var fieldValue = changedField.fieldValue;
  143. if(fieldName === 'Married1CHK' || fieldName === 'Single1CHK') {
  144. if(fieldName === 'Married1CHK')
  145. setFieldValue('Single1CHK', 'Off');
  146. if(fieldName === 'Single1CHK')
  147. setFieldValue('Married1CHK', 'Off');
  148. if(fieldValue === 'Off')
  149. return false; // prevent uncheck
  150. }
  151. if(fieldName === 'CorpCHK' || fieldName === 'GPCHK' || fieldName === 'IndivCHK') {
  152. // Uncheck other fields:
  153. switch(fieldName) {
  154. case 'CorpCHK':
  155. setFieldValue('GPCHK', 'Off');
  156. setFieldValue('IndivCHK', 'Off');
  157. break;
  158. case 'GPCHK':
  159. setFieldValue('CorpCHK', 'Off');
  160. setFieldValue('IndivCHK', 'Off');
  161. break;
  162. case 'IndivCHK':
  163. setFieldValue('CorpCHK', 'Off');
  164. setFieldValue('GPCHK', 'Off');
  165. break;
  166. default:
  167. break;
  168. }
  169. if(fieldValue === 'Off')
  170. return false; // prevent uncheck
  171. }
  172. } finally {
  173. updatingFieldsFlag = false;
  174. }
  175. return true;
  176. },
  177. mappings: {
  178. 'CustomContent1': {
  179. type: 'custom-content',
  180. content: '<h2>COMMERCIAL TENANT APPLICATION</h2>'
  181. },
  182. 'AppDate': {
  183. title: 'Application date',
  184. displayname: 'Date',
  185. type: 'date',
  186. defaultvalue: new Date().toJSON().slice(0, 10)
  187. },
  188. 'Entity': {
  189. autofocus: true,
  190. title: 'Name of individual, partnership, or corporation',
  191. displayname: 'Applicant or Leasing Entity',
  192. placeholder: 'Name of individual, partnership, or corporation',
  193. required: true,
  194. validationmessage: 'Entity name is required',
  195. validateoninput: true
  196. },
  197. 'CustomContent2': {
  198. type: 'custom-content',
  199. content: '<table> <tr><td style=\'vertical-align:top;\'> <i><u>Corporation:</u></i> </td><td style=\'vertical-align:top;\'> <i>Articles of Incorporation must be provided and 2 years\' Annual Report and corporate tax return.</i> </td></tr> <tr><td style=\'vertical-align:top;\'> <i><u>Partnership:</u></i> </td><td style=\'vertical-align:top;\'> <i>Partnership Agreement must be provided plus individual partners\' current personal financial statement and 2 years\' personal tax returns.</i> </td></tr> <tr><td style=\'vertical-align:top;\'> <i><u>Individual:</u></i> </td><td style=\'vertical-align:top;\'> <i>Personal balance sheet and 2 years\' personal tax returns must be provided. Must include Drivers\' license number.</i> </td></tr></table>'
  200. },
  201. 'Addr1': {
  202. title: 'Current corporate headquarters/home address (For partnership/individuals) (Do not use P.O. Box)',
  203. displayname: 'Current address',
  204. placeholder: 'Current corporate headquarters/home address (For partnership/individuals) (Do not use P.O. Box)',
  205. multiline: true,
  206. required: true,
  207. validationmessage: 'Address is required',
  208. validateoninput: true
  209. },
  210. 'Addr2': {
  211. hidden: true,
  212. },
  213. 'CorpPhone': {
  214. title: 'Corporate phone number',
  215. displayname: 'Corporate phone #',
  216. placeholder: 'Corporate phone',
  217. type: 'tel',
  218. pattern: requiredPhonePattern,
  219. validationmessage: requiredPhoneValidationMessage,
  220. validateoninput: true
  221. },
  222.  
  223. 'CorpState': {
  224. title: 'State where the company was registered',
  225. displayname: 'State of incorporation',
  226. placeholder: 'State of incorporation',
  227. validateoninput: true,
  228. validator: function(fieldValue, field) {
  229. if(!fieldValue || !fieldValue.trim())
  230. return 'This field cannot be empty';
  231. if(fieldValue.toLowerCase().indexOf('delaware') === -1)
  232. return 'Only Delaware state allowed.';
  233. return true;
  234. }
  235. },
  236. 'DBA': {
  237. title: 'DBA (Doing Business As)',
  238. displayname: 'DBA name',
  239. placeholder: 'DBA',
  240. required: true
  241. },
  242. 'HomePhone': {
  243. title: 'Home phone number (for partnerships/Individuals)',
  244. displayname: 'Home phone #',
  245. placeholder: 'Home phone (optional)',
  246. type: 'tel',
  247. pattern: optionalPhonePattern,
  248. validationmessage: optionalPhoneValidationMessage,
  249. validateoninput: true
  250. },
  251. 'PtnrState': {
  252. title: 'State of partnership formation',
  253. displayname: 'State of partnership formation',
  254. placeholder: 'State of partnership formation'
  255. },
  256. 'LocalPhone': {
  257. title: 'Local phone number',
  258. displayname: 'Local phone #',
  259. placeholder: 'Local phone (optional)',
  260. type: 'tel',
  261. pattern: optionalPhonePattern,
  262. validationmessage: optionalPhoneValidationMessage,
  263. validateoninput: true
  264. },
  265.  
  266. 'Use1': {
  267. title: 'Full description of intended use',
  268. displayname: 'Intended use',
  269. placeholder: 'Intended use (line 1)',
  270. required: true
  271. },
  272. 'Use2': {
  273. title: 'Full description of intended use',
  274. displayname: '',
  275. placeholder: 'Intended use (line 2)'
  276. },
  277. 'Use3': {
  278. title: 'Full description of intended use',
  279. displayname: '',
  280. placeholder: 'Intended use (line 3)'
  281. },
  282. 'CustomContent3': {
  283. type: 'custom-content',
  284. content: '<h2>CURRENT BUSINESS LANDLORD</h2>'
  285. },
  286. 'CurrLandlord': {
  287. title: 'Current business landlord name',
  288. displayname: 'Name',
  289. placeholder: 'Landlord name'
  290. },
  291.  
  292. LandLordPhone: {
  293. title: 'Phone number',
  294. displayname: 'Phone #',
  295. placeholder: 'Phone (optional)',
  296. type: 'tel',
  297. pattern: optionalPhonePattern,
  298. validationmessage: optionalPhoneValidationMessage,
  299. validateoninput: true
  300.  
  301. },
  302. BusAddr1: {
  303. title: 'Present business address',
  304. displayname: 'Present business address',
  305. placeholder: 'Present business address',
  306. multiline: true
  307. },
  308. BusAddr2: {
  309. hidden: true
  310. },
  311. NumYears: {
  312. title: 'Years at this location',
  313. displayname: 'Years at this location',
  314. placeholder: 'Years at this location',
  315. type: 'number',
  316. min: 0,
  317. max: 100
  318. },
  319. NumEmployees: {
  320. title: 'Number of employees',
  321. displayname: 'Number of employees',
  322. placeholder: 'Number of employees',
  323. type: 'number',
  324. min: 0,
  325. max: 1000000
  326. },
  327. PkgSpaces: {
  328. title: 'Number of parking spaces needed',
  329. displayname: 'Number of parking spaces needed',
  330. placeholder: 'parking spaces number',
  331. type: 'number',
  332. min: 0,
  333. max: 1000000
  334. },
  335. OvnPark: {
  336. title: 'Any overnight parking?',
  337. displayname: 'Any overnight parking?',
  338. type: 'checkbox'
  339. },
  340. BankAcct: {
  341. title: 'Bank account number',
  342. displayname: 'Account number',
  343. placeholder: 'Account number',
  344. minlength: 8,
  345. maxlength: 12,
  346. validationmessage: 'Expected value between 8 and 12 digits',
  347. validateoninput: true
  348. },
  349. BankPhone: {
  350. title: 'Bank phone number',
  351. displayname: 'Phone number'
  352. },
  353. BankRef: {
  354. title: 'Bank reference',
  355. displayname: 'Bank reference'
  356. },
  357. BankContact: {
  358. title: 'Contact name',
  359. displayname: 'Contact name'
  360. },
  361.  
  362. 'CustomContent4': {
  363. type: 'custom-content',
  364. content: '<h4>Please list all hazardous substances that will be on the premises and the approximate amounts</h4>'
  365. },
  366. HazSub1: {
  367. title: 'Please list all hazardous substances that will be on the premises and the approximate amounts',
  368. placeholder: 'List all hazardous substances that will be on the premises and the approximate amount (line 1)',
  369. nolabel: true
  370. },
  371. HazSub2: {
  372. title: 'Please list all hazardous substances that will be on the premises and the approximate amounts',
  373. placeholder: 'List all hazardous substances that will be on the premises and the approximate amount (line 2)',
  374. nolabel: true
  375. },
  376. HazSub3: {
  377. title: 'Please list all hazardous substances that will be on the premises and the approximate amounts',
  378. placeholder: 'List all hazardous substances that will be on the premises and the approximate amount (line 3)',
  379. nolabel: true
  380. },
  381. 'CustomContent5': {
  382. type: 'custom-content',
  383. content: '<h4>Please check one:</h4>'
  384. },
  385. CorpCHK: {
  386. title: 'Corporate',
  387. displayname: 'Corporate'
  388. },
  389. GPCHK: {
  390. title: 'General partner(s)',
  391. displayname: 'General partner(s)'
  392. },
  393. IndivCHK: {
  394. title: 'Individual(s) signing the lease',
  395. displayname: 'Individual(s) signing the lease'
  396. },
  397.  
  398.  
  399.  
  400. 'CustomContent6': {
  401. type: 'custom-content',
  402. content: '<h4>First person</h4>'
  403. },
  404. Fullname1: {
  405. title: 'Full name',
  406. displayname: 'Full name',
  407. placeholder: 'First / M.I./ Last Name'
  408. },
  409. Title1: {
  410. title: 'Title',
  411. displayname: 'Title',
  412. placeholder: 'Title'
  413.  
  414. },
  415. SSN1: {
  416. title: 'Social Security number (SSN)',
  417. displayname: 'Social Security number',
  418. placeholder: 'SSN (9 digits)'
  419. },
  420. Married1CHK: {
  421. title: 'Married',
  422. displayname: 'Married'
  423. },
  424. Single1CHK: {
  425. title: 'Single',
  426. displayname: 'Single'
  427. },
  428. DL1: {
  429. title: 'Driver License',
  430. displayname: 'Driver License',
  431. placeholder: 'Driver License'
  432. },
  433. DLState1: {
  434. title: 'Driver License state',
  435. displayname: 'Driver License state',
  436. placeholder: 'Driver License state'
  437. },
  438.  
  439. 'CustomContent7': {
  440. type: 'custom-content',
  441. content: '<h4>Name of spouse</h4>'
  442. },
  443. SpFullname1: {
  444. title: 'Full name',
  445. displayname: 'Full name of spouse',
  446. placeholder: 'First / M.I. / Last Name'
  447. },
  448. SpSSN1: {
  449. title: 'Social Security number (SSN)',
  450. displayname: 'Social Security number',
  451. placeholder: 'SSN (9 digits)'
  452. },
  453.  
  454. 'CustomContent8': {
  455. type: 'custom-content',
  456. content: '<h4>Current landlord/mortgage company</h4>'
  457. },
  458. LL1: {
  459. title: 'Company name',
  460. displayname: 'Company name',
  461. placeholder: 'Company name'
  462. },
  463. LLPhone1: {
  464. title: 'Company phone number',
  465. displayname: 'Phone number',
  466. placeholder: 'Phone number'
  467. },
  468.  
  469. ResAddr1A: {
  470. title: 'Current residence address',
  471. displayname: 'Current residence address',
  472. placeholder: 'Current residence address (line 1)'
  473. },
  474. ResAddr1B: {
  475. title: 'Current residence address',
  476. displayname: '',
  477. placeholder: 'Current residence address (line 2)'
  478. },
  479. HmPhone1: {
  480. title: 'Home phone',
  481. displayname: 'Home phone',
  482. placeholder: 'Home phone'
  483. },
  484.  
  485. Years1: {
  486. title: 'Years at this location',
  487. displayname: 'Years at this location',
  488. placeholder: 'Years at this location',
  489. type: 'number',
  490. min: 0,
  491. max: 100
  492. },
  493.  
  494. PrintName1: {
  495. title: 'Signed by (name)',
  496. displayname: 'Signed by (name)',
  497. placeholder: 'Signed by (name)'
  498. },
  499. Title1a: {
  500. title: 'Signed by (title)',
  501. displayname: 'Signed by (title)',
  502. placeholder: 'Signed by (title)'
  503. },
  504. SignedDate: {
  505. title: 'Signed date',
  506. displayname: 'Signed date',
  507. placeholder: 'Signed date',
  508. type: 'date',
  509. defaultvalue: new Date().toJSON().slice(0, 10)
  510. },
  511.  
  512. Fullname2: {
  513. hidden: true
  514. },
  515. Title2: {
  516. hidden: true
  517. },
  518. SSN2: {
  519. hidden: true
  520. },
  521. Married2CHK: {
  522. hidden: true
  523. },
  524. Single2CHK: {
  525. hidden: true
  526. },
  527. DL2: {
  528. hidden: true
  529. },
  530. DLState2: {
  531. hidden: true
  532. },
  533. SpFullname2: {
  534. hidden: true
  535. },
  536. SpSSN2: {
  537. hidden: true
  538. },
  539. LL2: {
  540. hidden: true
  541. },
  542. LLPhone2: {
  543. hidden: true
  544. },
  545. ResAddr2A: {
  546. hidden: true
  547. },
  548. ResAddr2B: {
  549. hidden: true
  550. },
  551. HmPhone2: {
  552. hidden: true
  553. },
  554. Years2: {
  555. hidden: true
  556. },
  557.  
  558. TradeRef1: {
  559. title: 'Trade references',
  560. displayname: 'Trade references',
  561. placeholder: 'Trade references (line 1)'
  562. },
  563. TradeRef2: {
  564. title: 'Trade references',
  565. displayname: '',
  566. placeholder: 'Trade references (line 2)'
  567. },
  568. TradeRef3: {
  569. title: 'Trade references',
  570. displayname: '',
  571. placeholder: 'Trade references (line 3)'
  572. },
  573.  
  574. PrintName2: {
  575. hidden: true
  576. },
  577. Title2a: {
  578. hidden: true
  579. },
  580. SignedDate2: {
  581. hidden: true
  582. }
  583. }
  584. };
  585. var viewer = new GcPdfViewer(selector, options);
  586.  
  587. // Add default sidebar panels
  588. viewer.addDefaultPanels();
  589.  
  590. // Configure toolbar buttons:
  591. viewer.toolbarLayout.viewer = {
  592. default: ['open', 'save', 'form-filler', '$navigation', '$split', 'text-selection', 'pan', '$zoom', '$fullscreen', 'print', 'title', 'about'],
  593. mobile: ['open', 'save', 'form-filler', '$navigation', 'title', 'about'],
  594. fullscreen: ['$fullscreen', 'open', 'save', 'form-filler', '$navigation', '$split', 'text-selection', 'pan', '$zoom', 'print', 'title', 'about']
  595. };
  596. if(!viewer.options.supportApi) {
  597. viewer.options.supportApi = {
  598. apiUrl: (window.__baseUrl || '') + 'support-api/gc-pdf-viewer',
  599. token: window.afToken || '',
  600. webSocketUrl: (window.__baseUrl || '') + 'signalr',
  601. suppressInfoMessages: true, suppressErrorMessages: true
  602. };
  603. }
  604. viewer.applyToolbarLayout();
  605. viewer.applyOptions();
  606. viewer.onAfterOpen.register(function(args) {
  607. var fileName = viewer.fileName;
  608. if (fileName.indexOf('viewer-form-filler') !== -1 ||
  609. fileName.indexOf('get-sample-pdf') !== -1 ||
  610. fileName.indexOf('GetSamplePdf') !== -1) {
  611. viewer.options.formFiller = formFiller_RentalApplicationForm;
  612. viewer.showFormFiller();
  613. } else {
  614. viewer.options.formFiller = {};
  615. }
  616. });
  617. return viewer;
  618. }
  619. ";
  620.  
  621. public static List<string[]> GetSampleParamsList()
  622. {
  623. return new List<string[]>()
  624. {
  625. new string[] { "@viewer/Form Filler", "Form filler customized in JS code for a particular PDF form", null },
  626. new string[] { "@use/Tenant Application", "Fill Tenant application form using DsPdfViewer&#x27;s Form filler dialog", null },
  627. };
  628. }
  629. }
  630. }
  631.