Skip to content

Instantly share code, notes, and snippets.

@ndbroadbent
Created November 5, 2019 19:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ndbroadbent/b45f59e53aa1e3841e9b4c11e188413e to your computer and use it in GitHub Desktop.
Save ndbroadbent/b45f59e53aa1e3841e9b4c11e188413e to your computer and use it in GitHub Desktop.
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>
sample-coi.pdf
- FormAPI.io</title>
<link rel="stylesheet" media="all" href="/assets/bootstrap-4e3cebc9fbc5fb97aaa32ed51a086b63d9fef4e3ce46082c4ecd8fa5dc3ddc2d.css" />
<link rel="stylesheet" media="all" href="/assets/web_form-be7376ecee212758c2e2f9e8c0ddd9f280c703b32cc8bb0a7afe3da0139d8336.css" />
</head>
<body>
<div class="alert alert-danger error-messages" role="alert" style="display: none;" >
</div>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h3>Embedded Data Request Example</h3><br/>
<!--[if lte IE 9]>
<div style="color: #444444; max-width: 700px; margin: 0 auto;">
<h2>Sorry, your browser is not supported.</h2>
<p>
Microsoft has
<a href="https://www.microsoft.com/en-us/windowsforbusiness/end-of-ie-support">
stopped supporting Internet Explorer 10 and below</a>.
Your browser no longer receives security updates, and
your computer is at risk of being infected with viruses and other malicious software.
It may not be safe to display sensitive information in your browser,
and we cannot guarantee the authenticity of your electronic signature.
<p>
<h4>Please install a modern browser to sign this document:</h4>
<ul>
<li><a href="https://www.microsoft.com/en-us/download/internet-explorer-11-for-windows-7-details.aspx">
Download Internet Explorer 11
</a></li>
<li><a href="https://www.microsoft.com/en-us/windows/microsoft-edge">
Download Microsoft Edge
</a></li>
<li><a href="https://www.google.com/chrome/">
Download Google Chrome
</a></li>
<li><a href="https://www.mozilla.org/en-US/firefox/new/">
Download Firefox
</a></li>
</ul>
<p style="color: #888888; font-size: 13px;">
(Please note that we also support iOS and Android, so you can sign the document on your phone.)
</p>
</div>
<![endif]-->
<ul>
<li>
<a href="/docs/data_requests.html">
View Data Requests Documentation
</a>
</li>
</ul>
<br/>
<p>
Create a test data request by entering your
name and email address in the form below. (Feel free to use fake details.)
</p>
<p>
After submitting the form, we will show the embedded signing window on this page.
</p>
<div class="panel" style="margin: 30px 0; padding: 15px 20px; border: 1px solid #eee;">
<form class="data-request-form" action="/embed_data_request_example" accept-charset="UTF-8" method="post"><input name="utf8" type="hidden" value="&#x2713;" /><input type="hidden" name="authenticity_token" value="LkHPnI90YaCB4KWhs76urXxM8VxcP5pzt0CRmtLh4Db4/lUZuyzIcdDLwl1po9OoY9tPQT+doso+bpYHjRneGQ==" />
<input value="tpl_VISUALDEMOmxEH34AAF" type="hidden" name="data_request[template_id]" id="data_request_template_id" />
<div class="form-group">
<label for="data_request_email">Email</label>
<input class="form-control" value="test@example.com" type="text" name="data_request[email]" id="data_request_email" />
</div>
<div class="form-group">
<label for="data_request_show_inline">Show Form Inline</label>&nbsp;
<input name="data_request[show_inline]" type="hidden" value="0" /><input type="checkbox" value="1" name="data_request[show_inline]" id="data_request_show_inline" />
</div>
<div class="form-group">
<label for="data_request_multiple_signers">Multiple Signers</label>&nbsp;
<input name="data_request[multiple_signers]" type="hidden" value="0" /><input type="checkbox" value="1" name="data_request[multiple_signers]" id="data_request_multiple_signers" />
</div>
<input type="submit" name="commit" value="Create Data Request" class="create-data-request btn btn-primary" disabled="disabled" data-disable-with="Create Data Request" />
<img class="loading-spinner" style="display: none;" src="/assets/loading-dark-8a70e0482f37a707559ab3f95c073d2809808d7d11d9c77e65812737817c5f51.svg" />
</form> </div>
</div>
</div>
<div class="row">
<div class="panel" id="formapi-form" style="max-width: 900px; margin: auto; box-shadow: 0 0 16px rgba(0,0,0,0.1);">
</div>
</div>
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="bs-callout bs-callout-info">
<p>
If you don't want to create a data request and an auth token,
you can also load the fields directly from the template.
We support two different kinds of forms.
<ul>
<li>
"Visual Forms" overlay the fields on top of the original document.<br/>
<a href="/embed_visual_example">See an Example</a>
</li>
<li>
"Simple Forms" are data collection forms with text fields,
similar to Google Forms, etc.<br/>
<a href="/embed_form_example">See an Example</a>
</li>
</ul>
</p>
<br/>
<h4>What if I don't use a Data Request?</h4>
<p>
Electronic signatures will not be legally binding if you don't use a Data Request.
For electronic signatures to be compliant with UETA and ESIGN regulations,
we need to record an audit trail, and you need to provide details about
how and when the user was authenticated. (If you send the user an email
with an authenticated link, then this counts as authentication.)
</p>
</div>
<br/>
</div>
</div>
</div>
<script src="/assets/raven-92f5fa1878b0d87c1d723d8f45bf274d28ef792e5acadf2f9777a772c5bd8f2b.js"></script>
<script>
Raven.config('https://513956e2470144ea8211a2a5160efee0@sentry.io/224002', {
environment: 'production',
shouldSendCallback(data) {
return !/^(.*CloudFlare-AlwaysOnline.*|.+MSIE 8\.0;.+)$/.test(window.navigator.userAgent);
}
}).install();
</script>
<script type="text/javascript" src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDjV6iibPCY4vDonKKwD5B3pEtFj8Hc4k4&libraries=places"></script>
<script src="/assets/web_form-5916c55749aa0c8c661c2125255ac566c34ff6ef780fedd2511668307c5869c0.js"></script>
<script src="/assets/web_form_dev-de3298462a2116c8a747ce67641628a68ad52a6407879f7c9652139460eb745d.js"></script>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-19054098-19', 'auto');
ga('send', 'pageview');
</script>
<script type="text/javascript" src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
if (window.Stripe) {
window.stripe = Stripe('pk_live_Ser7KlB2EZKi5F53DP0fRM1W');
}
</script>
<!--[if gte IE 9]><!-->
<script src="https://cdn.formapi.io/embed/data_request.v1.2.1.js"></script>
<!--<![endif]-->
<script>
if (window.FormAPI) {
$(function() {
var createDataRequest = function(dataRequest, token, onRemainingDataRequestsCallback) {
console.log("Showing Data Request with URL:", token.data_request_url);
// Show inline with:
// FormAPI.createVisualForm(selector, options)
FormAPI.createVisualForm({
// Pass a CSS selector to show the form inline on desktop.
// Leave this blank to always show the form in an modal overlay.
selector: $('#data_request_show_inline').prop('checked') ?
"#formapi-form" : null,
// Disables domain verification during development.
domainVerification: false,
// dataRequestURL: "",
dataRequestId: dataRequest.id,
tokenId: token.id,
tokenSecret: token.secret,
// Overrides the template's redirect URL
// redirectURL: 'example.com',
// As soon as the form is loaded, automatically focus the first field.
// (Default: The user must click the "Start" button to focus the first field.)
focusFirstFieldOnLoad: true,
// By default, the user must click the signature field to open the
// signature modal. Set the showSignatureModalOnFocus option to true
// if you want to open the signature modal automatically when a
// signature field is focussed (i.e. with the "Next" button or the Tab key).
// NOTE: It is important that the user can read the document before signing,
// and that they are aware of the location of their signature.
// The default behavior is much better for compliance reasons,
// because the user can view the document before they sign.
// However, this option might be useful if you want to streamline an
// internal document workflow.
showSignatureModalOnFocus: true,
// Allow the user to close the form if they click the darkened overlay
// (Default: true)
// closeModalOnClickOverlay: false,
// Close the modal as soon as the PDF job has been saved
// (But before the PDF has been processed)
// closeModalOnSave: false,
// Close the modal after the PDF has been processed.
// (Note: If submission privacy is set to "private", then
// we cannot poll for the status, so your should use closeModalOnSave.)
// closeModalOnProcessed: true,
// --------------------------------------------------------------------
// IMPORTANT: If you are embedding FormAPI in a single-page app and you
// want to redirect to a new page after the form has been filled,
// make sure you use either closeModalOnSave or closeModalOnProcessed.
// If you don't explicitly close the modal, it will just stay open,
// even if you "redirect" to another page using the pushState API.
// --------------------------------------------------------------------
// Time to wait for the iframe to load before throwing an error.
// Time is in milliseconds. Default: 30000 (30 seconds).
// You can handle this error in the onError callback. We will call:
// onError({ error: 'load_timeout', message: '...' })
// loadingTimeout: 30000,
// Customizations
// ------------------------------------------------------------------------------
// Hide the "clear form" button
// showClearButton: false,
// Don't show the "agree to terms of service" link
// showTermsOfServiceLink: false,
// Customize the terms of service link. (Default: FormAPI ToS)
// termsOfServiceLabel: 'YourCompany ToS',
// termsOfServiceURL: 'http://your-company.com/tos',
// When submitting data for a data request
submittingTitle: (template) =>
'Submitting Your Data...',
pdfProcessingTitle: (template) =>
'Processing Your Document...',
pdfProcessingMessage: (template) =>
`Please wait while we fill in ${template.name}...`,
// showPdfProcessingSpinner: false,
waitingForDataRequestsTitle: (remainingDataRequestsCount, template) =>
`You're the best! Thank you for filling out ${template.name}!`,
waitingForDataRequestsMessage: (remainingDataRequestsCount, template) =>
`${remainingDataRequestsCount} signer(s) remaining, ` +
'then the final PDF will be generated.',
completedTitle: (template, downloadURL) =>
`You're the best! Thank you for filling out ${template.name}!`,
completedTitleNoDownload: (template, downloadURL) =>
`You're the best! Thank you for filling out ${template.name}!`,
pdfProcessedMessage: (template, downloadURL) =>
`Click the "Download PDF" button to download the filled in ${template.name} PDF.`,
downloadButtonLabel: 'Download!',
// Callbacks:
// ------------------------------------------------------------------------------
onInitialize: function() {
console.log('[Callback] Form was initialized');
},
onLoad: function() {
console.log('[Callback] All form page images were loaded');
},
onClearForm: function() {
console.log('[Callback] Form was cleared');
},
onFieldFocus: function(field) {
console.log('[Callback] Focussed field:', field.name);
},
onFieldBlur: function(field) {
console.log('[Callback] Field lost focus:', field.name);
},
onFieldChange: function(field) {
var name = field.name,
value = field.value,
previousValue = field.previousValue;
console.log('[Callback] Changed field value.', {
name: name,
value: value,
previousValue: previousValue
});
},
onShowAcceptTerms: function() {
console.log('[Callback] Showing "accept terms"');
},
onSubmit: function(formData) {
console.log('[Callback] Form was submitted. Data:', formData);
},
onSave: function (submissionId) {
console.log('[Callback] Submission was saved:', submissionId);
},
onProcessed: function(data) {
console.log('[Callback] PDF was generated. Download at:', data.downloadURL);
},
onRemainingDataRequests: function(count) {
console.log('[Callback] Waiting for ' + count +
' more data request(s) to be completed.');
onRemainingDataRequestsCallback(count);
},
onError: function(error) {
console.log('[Callback] Error:', error);
}
});
}
$('form.data-request-form').submit(function(e) {
e.preventDefault();
$('input.create-data-request').hide();
$('.loading-spinner').show();
var form = $(this);
var url = form.attr('action');
$.ajax({
type: "POST",
url: url + ".json",
data: form.serialize(),
error: function(response) {
$('input.create-data-request').show();
$('.loading-spinner').hide();
$('.form-group').removeClass('has-error');
var errorMessage = 'Sorry, there were some problems with your form: ';
if (response.responseJSON && response.responseJSON.data_request_errors) {
var errors = [];
Object.keys(response.responseJSON.data_request_errors).forEach(function(f) {
response.responseJSON.data_request_errors[f].forEach(function(err) {
errors.push(f + ' ' + err);
});
$('input#data_request_' + f).parent('.form-group').addClass('has-error');
})
errorMessage += errors.join(', ');
}
$('.error-messages').text(errorMessage).show();
$(window).scrollTop(0);
},
success: function(data) {
$('input.create-data-request').show();
$('.loading-spinner').hide();
$('.error-messages').hide();
$('.form-group').removeClass('has-error');
console.log("Created " + data.data_requests.length + " data request(s)")
data.tokens.forEach(function(token) {
console.log("Data Request URL:", token.data_request_url);
})
var dataRequestIndex = 0;
var showNextDataRequest = function() {
var dataRequest = data.data_requests[dataRequestIndex];
var token = data.tokens[dataRequestIndex];
createDataRequest(dataRequest, token, function() {
dataRequestIndex++;
if (dataRequestIndex < data.data_requests.length) {
// Close modal and show next data request after a delay.
// (Gives integration test some time to check for the right text.)
setTimeout(function() {
FormAPI.closeModal();
showNextDataRequest();
}, 800);
}
})
}
showNextDataRequest();
}
});
});
// Enable the submit button now that we've set up the submit handler.
$('input.create-data-request').prop('disabled', false);
});
}
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment