Merge pull request #4956 from overleaf/jpa-jk-contact-form-de-ng

[web] de-ng contact form

GitOrigin-RevId: 8a92b37163555d6466e4b8c565f1ef490f73d49a
This commit is contained in:
Jakob Ackermann 2021-09-08 11:26:31 +02:00 committed by Copybot
parent 267b7fc17d
commit 7919017118
6 changed files with 135 additions and 5 deletions

View file

@ -121,7 +121,7 @@ html(
if (typeof(suppressFooter) == "undefined")
include layout/footer-marketing
!= moduleIncludes("contactModal", locals)
!= moduleIncludes("contactModal-marketing", locals)
block foot-scripts
each file in entrypointScripts(entrypoint)

View file

@ -0,0 +1,19 @@
import _ from 'lodash'
import AlgoliaSearch from 'algoliasearch'
import getMeta from '../../utils/meta'
let wikiIdx
export async function searchWiki(...args) {
if (!wikiIdx) {
const algoliaConfig = getMeta('ol-algolia')
const wikiIndex = _.get(algoliaConfig, 'indexes.wiki')
if (wikiIndex) {
const client = AlgoliaSearch(algoliaConfig.appId, algoliaConfig.apiKey)
wikiIdx = client.initIndex(wikiIndex)
}
}
if (!wikiIdx) {
return { hits: [], nbHits: 0, nbPages: 0 }
}
return wikiIdx.search(...args)
}

View file

@ -0,0 +1,12 @@
import { setupSearch } from './search'
document
.querySelectorAll('[data-ol-contact-form-with-search]')
.forEach(setupSearch)
document.querySelectorAll('a[ng-click="contactUsModal()"]').forEach(el => {
el.addEventListener('click', function (e) {
e.preventDefault()
$('[data-ol-contact-form-modal]').modal()
})
})

View file

@ -0,0 +1,86 @@
import _ from 'lodash'
import { searchWiki } from '../algolia-search/search-wiki'
import { sendMB } from '../../infrastructure/event-tracking'
function formatHit(hit) {
const pageUnderscored = hit.pageName.replace(/\s/g, '_')
const pageSlug = encodeURIComponent(pageUnderscored)
const pagePath = hit.kb ? 'how-to' : 'latex'
let pageAnchor = ''
let pageName = hit._highlightResult.pageName.value
if (hit.sectionName) {
pageAnchor = `#${hit.sectionName.replace(/\s/g, '_')}`
pageName += ' - ' + hit.sectionName
}
const url = `/learn/${pagePath}/${pageSlug}${pageAnchor}`
return { url, pageName }
}
export function setupSearch(formEl) {
const inputEl = formEl.querySelector('[name="subject"]')
const resultsEl = formEl.querySelector('[data-ol-search-results]')
const wrapperEl = formEl.querySelector('[data-ol-search-results-wrapper]')
let lastValue = ''
function hideResults() {
wrapperEl.setAttribute('hidden', '')
}
function showResults() {
wrapperEl.removeAttribute('hidden')
}
async function handleChange() {
const value = inputEl.value
if (value === lastValue) return
lastValue = value
if (value.length < 3) {
hideResults()
return
}
try {
const { hits, nbHits } = await searchWiki(value, {
hitsPerPage: 3,
typoTolerance: 'strict',
})
resultsEl.innerText = ''
for (const hit of hits) {
const { url, pageName } = formatHit(hit)
const liEl = document.createElement('li')
const linkEl = document.createElement('a')
linkEl.className = 'contact-suggestion-list-item'
linkEl.href = url
linkEl.target = '_blank'
liEl.append(linkEl)
const contentEl = document.createElement('span')
contentEl.innerHTML = pageName
linkEl.append(contentEl)
const iconEl = document.createElement('i')
iconEl.className = 'fa fa-angle-right'
iconEl.setAttribute('aria-hidden', 'true')
linkEl.append(contentEl)
resultsEl.append(liEl)
}
if (nbHits > 0) {
showResults()
sendMB('contact-form-suggestions-shown')
} else {
hideResults()
}
} catch (e) {
hideResults()
}
}
inputEl.addEventListener('input', _.debounce(handleChange, 350))
// display initial results
handleChange()
}

View file

@ -26,6 +26,7 @@ function formSubmitHelper(formEl) {
const captchaResponse = await validateCaptcha(formEl)
const data = await sendFormRequest(formEl, captchaResponse)
formEl.dispatchEvent(new Event('sent'))
// Handle redirects. From poking around, this still appears to be the
// "correct" way of handling redirects with fetch
@ -110,16 +111,27 @@ function formInflightHelper(el) {
disabledEl.disabled = false
toggleDisplay(showWhenInflightEl, showWhenNotInflightEl)
})
}
function toggleDisplay(hideEl, showEl) {
hideEl.setAttribute('hidden', '')
showEl.removeAttribute('hidden')
}
function formSentHelper(el) {
const showWhenPending = el.querySelector('[data-ol-not-sent]')
const showWhenDone = el.querySelector('[data-ol-sent]')
if (!showWhenDone) return
el.addEventListener('sent', () => {
toggleDisplay(showWhenPending, showWhenDone)
})
}
function toggleDisplay(hideEl, showEl) {
hideEl.setAttribute('hidden', '')
showEl.removeAttribute('hidden')
}
export function hydrateForm(el) {
formSubmitHelper(el)
formInflightHelper(el)
formSentHelper(el)
}
document.querySelectorAll(`[data-ol-form]`).forEach(form => hydrateForm(form))

View file

@ -2,5 +2,6 @@ import './utils/webpack-public-path'
import 'jquery'
import 'bootstrap'
import './features/form-helpers/hydrate-form'
import './features/contact-form'
$('[data-ol-lang-selector-tooltip]').tooltip({ trigger: 'hover' })