From 5ff6d0b0147d757df3811611e4a583ca4baeec68 Mon Sep 17 00:00:00 2001 From: Raphael Michel Date: Mon, 15 May 2017 11:33:18 +0200 Subject: [PATCH] Auto-detect common typos in email addresses --- src/pretix/presale/forms/checkout.py | 8 +- .../presale/templates/pretixpresale/base.html | 1 + .../event/checkout_questions.html | 6 ++ .../static/pretixpresale/js/ui/typocheck.js | 79 +++++++++++++++++++ .../static/pretixpresale/scss/main.scss | 5 ++ 5 files changed, 97 insertions(+), 2 deletions(-) create mode 100644 src/pretix/static/pretixpresale/js/ui/typocheck.js diff --git a/src/pretix/presale/forms/checkout.py b/src/pretix/presale/forms/checkout.py index b846f451b..0d5a3f52a 100644 --- a/src/pretix/presale/forms/checkout.py +++ b/src/pretix/presale/forms/checkout.py @@ -20,7 +20,8 @@ class ContactForm(forms.Form): email = forms.EmailField(label=_('E-mail'), help_text=_('Make sure to enter a valid email address. We will send you an order ' 'confirmation including a link that you need in case you want to make ' - 'modifications to your order or download your ticket later.')) + 'modifications to your order or download your ticket later.'), + widget=forms.EmailInput(attrs={'data-typocheck-target': '1'})) class InvoiceAddressForm(forms.ModelForm): @@ -30,6 +31,8 @@ class InvoiceAddressForm(forms.ModelForm): fields = ('company', 'name', 'street', 'zipcode', 'city', 'country', 'vat_id') widgets = { 'street': forms.Textarea(attrs={'rows': 2, 'placeholder': _('Street and Number')}), + 'company': forms.TextInput(attrs={'data-typocheck-source': '1'}), + 'name': forms.TextInput(attrs={'data-typocheck-source': '1'}), } def __init__(self, *args, **kwargs): @@ -76,7 +79,8 @@ class QuestionsForm(forms.Form): self.fields['attendee_name'] = forms.CharField( max_length=255, required=event.settings.attendee_names_required, label=_('Attendee name'), - initial=(cartpos.attendee_name if cartpos else orderpos.attendee_name) + initial=(cartpos.attendee_name if cartpos else orderpos.attendee_name), + widget=forms.TextInput(attrs={'data-typocheck-source': '1'}), ) if item.admission and event.settings.attendee_emails_asked: self.fields['attendee_email'] = forms.EmailField( diff --git a/src/pretix/presale/templates/pretixpresale/base.html b/src/pretix/presale/templates/pretixpresale/base.html index bf8746d98..43f914070 100644 --- a/src/pretix/presale/templates/pretixpresale/base.html +++ b/src/pretix/presale/templates/pretixpresale/base.html @@ -27,6 +27,7 @@ + {% endcompress %} diff --git a/src/pretix/presale/templates/pretixpresale/event/checkout_questions.html b/src/pretix/presale/templates/pretixpresale/event/checkout_questions.html index ee6b26939..da509576b 100644 --- a/src/pretix/presale/templates/pretixpresale/event/checkout_questions.html +++ b/src/pretix/presale/templates/pretixpresale/event/checkout_questions.html @@ -74,6 +74,12 @@ {% endfor %} +
+ {% trans "Are you sure your email address is correct?" %}
+ {% blocktrans trimmed with entered="" suggestion="" %} + You entered "{{ entered }}". Did you mean "{{ suggestion }}"? + {% endblocktrans %} +
0) { + patterns.push(regexEscape(word.slice(0, j)) + '.' + regexEscape(word.slice(j))); + } + if (j > 0 || word.slice(0, 1) !== '@') { + patterns.push(regexEscape(word.slice(0, j)) + '.' + regexEscape(word.slice(j + 1))); + patterns.push(regexEscape(word.slice(0, j)) + regexEscape(word.slice(j + 1, j + 2)) + regexEscape(word.slice(j, j + 1)) + regexEscape(word.slice(j + 2))); + } + patterns.push(regexEscape(word.slice(0, j)) + regexEscape(word.slice(j + 1))); + } + + // Remove conflicting patterns (i.e. gmail.com shouldn't correct email.com) + for (j = patterns.length - 1; j >= 0; j--) { + r = new RegExp(patterns[j]); + for (k = 0; k < words.length; k++) { + if (k === i) { + continue; + } + if (words[k] === '@mail.com') { + console.log(words[k], r, words[k].match(r)); + } + if (words[k].match(r)) { + patterns.splice(j, 1); + } + } + } + val = val.replace(new RegExp('(' + patterns.join('|') + ')', 'i'), word); + } + val = val.replace(/gmail\.(?!com$)[a-z]*$/i, 'gmail.com'); + + var changed = (val.toLowerCase() != orig_val.toLowerCase()); + $(".typo-alert").toggle(changed).find("[data-typosuggest]").text(val); + $(".typo-alert").find("[data-typodisplay]").text(orig_val); +} + +$(document).ready(function () { + if ($("input[data-typocheck-target]").length === 0) { + return; + } + + $('body').on('change', 'input[data-typocheck-target], input[data-typocheck-source]', function () { + typocheck(); + }); + $(".typo-alert span[data-typosuggest]").click(function () { + $("input[data-typocheck-target]").val($(this).text()); + $(".typo-alert").slideUp(); + }) + typocheck(); +}); diff --git a/src/pretix/static/pretixpresale/scss/main.scss b/src/pretix/static/pretixpresale/scss/main.scss index a12aac674..d01dce156 100644 --- a/src/pretix/static/pretixpresale/scss/main.scss +++ b/src/pretix/static/pretixpresale/scss/main.scss @@ -116,6 +116,11 @@ body.loading .container { -webkit-transition: opacity .5s ease-in-out; } +.typo-alert span[data-typosuggest] { + text-decoration: underline; + cursor: pointer; +} + .info-row { & > .fa { font-size: 26px;