UNPKG

formio-sfds

Version:
227 lines (200 loc) 7.04 kB
const { URL } = require('url') const fetch = require('node-fetch') const { JSDOM } = require('jsdom') const packageJson = require('../package.json') const LIVE_URL = 'https://sf.gov' const environments = { live: LIVE_URL, test: 'https://test-sfgov.pantheonsite.io' } class Proxy { constructor (options) { const { env = 'live', base } = options || {} this.base = options.url || base || environments[env] || LIVE_URL console.info('proxy base URL:', this.base) this.options = options } fetch (url) { const actualUrl = /^https?:/.test(url) ? url : new URL(url, this.base).href console.warn('fetching:', actualUrl) return fetch(actualUrl) .then(async res => { this.response = res this.url = actualUrl this.body = await res.text() this.dom = new JSDOM(this.body) this.document = this.dom.window.document const base = this.document.createElement('base') base.setAttribute('href', String(this.base)) this.document.head.insertBefore(base, this.document.head.firstChild) return this }) } transform (query) { const { version, formioSFDSVersion = version, formiojsVersion, lang, env = 'live' } = query const { document, url } = this let { source, options } = query this.setFormioSFDSVersion(formioSFDSVersion) if (formiojsVersion) { this.setFormioJSVersion(formiojsVersion) } const div = document.querySelector('[data-source]') if (div) { if (source) { div.setAttribute('data-source', source) } else { source = div.getAttribute('data-source') } if (lang) { div.setAttribute('lang', lang) } if (options) { const optstr = options instanceof Object ? JSON.stringify(options) : options div.setAttribute('data-options', optstr) } else { options = div.getAttribute('data-options') } const info = this.element('div', { class: 'formio-sfds' }) info.innerHTML = ` <details class="my-4 notranslate" lang="en" translate="no"> <summary class="m-0">⚠️ This is a form preview</summary> <div class="bg-blue-1 p-2 border-1 border-bright-blue round-bottom-1"> <p class="mt-0 mb-1"> <b>You are viewing this form in a simulated sf.gov environment.</b> The form should function as expected, and styles should reflect what you will see when this version of <code>formio-sfds</code> is used on sf.gov. Some additional information is listed below. </p> <dl class="m-0"> <dt><b>Fetched URL</b></dt> <dd class="mb-1 ml-2"> <a href="${url}"><code>${url}</code></a> ${env ? `(via <code>env=${env}</code>)` : ''} </dd> <dt><b>Form.io JS versions </b></dt> <dd class="mb-0 ml-2"> <a data-script-src="formiojs"> <code>formiojs@${formiojsVersion || this.getScriptVersion('formiojs')}</code> </a> </dd> <dd class="mb-0 ml-2"> <a data-script-src="formio-sfds"> <code>formio-sfds@${formioSFDSVersion || this.getScriptVersion('formio-sfds') || packageJson.version}</code> </a> ${formioSFDSVersion ? '' : ' (local)'} </dd> <dt><b>Form data source URL</b></dt> <dd class="mb-1 ml-2">${ source ? `<a href="${source}"><code>${source}</code></a>` : 'not provided' }</dd> <dt><b>Form options</b></dt> <dd class="mb-1 ml-2">${ options ? `<pre>${JSON.stringify(JSON.parse(options), null, 2)}</pre>` : 'none provided' }</dd> </ul> </div> </details> `.trim() div.parentNode.insertBefore(info, div) this.appendScript(` Array.from(document.querySelectorAll('[data-script-src]')).forEach(link => { var pattern = link.getAttribute('data-script-src') var script = document.querySelector('script[src*=' + pattern + ']') if (script) { link.href = script.src } }) `) } else { console.warn('no [data-source] form element found!') } } appendScript (code) { const script = this.document.createElement('script') script.textContent = `(function () { ${code} })()` this.document.body.appendChild(script) } getScript (srcPattern) { const selector = `script[src*="${srcPattern}"]` return this.document.querySelector(selector) } getScriptVersion (srcPattern) { const script = this.getScript(srcPattern) if (script) { const match = script.src.match(/@([^/]+)/) return match ? match[1] : undefined } return undefined } setFormioSFDSVersion (version) { const script = this.getScript('formio-sfds@') if (script) { if (version) { script.setAttribute('src', script.src.replace(/formio-sfds@[^/]+/, `formio-sfds@${version}`)) } else { script.removeAttribute('src') script.textContent = ` document.addEventListener('DOMContentLoaded', () => { var script = document.createElement('script') var baseUrl = [ location.protocol, '//', location.hostname, location.port ? ':' + location.port : '' ].join('') var formioSfdsUrl = document.getElementById('formio-sfds-url') script.src = baseUrl + '/dist/formio-sfds.standalone.js' console.info('injected formio-sfds:', script.src) document.body.appendChild(script) if(formioSfdsUrl) { formioSfdsUrl.href = script.src } }) ` } } else { throw new Error('No <script> found with formio-sfds in the src attribute') } } setFormioJSVersion (version) { const script = this.getScript('formiojs@') if (script) { script.setAttribute('src', script.src.replace(/formiojs@[^/]+/, `formiojs@${version}`)) } else { throw new Error('No <script> found with formiojs in the src attribute') } } element (name, attrs = {}, children = []) { const el = this.document.createElement(name) if (attrs) { for (const [key, value] of Object.entries(attrs)) { el.setAttribute(key, value) } } if (typeof children === 'string') { el.innerHTML = children } else if (Array.isArray(children)) { for (const child of children) { el.appendChild(child) } } return el } send (res) { const html = this.dom.serialize() res.setHeader('Content-Type', 'text/html') res.setHeader('Content-Length', Buffer.byteLength(html)) res.end(html, 'utf8') } } module.exports = { LIVE_URL, environments, Proxy }