ViewerFormFiller.cs
// 完毕:
using System.IO;
using System.Collections.Generic;
using GrapeCity.Documents.Pdf;

namespace DsPdfWeb.Demos
{
    // 
    // This sample demonstrates using the GcPdfViewer's Form Filler.
    // It loads an example Commercial Rental Application Form.
    // To make form input more convenient, we customize the appearance and 
    // behavior of the Form Filler dialog using the formFiller option. 
    // After loading the document - the Form Filler dialog is displayed 
    // using the client side showFormFiller method.

    // 此示例和本节中的其他示例演示了 GcDocs.PdfViewer 的功能
    // (GcDocs.Pdf 中包含的 JavaScript PDF 查看器控件),主要是能力
    // 更改 PDF 文件(添加或编辑注释和 AcroForm 字段、旋转页面等)
    // 当服务器上运行的 GcDocs.Pdf 支持客户端上的 JS 查看器时。
    // 
    // 要启用查看器的编辑功能,必须设置其 supportApi 属性
    // 到服务器上实现全部或部分编辑支持 API 的 URL
    // 观众已知/期望的。这个 GcDocs.Pdf 演示站点提供了这些 API,
    // 这使得您可以在打开 PDF 查看器时演示编辑过程
    // 在这个样本中。当您下载此示例时,除了 .NET Core
    // 生成示例 PDF 的控制台应用程序项目,一个 ASP.NET Core 项目是
    // 也包含在下载 zip 中(位于 GcPdfViewerWeb 子文件夹中)
    // 下载的 zip),它还提供了必要的 API。特别是,它包括
    // 一个实现 API 并通过特殊控制器提供它们的项目。
    // 它实际上与此 GcDocs.Pdf 演示站点使用的控制器相同,并且
    // 可以在任何 ASP.NET Core 站点中使用以启用查看器编辑功能。
    // 
    // 查看示例下载 zip 中的以下文件以获取更多信息:
    // - GcPdfViewerWeb\SupportApiDemo:示例 ASP.NET Core 网站。
    // - GcPdfViewerWeb\SupportApiDemo.sln:构建/运行示例网站的解决方案。
    // - GcPdfViewerWeb\SupportApi:支持API实现(可以在任何站点中使用)。
    // - GcPdfViewerWeb\SupportApi\Controllers\GcPdfViewerController.cs:支持 API 控制器。
    // 
    // 请注意,此示例和本节中的其他示例目前仅提供 C# 版本。
    public class ViewerFormFiller
    {
        public void CreatePDF(Stream stream)
        {
            CreatePDF(stream, 0);
        }

        public void CreatePDF(Stream stream, int _)
        {
            var doc = new GcPdfDocument();
            using var fs = File.OpenRead(Path.Combine("Resources", "PDFs", "Commercial-Rental-Application-Form.pdf"));
            doc.Load(fs);
            doc.Save(stream);
        }

        public const string JS_CODE = @"
var requiredPhonePattern = '^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$';
var requiredPhoneValidationMessage = 'Valid formats: 1234567890, (123)456-7890,\n 123-456-7890, 123.456.7890, +31636363634, 075-63546725';
var optionalPhonePattern = '^$|^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$';
var optionalPhoneValidationMessage = 'Field is optional, valid formats:\n 1234567890, (123)456-7890,\n 123-456-7890, 123.456.7890, +31636363634, 075-63546725';
var ovnPark_FieldValue_On = 'Has overnight parking.', ovnPark_FieldValue_Off = 'NO';
var updatingFieldsFlag = false;
function combineTwoFieldsIntoOneValue(destfieldName, fieldName2, formFiller) {
            var addr1 = formFiller.getFieldByName(destfieldName);
            var addr2 = formFiller.getFieldByName(fieldName2);
            if(addr1 && addr2) {
                if(addr2.fieldValue) {
                    addr1.fieldValue = addr1.fieldValue + '\n' + addr2.fieldValue;
                    addr2.fieldValue = '';
                    formFiller.onFieldChanged(addr1);
                    formFiller.onFieldChanged(addr2);
                }
            }
}
function splitFieldValueIntoTwoFields(srcfieldName, fieldName2, formFiller) {
            var addr1 = formFiller.getFieldByName(srcfieldName);
            var addr2 = formFiller.getFieldByName(fieldName2);
            if(addr1 && addr2) {
                var s = addr1.fieldValue;
                var nlInd = s.indexOf('\n');
                if(nlInd !== -1) {
                    var firstPart = s.substring(0, nlInd);
                    var secondPart = s.substr(nlInd + 1);
                    addr1.fieldValue = firstPart;
                    addr2.fieldValue = secondPart;
                } else {
                    addr2.fieldValue = '';
                }
                formFiller.onFieldChanged(addr1);
                formFiller.onFieldChanged(addr2);
            }
}
function createPdfViewer(selector, baseOptions) {
    var options = baseOptions || {};
    // Form Filler options for 'RentalApplicationForm' document:
    var formFiller_RentalApplicationForm = {
        onInitialize: function(formFiller) {
            combineTwoFieldsIntoOneValue('Addr1', 'Addr2', formFiller);
            combineTwoFieldsIntoOneValue('BusAddr1', 'BusAddr2', formFiller);
            var ovnParkField = formFiller.getFieldByName('OvnPark');
            if(ovnParkField.fieldValue) {
                var ovnPark_LowVal = (ovnParkField.fieldValue || '').toLowerCase();
                if(!ovnPark_LowVal || ovnPark_LowVal.indexOf('no') !== -1 || ovnPark_LowVal === 'off' || ovnPark_LowVal === 'false') {
                    ovnParkField.fieldValue = 'Off';
                    formFiller.onFieldChanged(ovnParkField);
                } else {
                    ovnPark_FieldValue_On = ovnParkField.fieldValue;// remember current On value.
                    ovnParkField.fieldValue = 'On';
                    formFiller.onFieldChanged(ovnParkField);
                }
                
            }
        },
        beforeApplyChanges: function(formFiller) {
            splitFieldValueIntoTwoFields('Addr1', 'Addr2', formFiller);
            splitFieldValueIntoTwoFields('BusAddr1', 'BusAddr2', formFiller);
            var ovnParkField = formFiller.getFieldByName('OvnPark');
            if(ovnParkField.fieldName === 'OvnPark') {
                if(ovnParkField.fieldValue === 'On') {
                    ovnParkField.fieldValue = ovnPark_FieldValue_On;
                } else {
                    ovnParkField.fieldValue = ovnPark_FieldValue_Off;
                }
            }
            return true;
        },
        beforeFieldChange: function(changedField, formFiller) {
            if(updatingFieldsFlag) 
                return true;
            var setFieldValue = function(chkboxFieldName, newVal) {
                var tmpField = formFiller.getFieldByName(chkboxFieldName);
                if(tmpField.fieldValue !== newVal) {
                    tmpField.fieldValue = newVal;
                    formFiller.onFieldChanged(tmpField);
                }
            };
            updatingFieldsFlag = true;
            try {
                var fieldName = changedField.fieldName;
                var fieldValue = changedField.fieldValue;
                if(fieldName === 'Married1CHK' || fieldName === 'Single1CHK') {
                    if(fieldName === 'Married1CHK')
                        setFieldValue('Single1CHK', 'Off');
                    if(fieldName === 'Single1CHK')
                        setFieldValue('Married1CHK', 'Off');
                    if(fieldValue === 'Off')
                        return false; // prevent uncheck
                }
                if(fieldName === 'CorpCHK' || fieldName === 'GPCHK' || fieldName === 'IndivCHK') {
                    // Uncheck other fields:
                    switch(fieldName) {
                        case 'CorpCHK':
                            setFieldValue('GPCHK', 'Off');
                            setFieldValue('IndivCHK', 'Off');
                            break;
                        case 'GPCHK':
                            setFieldValue('CorpCHK', 'Off');
                            setFieldValue('IndivCHK', 'Off');
                            break;
                        case 'IndivCHK':
                            setFieldValue('CorpCHK', 'Off');
                            setFieldValue('GPCHK', 'Off');
                            break;
                        default:
                            break;
                    }
                    if(fieldValue === 'Off')
                        return false; // prevent uncheck
                }
            } finally {
                updatingFieldsFlag = false;
            }
            return true;
        },
        mappings: {
            'CustomContent1': { 
                type: 'custom-content', 
                content: '<h2>COMMERCIAL TENANT APPLICATION</h2>'
            },
            'AppDate': {                                
                title: 'Application date',
                displayname: 'Date',
                type: 'date',
                defaultvalue: new Date().toJSON().slice(0, 10)
            },
            'Entity': {                
                autofocus: true,
                title: 'Name of individual, partnership, or corporation',
                displayname: 'Applicant or Leasing Entity',
                placeholder: 'Name of individual, partnership, or corporation',
                required: true,
                validationmessage: 'Entity name is required',
                validateoninput: true
            },
            'CustomContent2': { 
                type: 'custom-content', 
                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>'
            },
            'Addr1': {       
                title: 'Current corporate headquarters/home address (For partnership/individuals) (Do not use P.O. Box)',
                displayname: 'Current address',
                placeholder: 'Current corporate headquarters/home address (For partnership/individuals) (Do not use P.O. Box)',
                multiline: true,
                required: true,
                validationmessage: 'Address is required',
                validateoninput: true
            },
            'Addr2': {        
                hidden: true,
            },
            'CorpPhone': {                
                title: 'Corporate phone number',
                displayname: 'Corporate phone #',
                placeholder: 'Corporate phone',
                type: 'tel',
                pattern: requiredPhonePattern,
                validationmessage: requiredPhoneValidationMessage,
                validateoninput: true
            },

            'CorpState': {                
                title: 'State where the company was registered',
                displayname: 'State of incorporation',
                placeholder: 'State of incorporation',
                validateoninput: true,
                validator: function(fieldValue, field) { 
                    if(!fieldValue || !fieldValue.trim())
                        return 'This field cannot be empty';
                    if(fieldValue.toLowerCase().indexOf('delaware') === -1)
                        return 'Only Delaware state allowed.';
                    return true;
                }
            },
            'DBA': {                
                title: 'DBA (Doing Business As)',
                displayname: 'DBA name',
                placeholder: 'DBA',
                required: true
            },
            'HomePhone': {                
                title: 'Home phone number (for partnerships/Individuals)',
                displayname: 'Home phone #',
                placeholder: 'Home phone (optional)',
                type: 'tel',
                pattern: optionalPhonePattern,
                validationmessage: optionalPhoneValidationMessage,
                validateoninput: true
            },
            'PtnrState': {
                title: 'State of partnership formation',
                displayname: 'State of partnership formation',
                placeholder: 'State of partnership formation'
            },
            'LocalPhone': {                
                title: 'Local phone number',
                displayname: 'Local phone #',
                placeholder: 'Local phone (optional)',
                type: 'tel',
                pattern: optionalPhonePattern,
                validationmessage: optionalPhoneValidationMessage,
                validateoninput: true
            },

            'Use1': {                
                title: 'Full description of intended use',
                displayname: 'Intended use',
                placeholder: 'Intended use (line 1)',
                required: true
            },
            'Use2': {       
                title: 'Full description of intended use',
                displayname: '',
                placeholder: 'Intended use (line 2)'
            },
            'Use3': {                
                title: 'Full description of intended use',
                displayname: '',
                placeholder: 'Intended use (line 3)'
            },
            'CustomContent3': { 
                type: 'custom-content', 
                content: '<h2>CURRENT BUSINESS LANDLORD</h2>'
            },
            'CurrLandlord': {
                title: 'Current business landlord name',
                displayname: 'Name',
                placeholder: 'Landlord name'
            },

            LandLordPhone: {
                title: 'Phone number',
                displayname: 'Phone #',
                placeholder: 'Phone (optional)',
                type: 'tel',
                pattern: optionalPhonePattern,
                validationmessage: optionalPhoneValidationMessage,
                validateoninput: true

            },
            BusAddr1: {
                title: 'Present business address',
                displayname: 'Present business address',
                placeholder: 'Present business address',
                multiline: true
            },
            BusAddr2: {
             hidden: true
            },
            NumYears: {
                title: 'Years at this location',
                displayname: 'Years at this location',
                placeholder: 'Years at this location',
                type: 'number',
                min: 0,
                max: 100
            },
            NumEmployees: {
                title: 'Number of employees',
                displayname: 'Number of employees',
                placeholder: 'Number of employees',
                type: 'number',
                min: 0,
                max: 1000000
            },
            PkgSpaces: {
                title: 'Number of parking spaces needed',
                displayname: 'Number of parking spaces needed',
                placeholder: 'parking spaces number',
                type: 'number',
                min: 0,
                max: 1000000
            },
            OvnPark: {
                title: 'Any overnight parking?',
                displayname: 'Any overnight parking?',
                type: 'checkbox'
            },
            BankAcct: {
                title: 'Bank account number',
                displayname: 'Account number',
                placeholder: 'Account number',
                minlength: 8,
                maxlength: 12,
                validationmessage: 'Expected value between 8 and 12 digits',
                validateoninput: true
            },
            BankPhone: {
                title: 'Bank phone number',
                displayname: 'Phone number'
            },
            BankRef: {
                title: 'Bank reference',
                displayname: 'Bank reference'
            },
            BankContact: {
                title: 'Contact name',
                displayname: 'Contact name'
            },

            'CustomContent4': { 
                type: 'custom-content', 
                content: '<h4>Please list all hazardous substances that will be on the premises and the approximate amounts</h4>'
            },
            HazSub1: {
                title: 'Please list all hazardous substances that will be on the premises and the approximate amounts',
                placeholder: 'List all hazardous substances that will be on the premises and the approximate amount (line 1)',
                nolabel: true
            },
            HazSub2: {
                title: 'Please list all hazardous substances that will be on the premises and the approximate amounts',
                placeholder: 'List all hazardous substances that will be on the premises and the approximate amount (line 2)',
                nolabel: true
            },
            HazSub3: {
                title: 'Please list all hazardous substances that will be on the premises and the approximate amounts',
                placeholder: 'List all hazardous substances that will be on the premises and the approximate amount (line 3)',
                nolabel: true
            },
            'CustomContent5': { 
                type: 'custom-content', 
                content: '<h4>Please check one:</h4>'
            },
            CorpCHK: {
                title: 'Corporate',
                displayname: 'Corporate'
            },
            GPCHK: {
                title: 'General partner(s)',
                displayname: 'General partner(s)'
            },
            IndivCHK: {
                title: 'Individual(s) signing the lease',
                displayname: 'Individual(s) signing the lease'
            },



            'CustomContent6': { 
                type: 'custom-content', 
                content: '<h4>First person</h4>'
            },
            Fullname1: {
                title: 'Full name',
                displayname: 'Full name',
                placeholder: 'First / M.I./ Last Name'
            },
            Title1: {
                title: 'Title',
                displayname: 'Title',
                placeholder: 'Title'

            },
            SSN1: {
                title: 'Social Security number (SSN)',
                displayname: 'Social Security number',
                placeholder: 'SSN (9 digits)'
            },
            Married1CHK: {
                title: 'Married',
                displayname: 'Married'
            },
            Single1CHK: {
                title: 'Single',
                displayname: 'Single'
            },
            DL1: {
                title: 'Driver License',
                displayname: 'Driver License',
                placeholder: 'Driver License'
            },
            DLState1: {
                title: 'Driver License state',
                displayname: 'Driver License state',
                placeholder: 'Driver License state'
            },

            'CustomContent7': { 
                type: 'custom-content', 
                content: '<h4>Name of spouse</h4>'
            },
            SpFullname1: {
                title: 'Full name',
                displayname: 'Full name of spouse',
                placeholder: 'First / M.I. / Last Name'            
            },
            SpSSN1: {
                title: 'Social Security number (SSN)',
                displayname: 'Social Security number',
                placeholder: 'SSN (9 digits)'
            },

            'CustomContent8': { 
                type: 'custom-content', 
                content: '<h4>Current landlord/mortgage company</h4>'
            },
            LL1: {
                title: 'Company name',
                displayname: 'Company name',
                placeholder: 'Company name'
            },
            LLPhone1: {
                title: 'Company phone number',
                displayname: 'Phone number',
                placeholder: 'Phone number'
            },

            ResAddr1A: {
                title: 'Current residence address',
                displayname: 'Current residence address',
                placeholder: 'Current residence address (line 1)'
            },
            ResAddr1B: {
                title: 'Current residence address',
                displayname: '',
                placeholder: 'Current residence address (line 2)'
            },
            HmPhone1: {
                title: 'Home phone',
                displayname: 'Home phone',
                placeholder: 'Home phone'
            },

            Years1: {
                title: 'Years at this location',
                displayname: 'Years at this location',
                placeholder: 'Years at this location',
                type: 'number',
                min: 0,
                max: 100
            },

            PrintName1: {
                title: 'Signed by (name)',
                displayname: 'Signed by (name)',
                placeholder: 'Signed by (name)'
            },
            Title1a: {
                title: 'Signed by (title)',
                displayname: 'Signed by (title)',
                placeholder: 'Signed by (title)'
            },
            SignedDate: {
                title: 'Signed date',
                displayname: 'Signed date',
                placeholder: 'Signed date',
                type: 'date',
                defaultvalue: new Date().toJSON().slice(0, 10)
            },

            Fullname2: {
             hidden: true
            },
            Title2: {
             hidden: true
            },
            SSN2: {
             hidden: true
            },
            Married2CHK: {
             hidden: true
            },
            Single2CHK: {
             hidden: true
            },
            DL2: {
             hidden: true
            },
            DLState2: {
             hidden: true
            },
            SpFullname2: {
             hidden: true
            },
            SpSSN2: {
             hidden: true
            },
            LL2: {
             hidden: true
            },
            LLPhone2: {
             hidden: true
            },
            ResAddr2A: {
             hidden: true
            },
            ResAddr2B: {
             hidden: true
            },
            HmPhone2: {
             hidden: true
            },
            Years2: {
             hidden: true
            },

            TradeRef1: {
                title: 'Trade references',
                displayname: 'Trade references',
                placeholder: 'Trade references (line 1)'
            },
            TradeRef2: {
                title: 'Trade references',
                displayname: '',
                placeholder: 'Trade references (line 2)'
            },
            TradeRef3: {
                title: 'Trade references',
                displayname: '',
                placeholder: 'Trade references (line 3)'
            },

            PrintName2: {
             hidden: true
            },
            Title2a: {
             hidden: true
            },
            SignedDate2: {
             hidden: true
            }
        }
    };
    
    var viewer = new GcPdfViewer(selector, options);

    // Add default sidebar panels
    viewer.addDefaultPanels();

    // Configure toolbar buttons:    
    viewer.toolbarLayout.viewer = { 
        default: ['open', 'save', 'form-filler', '$navigation', '$split', 'text-selection', 'pan', '$zoom', '$fullscreen', 'print', 'title', 'about'], 
        mobile: ['open', 'save', 'form-filler', '$navigation', 'title', 'about'], 
        fullscreen: ['$fullscreen', 'open', 'save', 'form-filler', '$navigation', '$split', 'text-selection', 'pan', '$zoom', 'print', 'title', 'about'] 
    };
    if(!viewer.options.supportApi) {
        viewer.options.supportApi = {
            apiUrl: (window.__baseUrl || '') + 'support-api/gc-pdf-viewer',
            token: window.afToken || '',
            webSocketUrl: (window.__baseUrl || '') + 'signalr',
            suppressInfoMessages: true, suppressErrorMessages: true
        };
    }
    viewer.applyToolbarLayout();
    viewer.applyOptions();
    viewer.onAfterOpen.register(function(args) {
        var fileName = viewer.fileName;
        if (fileName.indexOf('viewer-form-filler') !== -1 || 
            fileName.indexOf('get-sample-pdf') !== -1 ||
            fileName.indexOf('GetSamplePdf') !== -1) {
            viewer.options.formFiller = formFiller_RentalApplicationForm;
            viewer.showFormFiller();
        } else {
            viewer.options.formFiller = {};
        }
    });
    return viewer;
}
";

        public static List<string[]> GetSampleParamsList()
        {
            return new List<string[]>()
            {
                new string[] { "@viewer/Form Filler", "Form filler customized in JS code for a particular PDF form", null },
                new string[] { "@use/Tenant Application", "Fill Tenant application form using DsPdfViewer&#x27;s Form filler dialog", null },
            };
        }
    }
}