ENvalidate setup & use instructions

* [General setup](#general-setup) * [Enable an organisation to access our code](#1--enable-an-organisation-to-access-our-code) * [Embed the code in pages template](#2--embed-the-code-in-pages-template) * [Accessibility improvements](#3--accessibility-improvements) * [Set up validators](#4--set-up-validators) * [Form setup](#form-setup) * [Adding a validator to a form field](#adding-a-validator-to-a-form-field) * [Error message positioning and scrolling](#error-message-positioning-and-scrolling) * [Calling another script when ENvalidate is set up](#calling-another-script-when-envalidate-is-set-up) * [Disabling ENvalidate on a particular page](#disabling-envalidate-on-a-particular-page) * [Preventing form submission and calling another function when the form has been validated](#preventing-form-submission-and-calling-another-function-when-the-form-has-been-validated) * [Setting a custom error message for a field](#setting-a-custom-error-message-for-a-field) * [Getting/displaying any field value](#gettingdisplaying-any-field-value) * [Donation amount switching](#donation-amount-switching) * [Phone number or postcode / zip code](#phone-number-or-postcode--zip-code) * [Bank details](#bank-details) * [PCA bank details](#pca-bank-details) * [Credit card details](#credit-card-details) * [Show Stripe payment in progress](#show-stripe-payment-in-progress) * [Dates](#dates) * [Email using Loqate](#email-using-loqate) * [Address using Loqate](#address-using-loqate) * [Image uploads](#image-uploads) * [WhatsApp sharing](#whatsapp-sharing) * [Scrolling thank you page](#scrolling-thank-you-page)

General setup

These are the main overall things you need to do for all organisations:

1. Enable an organisation to access our code

Add their sub-domain as a referrer in the AWS S3 Bucket Policy [here.](https://s3.console.aws.amazon.com/s3/buckets/envalidate/?region=eu-west-2&tab=permissions) NB if they use different sub-domains (e.g. `act.` and `donate.`) both must be included.

2. Embed the code in pages template

Add this script to the bottom of the _footer_ of an Engaging Networks pages template: ```html ```

3. Accessibility improvements

To fix the Engaging Networks accessibility problems listed here, simply add the line of code below _before_ the script tag calling the ENvalidate JS file (the best place to put it is usually in the footer of the template so it applies to all pages, but make sure to test that it works across different pages): * By default, Engaging Networks form inputs don’t have a ‘tab index’ applied and aren’t selectable with the keyboard. For most input this isn’t a problem, but for most styled radio buttons and check boxes it means that screen readers will miss them -- including especially donation amount radio buttons -- and they won’t meet the [W3C accessibility standard](https://www.w3.org/wiki/RadioButton) for how radio buttons should work with the keyboard. We add tabbing and keyboard accessibility to all inputs. * Mandatory form fields don't have aria-required="true" set. We add this for screenreaders. * Form fields that have a validator error don't have aria-invalid="true" set. Error messages don't have role="alert" set. We add these for screenreaders. * There are some accessibility errors with images and inputs on the tweet page of tweet to target actions that aren't labelled / have missing alt text. We fix these. * 'Other' inputs (e.g. other donation amount, other title) are missing a label. We add one for screenreaders. By default this is "[Label for that field] - Other" (e.g. "Choose your donation amount - Other"), but you can also set this text manually for any field -- see below. * Standard form fields like name, email, phone, address, credit card details do not have [autocomplete](https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete) attributes set. We set them. ```html ```

4. Set up validators

Add any validators you need from this list to [Alerts & Validators for Pages](https://ca.engagingnetworks.app/index.html#validators) in Engaging Networks:
Type Name Message to Supporter \ (though this can be different if desired) Expression
Anywhere
Custom Email validated with Loqate Please check your email address ^(\S+@\S+\.\S+)(?=|---email-loqate___)$
Custom International postal code Please check your postal code ^([\s\S]+)(?=|---post-code-international___)$
Custom International phone number (mandatory) Please check your phone number ^([0-9]{7,20})(?=|---phone-number-international___)$
Custom International phone number (optional) Please check your phone number ^(?:\d{7,20}|)(?=|---phone-number-international-optional___)$
Custom Address Loqate lookup - autocomplete (mandatory) Please check your address ^([\s\S]+)(?=|---address-loqate___)$
Custom Address Loqate lookup - autocomplete (optional) Please check your address ^([\s\S]*)(?=|---address-loqate___)$
Custom Country Please select your country ^([\s\S]+)(?=|---country___)$
Custom Credit Card Holder Name Please add your name as it appears on your card ^([\s\S]+)(?=|---credit-card-holder___)$
Custom Credit Card Number Please check your card number ^([0-9]{8,19}|)(?=|---credit-card-number___-_-_cardType:Sorry, we don’t support this type of card_-_-)(?=|8,28__-__)$
Custom Credit Card Verification Value Please check your card verification number (CVV) ^([0-9]{3,4}|)(?=|---credit-card-cvv___)$
Custom Credit Card Expiry Date (split select) Please check your card expiry date ^((0[1-9])|(1[0-2])|(20[1-3][0-9]))(?=|---credit-card-expiry___)$
Custom Credit Card Expiry Date (split text - 2 digit years) Please check your card expiry date ^((0[1-9])|(1[0-2])|([1-3][0-9]))(?=|---credit-card-expiry___)(?=|2,2__-__)$
Custom Payment Type Please choose a payment type ^([\s\S]*)(?=|---payment-type___)$
Custom (not Date)
Date Custom Validator Please choose a valid date YYYY-MM-DD format:

^([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))(?=|---date-yyyy-mm-dd___)(?=|10,10__-__)$

Notes on dates:

Haven't been able to get EN's built-in validator types 'Date' or 'Required Date' to work when testing, at least not with a calendar form input which is the most likely combination.

There are problems with using EN's Calendar input type which uses - the primary issue being that the date is returned in different formats in different locales (e.g. US vs UK). We should do some real world testing of the best way to fix this with the first organisation who needs it -- it may be best to use something like JQuery Date Picker, though our validation may need updating.

Have only got calendar fields with date validation to work using this YYY-MM-DD format, because at least in Chrome it stores the date in the field in this format

UK
Custom PCA Bank Account (UK) Please check your bank details ^[0-9]{8,8}(?=|---pca-bank-account-uk___)$
Custom PCA Bank Sort Code (UK) (triple text field) Please check your bank details ^[0-9]{2,2}(?=|---pca-bank-sort-code-uk___)(?=|2,2__-__)$
Custom PCA Bank Sort Code (UK) (single text field) Please check your bank details ^[0-9]{6,6}(?=|---pca-bank-sort-code-uk___)$
Custom PCA Bank Name (UK) Please check your bank details ^([\s\S]*)(?=|---pca-bank-name-uk___)$
Custom Bank Account Please check your bank details ^[0-9]{8,8}(?=|---bank-account-uk___)$
Custom Bank Sort Code (UK) (triple text field) Please check your bank details ^[0-9]{2,2}(?=|---bank-sort-code-uk___)(?=|2,2__-__)$
Custom Bank Sort Code (UK) (single text field) Please check your bank details ^[0-9]{6,6}(?=|---bank-sort-code-uk___)$
Custom Postcode (UK) Please check your postcode ^[A-Z,a-z]{1,2}\d[A-Z,a-z\d]?\s*\d[A-Z,a-z]{2}(?=|---post-code-uk___)(?=|6,8__-__)$

adapted from https://github.com/ideal-postcodes/postcode.js/blob/master/index.js

Custom Phone number (UK) (mandatory) Please check your phone number Allowing normal UK number (digits only):

^[0-9]{10,11}(?=|---phone-number-uk___)$

Allowing normal UK number (digits only) or optional +44 at beginning:

^(((\+44)? ?(\(0\))? ?)|(0))( ?[0-9]{3,4}){3}(?=|---phone-number-uk___`+)(?=|13,15__-__)$

Latter taken from http://regexlib.com/REDetails.aspx?regexp_id=1430

Custom Phone number (UK) (optional) Please check your phone number Allowing normal UK number (digits only):

^(?:\d{10,11}|)(?=|---phone-number-uk___)$

Allowing normal UK number (digits only) or optional + symbol at beginning and country code:

^(?:\+?\d{10,13}|)(?=|---phone-number-uk___`+)(?=|13,15__-__)$

Custom NHS number (UK) Please check your number ^[0-9]{10,10}(?=|---nhs-number-uk___)$
North America

Note: Most online forms seem to ask for the first 5-digit part only. But zip codes can also have a second, 4-digit part. The first time we try this with a US-based org we should ask whether they want to allow this too, not sure what's normal practice in North America.

Custom Zip code (US) Please check your zip code Main 5 digit code:

^[0-9]{5,5}(?=|---post-code-us___)$

Main 5 digit code or 5+4 format with a dash in-between:

^[0-9]{5}(?:-[0-9]{4})?(?=|---post-code-us___)$

Custom Phone number (US/Canada) Please check your phone number ^([0-9]( |-)?)?(\(?[0-9]{3}\)?|[0-9]{3})( |-)?([0-9]{3}( |-)?[0-9]{4}|[0-9]{7})(?=|---phone-number-us-ca___`-`(`)` )$

Form setup

Adding a validator to a form field

To get validation working on a particular form, assign a validator when editing the Form Block in a page. You need to specifically assign one for: * Email * Phone number * Postcode/zip code * Bank account (normal or PCA) * Bank sort code (normal or PCA) * Bank name (hidden field, optional - for PCA only) * Credit card number * Credit card validation number * Credit card expiry date * Payment type (radio or hidden field) Other fields (e.g. text, radio buttons, dropdowns) are automatically validated if they are set to ‘Mandatory’. All EN field types are supported. For certain kinds of validation you also need to do / bear in mind some particular things:

Error message positioning and scrolling

* By default, error messages appear before (above) fields. But if you want, you can (optionally) set error messages to appear after (below) fields - add this just _before_ the script tag calling the ENvalidate JS file: ```html ``` * When the user tries to submit the form, if there are errors then ENvalidate scrolls the user back up to the first error. But there are times when you may want to scroll them a little higher (or lower) - e.g. because there is a header overlay which would otherwise be hiding the error message. \ \ Set this value in pixels in the template or in a code block anywhere on the page -- a positive number e.g. `100` scrolls the user higher up, a negative number e.g. `-100` scrolls them further down. If necessary, you can also use the built-in function `isMobile()` to do a basic check of the user’s screen size or you can use JQuery’s `$(window).width()` ```html ``` * Engaging Networks displays certain error messages in an unhelpful place at the top of the page. You can move these to another place on the page by following these steps. **Be careful: make sure you choose a new location for error messages that exists on every page of every action that uses the template you're editing. Normally these error messages only appear on payment pages (e.g. if a card payment fails), but in theory they could appear on any page (except probably not thank you pages).** * Add this style to your page template (or you could put it in a code block, but using the template is more reliable) -- this hides the top-of-page error messages initially, until ENvalidate can move them to where you want them: ```html ``` * Add this JavaScript code to your page template to tell ENvalidate where you want those top-of-page error messages to appear -- they will appear before or after the element you point to with the `selector` below: ```html ```

Calling another script when ENvalidate is set up

* Sometimes there are custom things you want to do on the Engaging Networks form (e.g. add a custom event listener or modify a field). But you only want to do it after ENvalidate has finished loading and setting up, because ENvalidate makes a copy of the entire form and destroys the original (so that we’re not tied into Engaging Networks’ built-in validation), so if you alter the form in some custom way before ENvalidate has finished setting up then your change may not be copied over -- especially if it’s an event listener. \ * To do something when ENvalidate has finished setup, add this code into a code block on the page, renaming `myFunction` to whatever you want. You can have one or multiple code blocks like this on the page: ```html ``` _Deprecated:_ _To do something when ENvalidate has finished setup, just create a normal Javascript function which must be called `onENValidateSetupComplete `in a code block on the page - like this:_ ``` ``` * There is also a variable called `window.enValidateSetupComplete `that you can check to see if it’s `typeof undefined` (ENvalidate hasn’t started running yet), `false` (ENvalidate has started running but hasn’t finished setup) or `true` (ENvalidate has finished setup).

Disabling ENvalidate on a particular page

* It is very rare you’ll need to use this -- there is usually a better approach -- but just in case needed, you can disable ENvalidate entirely on a particular page where it’s included by adding this code before the ENvalidate script file is called: ```html ```

Preventing form submission and calling another function when the form has been validated

* Sometimes you might want to handle form submission yourself e.g. if you are submitting the data to an API rather than submitting the page and moving to the next one. * To prevent the page submitting after validation is complete: ```html ``` * To do something else when ENvalidate has finished validating the form and is ready to submit, add this code into a code block on the page, renaming `myFunction` to whatever you want: ```html ```

Setting a custom error message for a field

* You should usually change the validation error message for a field by editing the validator in ‘Components’. However, sometimes you want to alter the error message as a one-off. \ * To do that, use the [Calling another script when ENvalidate is set up](#calling-another-script-when-envalidate-is-set-up) functionality described above to call `changeFieldErrorMessage` when ENvalidate is loaded and ready. You can have one or multiple code blocks like this on the page. You can change the function name `changeFirstNameErrorMessage` to whatever you want. ```html ``` The above example is how you will mostly use this. However, you can also use it by identifying the field based on its ‘special validator’ (certain fields have special validators e.g. credit card number). To see all the special validators, go to an EN page where ENvalidate is loaded, go to the browser console, type in `specialValidators` and hit enter. Use the value in quotes for the field you want. You can change the function name `changeCreditCardNumberErrorMessage` to whatever you want. ```html ```

Getting/displaying any field value

* Engaging Networks lets you insert some user/transaction data into a text block, but it doesn’t give you access to all fields, and it doesn’t let you do it until after the user has entered their email address. This can be limiting. * ENvalidate stores the value of every field entered, but only for as long as the user has that tab open and other sites outside of Engaging Networks can’t access the data. The only exceptions are sensitive payment fields (credit card number, expiry date, CVV, bank account number, sort code) -- if an organisation allowed malicious Javascript code onto their Engaging Networks pages there’s a small risk that data could be grabbed, so these fields aren’t stored. * To show a field’s value within a text block, if the user used that field on a _previous page_ (i.e. it’s already stored before the page loads), simply add some code like this inside the text block’s HTML source code. \ \ Change `supporter.firstName` to the name of the form field you want (if you’re not sure what this is, inspect the form field in your browser, then see what the `name=""` shows e.g. `name="supporter.firstName"`). ```html Hello {ENvalidate_form_data~supporter.firstName} ``` Note: - Make sure you don’t don’t delete the `~` - Make sure you don’t have any spaces anywhere inside the curly brackets `{}` - You must have the class `envalidate-form-data` but you can also add any other classes or an id - It doesn’t have to be a `` but it would most often be if you’re using it in a sentence * Like when you insert a field value in a text block the built-in Engaging Networks way, you can optionally have a fallback value if the field hasn’t been set or is blank, like this. Change `supporter.firstName` to the field name. Change `there` to what you want to show as the fallback. \ ```html Hello {ENvalidate_form_data~supporter.firstName~there} ``` * While the page is loading, the user will briefly see the code above before ENvalidate sets it to the right value. That’s a bit ugly, so good practice is to hide this text until they’re set. Add this to the stylesheet or template for the organisation -- ENvalidate will automatically make the text visible again once it’s set it. ```html ``` * If you want to do something more complicated in Javascript, or you want to retrieve the value and use it in Javascript rather than simply displaying it in a text block, you can use ENvalidate’s `getStoredFieldValue` function, e.g. `getStoredFieldValue('supporter.firstName') `You might also find this useful for example if you want to display the value of a dropdown or a checkbox where the stored value is not in a human-friendly readable format (e.g. country gets saved as ‘GB’ rather than ‘United Kingdom’ and you need to convert it back to display it).` \ \ Remember that this code won’t work until ENvalidate is loaded, so use it in conjunction with the [Calling another script when ENvalidate is set up](#calling-another-script-when-envalidate-is-set-up) instructions above, e.g. ```html ```

Donation amount switching

* This relies on: * the frequency choice (one-off, monthly, etc) being a radio button * the amount choice being a radio with input (i.e. radio + 'Other' option) * Setting up a donation form so that the donation amounts change based on what donation frequency (single, monthly, etc) the user chooses: ```html ``` * In PageBuilder, in the form you should also set the donation amount field’s values to be the same as for the first frequency that appears e.g. £25, £35 and £50 for single

Phone number or postcode / zip code

* If your form will only be accepting postcodes or phone numbers from **only one country,** you can use a country-specific validator if you want e.g. Postcode (UK) * However, if your form will be accepting postcodes or phone numbers from **more than one country,** you should: * Use the International phone number or International post code validator -- this does specific validation for a country’s specific format of postcode / phone number where it can, falling back gracefully to just check that something has been entered for other countries. * And you must also have a Country field on the same page of the form (which must have two-letter ISO country codes as its values e.g. `us`) and this must have the Country validator added to it. This tells ENvalidate which country to validate for.

Bank details

* The same (PCA or non-PCA) validators must be assigned to bank account and sort code fields

PCA bank details

* You must also add the PCA Bank Name validator to this hidden field if it is being used * Add the PCA Bank Details key in the footer, just _before_ the script tag calling the ENvalidate JS file: ```html ```

Credit card details

* If you are using credit card validation, you must also apply the Payment type validator to the payment type field * Add the JQuery Credit Card validator script tag _after_ the script tag calling the ENvalidate JS file: \ `` * Add the **payment processor** and **accepted card types** for the organisation in the footer, just _before_ the script tag calling the ENvalidate JS file: ```html ``` where the card types must only be ones from the above list (which comes from [JQuery Credit Card Validator](http://jquerycreditcardvalidator.com/)) (note: card types the payment processor accepts are stored in our JS library) and the payment processor `xxxxxxxxx` must be one of the following payment processors (exact spelling and case-sensitive): - worldpay - rsm2000 - paypal-canada - paypal-uk - paypal-us - iats - vantiv - ip-payments - stripe - paysafe * Note: on the form, if you don’t need the user to choose the payment type, include this as a _text_ input with default value `card` and add some CSS to hide the input and its container div e.g. ```html ```

Show Stripe payment in progress

It can take a few seconds (sometimes more) for Stripe payments to go through when the user clicks the submit button on a payment page of a donation action. To make it clear to the user that something is happening, we can grey out the button and show a loading spinner on the submit button (or any other styling you want to add). We cannot disable the button using Javascript, because this appears to conflict with Stripe's or Engaging Networks' built-in functionality. The only thing you need to do is add some CSS as a code block on the payment page or as part of the HTML template -- this will need to vary by organisation, but here's an example below, you can adapt the exact styling. While you're trying out what styling to use, you can run the command `showSubmitInProgress(true)` in your browser console on a payment page, to see how the button would look in its loading state. If Stripe is set to test mode, you can also test it with card payments using [test card numbers](https://stripe.com/docs/testing) (as part of this, see the card numbers for errors e.g. declined payments if you want to check how that works). ```html ```

Dates

* Add the Moment script tag _after_ the script tag calling the ENvalidate JS file: ```html ```

Email using Loqate

* Set up an Email Verification service on the organisation's Loqate account. Copy the key for this service. * In the page template just _before_ the script tag calling the ENvalidate JS file, add a line like this - replacing the string with the actual key from the previous step: ```html ``` * Make sure you have the *Email validated with Loqate* validator set up on the organisation's account * Add the *Email validated with Loqate* validator to the email address field

Address using Loqate

Loqate method 1 - Autocomplete

* Add the Loqate address validator. You _only_ need to add the Loqate address validator to the _first address input_ -- the one the user will start typing into (you don’t need to add a validator to other address fields). \ \ ENvalidate will then automatically show the other address fields when an address has been entered (assuming Loqate has been set up correctly to include all the address fields on the page). * It’s good practice to also add CSS in a code block to hide the other address fields (they are hidden anyway by ENvalidate JavaScript, but this will only happen after the page has fully loaded, so the other address fields could be temporarily shown then hidden if you don’t add this CSS) -- for example: ```html ``` Make sure to reference the divs that contain all the inputs, labels, etc -- not the inputs themselves. * If you are using a separate field for the lookup (rather than address line 1 to do this), you may want to use the validator 'Address Loqate (optional)' in case the user has entered their address manually and the lookup field is empty. * By default, the link in the first address input to enter your address manually is “Enter manually”. If you want to change that text to something else, you can do that by adding this script the footer, just _before_ the script tag calling the ENvalidate JS file: ```html ```

Method 2 - Search and choose from a dropdown

* No validators are needed. * Remove the Loqate (PCA) script from the page template if it's already included - so it doesn't conflict. * Set up two new questions, if these don't exist already on the organisation's account: Text Name: Postcode or first line of your address Label: Postcode or first line of your address [or you can change this label if you want] Mandatory: yes Select Name: Address results Label: Select your address from the list below: [or you can change this label if you want] Mandatory: no * On the address form, make Country the first address field, the values of this field must be two-letter country codes e.g. 'GB'. (If you only want to allow UK addresses, you can make Country a hidden field with the value 'GB'.) * On the address form, next put 'Postcode or first line of your address' * On the address form, next put 'Address results' * On the address form, other address fields e.g. address line 1 etc, follow after this * Add CSS in a code block to hide the normal address fields -- for example: ```html ``` Make sure to reference the divs that contain all the inputs, labels, etc -- not the inputs themselves. * Add CSS in a code block or the template to style the search button -- for example: ```html ``` * Add script in a code block with these essential settings: ``` ``` * By default, the link to enter your address manually is “Enter manually”. If you want to change that text to something else, you can do that by adding this script as a code block or in the footer, just _before_ the script tag calling the ENvalidate JS file: ```html ```

Image uploads

* You can create an image upload question/field fairly easily. The image URL(s) will be stored as the value of the question/field. (Current limitations: only works for optional question/field not required, can only have one of these questions/fields on each page of an action, all files go into the same folder in Engaging Networks unless you set up separate upload presets pointing to different folders for different EN actions.) * First, set up a [Cloudinary](https://cloudinary.com/) account (you must have one). Create an unsigned Cloudinary preset: go to [upload settings](https://cloudinary.com/console/settings/upload), scroll down to 'Upload presets', add a new preset: * Give it a name e.g. `engaging-networks` * Signing mode: set it to **Unsigned** * Folder: add a folder name e.g. `engaging-networks` * You can leave other settings as you find them * Then in your Engaging Networks page: * In the template, in the `` of the page, insert this ` ``` * If it doesn't exist already, create the question or field you want to use for the image upload. Make this a **hidden** question/field and keep it **optional** not required. * Insert the hidden question/field into a form block like you normally would. * Insert a text block into the page where you want the image upload button to appear. The HTML structure must be exactly as below (except you can remove the `
...
` if you want). Feel free to change the text as needed - you may want to tell the user if they can upload multiple files and/or what size files are allowed and/or what file types. ```html
Upload photo(s)
Files max 2Mb each
 
``` * Add a code block with the script and styles below. * In the ` ```

WhatsApp sharing

* You can add a WhatsApp sharing button to the built-in EN share buttons. * First, set up and add into the page the normal EN share buttons. * Next, create a code block on the same page where the share buttons appear, setting the text and link (if any) that you want to include: ```html ``` * Lastly, you also need to add styles on the page or in the organisation’s style sheet, otherwise the WhatsApp button will be invisible. Here are styles you could use, depending on which kind of share buttons you’re using. Simple: ```html ``` Small: ```html ``` Large: ```html ```

Scrolling thank you page

* You can easily add a series of scrolling screens to thank you pages (or another page) * **Add this script as a code block on the page.** The key thing to get right from the beginning is the `startRow` - this is the first row on the page that contains one of your scrolling screens, it might be `1` if that's the first row on the page, but if e.g. you have a first row with only code blocks in then it might be `2`: ```html ``` * **Now, set up the different screens, one in each row.** You can easily add buttons or links that nove the user to different rows: * For buttons that don't do anything else, use a `
`. If you need to use a link (e.g. to a donation page) that also advances the user to another row, you can do that - just make sure to use `target="_blank"` so that the link opens in a new window. * Add a data attribute to **move the user forward one or more rows** when they click on it, e.g. `
Yes
` * (Optional) You can also add a data attribute to **say that a specific row has been completed** - this will update the progress bar. The row number is based on the row you marked as the `startRow` being the first row (so the start row becomes `1`, the row after would always be `2` for instance). For example, if a donate link is clicked you probably want to say that the donate stage is complete `£5` * (Optional) You can also add a data attribute to **say that a specific row has been skipped** - this will also update the progress bar. The row number is based on the row you marked as the `startRow` being the first row (so the start row becomes `1`, the row after would always be `2` for instance). For example, to add a skip button to skip your third row of content `
Skip
` * Share buttons are automatically set so that they move the user forward one row and they mark the row they are on as complete. * **You will also need to set up styles** in a code block or the template to style at least the rows and the progress bar (possibly also buttons if these aren't already styled well). Here is some example code you can work from (make sure to change at least the references to the images as these are on Hope Not Hate's account so might move later): ```html ```