To make certain that you&';re up-to-date with the latest changes to my Expressive Websites Javscript Library, and I will send you updates when I make changes.
contact me.
Changes
Version 1.4.0 - Added xf_validate_distinct validation routine to make sure certain fields are distinct.
Version 1.3.3 - Added data-emaillabel so that text input can be formatted as a label in the email.
Version 1.3.2 - Suppressed xf_email_label_before and after, if label is blank or empty.
Version 1.3.1 - Added variables xf_email_label_before and xf_email_label_after.
Version 1.3.0 - Added xf_options_... functions
Version 1.2.0 - Added xf_disabled_toggle(checkbox_element,checked_action_array,affected_array,required_array) and xf_toggle_label_class(add_remove,xf_el,el_class)
Version 1.1.0 - Added xf_add_class_by_attribute(form_element) to add classes, depending on required, etc.
Version 1.0.3 - Email Radio Buttons and Checkboxes now use group label in email (whatever element has same id as button/checkbox name)
Version 1.0.2 - Added xf_form_lock_toggle(form_element)
Version 1.0.1 - Added xf_fields_equal()
Version 1.0.0 - Added contact form, calculator form, and menu form
Contact FormCalculator FormMenu FormLocking / Unlocking a Form
If you want your website to be more expressive - with forms - please use my xf_form.js
javascript library. If you do use xf_form.js, etc., attributions are helpful, links are more helpful, posting articles is most helpful, and donations (link at top of page) are always helpful. (Helpful to me and to others who could benefit from this library. Donations offset my webhosting and usage costs which go up when more people use my code.)
xf_form.js
contains several functions which are explained below. You have two options for using xf_form.js. You can download files to your desktop and upload them to your website, or you can link directly to my code.
Downloading ... Your code is static until you download again. If I change the code, it doesn&';t affect you.
Click on the files below to download them. Then, upload them to your website. Finally, place <script src="yourpath/xf_form.js"></script>
and <link rel="stylesheet" type="text/css" href="yourpath/xf_form.css" /> in the <head>
of your html. yourpath
is where you upload these to on your website.
If you just want to point to my code without downloading and uploading, place https://stubbart.com/computer_consulting/code/
in place of yourpath/
above.
Whether you download or point directly to my code, please so that I can inform you of updates.
Files to Download:
Form function library
Form function styles
xf_form also executes functions in x_press. Make sure you download or point to those files also (the ones which are appropriate). xf_form.js
contains functions for simple forms. These files are quite small and will load fast.
Most contact forms send emails. Mine dumps the information from the form into an email which the user can send. This way, they get to see the email. They also get to see my emailaddress which is hidden, up to that point. And, they can cc themselves, in case they want to keep my email address on hand to contact me later. Some companies don&';t want individual users knowing their email address. I figure, it&';s more repeat business, if they do.
Emails need a to and a subject. The body of the email is extremely helpful. And emails can also have a cc and a bcc. My contact form has all those parts, except bcc. These are all specified in data-emailpart
. Since several form fields end up in the body of the email, those all have data-emailpart="body"
.
The following is a website which only contains an email contact form.
<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="x_press.css" /><link rel="stylesheet" type="text/css" href="xf_form.css" />
<script src="x_press.js"></script><script>x_press_init()</script><script src="xf_form.js"></script><script>xf_form_init()</script>
</head>
<body>
<form id="contactform" class="xf_form_padding xf_border_inset xf_form_border_rounded" style="width:500px" onsubmit="xf_send_email('contactform')">
<input id="to" name="to" type="hidden" data-emailpart="to" value="">
<label for="subject" class="xf_label_align_left">Reason for Connecting</label><input id="subject" name="subject" type="text" data-emailpart="subject" autofocus required maxlength="30"><br>
<label for="name" class="xf_label_align_left">Your Name</label><input id="name" name="name" type="text" data-emailpart="body" required><br>
<fieldset class="xf_fieldset_no_border"><label for="email" class="xf_label_align_left">Your Email</label><input id="email" name="email" type="email" data-emailpart="body" minlength="6"> <label for="cc">Send Yourself a Copy</label> <input id="cc" name="cc" type="checkbox" data-emailpart="cc"></fieldset><br>
<label for="phone" class="xf_label_align_left">Your Phone</label><input id="phone" name="phone" type="tel" data-emailpart="body"><br>
<label for="msg" class="xf_label_align_left">Message</label><textarea id="msg" name="msg" data-emailpart="body" rows="5" cols="43" maxlength="1000"></textarea><br>
<span class="xf_label_align_left"></span><button id="submit" name="submit" type="submit" class="xf_button_rounded" style="background-color:azure">Send Mail</button>
</form></body></html>
To is the first field. It is hidden.
The email address is your emailaddress encrypted using x_code_simple – see that function in the appendix for x_press auxiliary functions. data-process is a semicolon delimited string to decrypt the email address. data process="return;xf_email_code_simple;de;emailaddressencrypted;fromarray_ascommadelimitedstring;toarray_ascommadelimitedstring"
The first part of the string, is return, as the function is returning this information. The second part is the xf_email_code_simple. xf_email_code_simple is not a function. Rather, it’s a pseudo-function. It doesn’t exist. xf_email_code_simple just tells xf_process what to do. The third part of the string is de for decrypt. The fourth is your encrypted emailaddress. The fourth and fifth are the from and to arrays to decrypt as comma delimited strings.
The second field is subject. It is required. Since it is the first field that the user can type in, autofocus is specified. Typically, this would be <select>
, rather than <input>
. <select>
would provide a drop-down list, including Other. Then the user might need to input what they mean by other.
The third field is the User&';s name. It is required. Typically, the name is split into first and last names, so that emails can be sent, addressing the person by their first name. And often, only the first name is required.
Next, comes the user&';s email address. Again, this is required because you want to be able to reply to them, at least once, even if you’re not adding them to your email list. The email address, in this case, is only slightly validated. You can enter a@b and it will pass. To prevent that from happening, I&';ve added minlength="6"
. You can add a pattern as previously discussed in simple validation.
Next, is the phone number. This is optional (not required). However, you can make it required. I&';m less likely to give somebody my phone number, than my emailaddress. Phone numbers are not validated. Any entry or none is valid. You can add minlength="6"
. The phone number, if entered, ends up in the body of the email.
The reason phone numbers are not validated is because international numbers have a variety of formats. Also, some companies use an alpha equivalent of their phone number. But, who can translate alpha phone numbers back to their numeric equivalents in their head? Not I.
You can add a pattern to limit the phone number to digits, or perhaps to digits, commas, and parentheses. You can also say to yourself that you&';re only dealing in real-time with local customers. So, you want to limit the format to something that&';s valid locally (with a pattern).
The last field is the message. It is required. The user has to enter at least two characters (Perhaps they just want to say Hi). They can enter at most 1000 characters.
I&';ve set message up as a textarea so that the user can more easily enter the information. The message ends up in the email body.
When the user clicks the button, onsubmit is performed. In this case, xf_send_email('contactform'). contactform is the id of the form. xf_send_email builds the string mailto:to?cc=useremail&subject=reason&body=phone+msg
. If the user didn&';t specify to send themselves a copy, cc is not part of this string.
location.href
is then set to this string. location.href=string. This statement causes an email to be created, using this information.
The user gets a chance to clean up anything they want. They can also type more information until they&';re blue in the face (or would that be in the fingers?). They can also attach files to the email. Though you should be cautious about opening those attached files. They might contain viruses. Then the user can press send in their email program.
A calculator form, allows you to input information into a formula. The formula is evaluated when the submit button is clicked. And, the results are displayed in a field for output.
xf_form.js provides x=xf_math_eval(eq_array). Pass the equation as an array of numbers and operators. Operators are **, *, /, +, -. Order of evaluation is **, left to right * and /, left to right + and -. xf_math_eval does not handle nesting with () or anything else that is complex. That means, you will need to break the equation into parts and pass each part to xf_math_eval and handle the complex parts and nesting manually. Be sure to pass numbers, rather than strings. '2'+'3'='23'. 2+3=6.
xf_form.js also provides xf_calc(form_element) which calculates the value of the equation on a form.
On the form element, add data-calceqs=n
, where n is the number of equations on the form. In other words, if some equations are nested, those are separate equations. Then for each input field, add data-calceq
to assign it to an equation (data-calceq="2"
). The lowest level equation is 1. Don&';t skip numbers.
Each nested field&';s result must reside somewhere. Also, the final result must reside somewhere. I use hidden input fields for intermediate results, and an output field (not hidden) for the final result. The id of these fields is xf_calc_resultn
where n is the equation that the result goes into.
The following calculation form shows how to set up a form to perform a calculation.
<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="x_press.css" /><link rel="stylesheet" type="text/css" href="xf_form.css" />
<script src="x_press.js"></script><script>x_press_init()</script><script src="xf_form.js"></script><script>xf_form_init()
x_press_extra_fr=['xf_oper_plus','xf_oper_minus','xf_oper_times','xf_oper_by','xf_oper_paren_left','xf_oper_paren_right','xf_oper_equal']
x_press_extra_to=['#x2b','#x2013','#x2217','#x27cb','#x28','#x29','#x3d']
</script></head>
<body>
<form id="calcform" class="xf_form_padding xf_border_inset xf_form_border_rounded" style="width:500px" onsubmit="xf_calc('calcform');event.preventDefault()" data-calceqs="2">
<label for="apples" class="xf_label_align_left">Apples</label><input id="apples" name="apples" type="number" data-calceq="1" autofocus required maxlength="2" min="1" style="width:3em"><input class="xf_calc_op" type="text" readonly data-calceq="1" value="*" placeholder="&xf_oper_times;"><br>
<label for="oranges" class="xf_label_align_left">Oranges</label><input id="oranges" name="oranges" type="number" data-calceq="1" autofocus required maxlength="2" min="1" style="width:3em"><input class="xf_calc_op" type="text" readonly data-calceq="1" value="*" placeholder="&xf_oper_times;"><br>
<label for="bananas" class="xf_label_align_left">Bananas</label><input id="bananas" name="bananas" type="number" data-calceq="1" autofocus required maxlength="2" min="1" style="width:3em"><input class="xf_calc_op" type="text" readonly data-calceq="1" value="*" placeholder="&xf_oper_times;"><br>
<fieldset class="xf_fieldset_no_border"><legend class="xf_legend_align_left">Pears</legend>
<label for="bosq" class="xf_label_align_right">Bosq ( </label><input id="bosq" name="bosq" type="number" data-calceq="2" autofocus required maxlength="2" min="1" style="width:3em"><input class="xf_calc_op" type="text" readonly data-calceq="2" value="+" placeholder="&xf_oper_plus;"><br>
<label for="Bartlett" class="xf_label_align_right">bartlett </label><input id="bartlett" name="bartlett" type="number" data-calceq="2" autofocus required maxlength="2" min="1" style="width:3em"> )<input id="xf_calc_result2" type="hidden" value="" data-calceq="1"><br>
</fieldset>
<span class="xf_label_align_left"></span><button id="submit" name="submit" type="submit" class="xf_button_rounded" style="background-color:azure;margin-top:.1em;margin-bottom:.2em">Calculate</button><indent><button id="reset" name="reset" type="reset" class="xf_button_rounded" style="background-color:azure;margin-top:.1em;margin-bottom:.2em">Clear Form</button><br>
<span class="xf_label_align_right">&xf_oper_equal; </span><output id="xf_calc_result1" style="display:inline-block;width:2.8em;height:1.2em;background-color:azure;border-style:outset"></output>
</form><script>x_press();</script></body></html>
I’ve specified data-calceqs="2" in the form element. The parenthetical expression is enclosed in a fieldset, but that’s not necessary. I just do that so things make logical sense for grouping, since the () do nothing. What makes this sub-equation work is that the values and operator going into the equation all have data-calceq="2"
. The result field goes into equation 1, so it has data-calceq="1"
. It also has id="xf_calc_result2"
. I also don’t want to ever show this sub-result, so I make the type="hidden"
.
onsubmit
, in <form>
executes xf_calc(form_element). Then it submits event.preventDefault(), which prevents the form from automatically resetting / clearing. Technically, that&';s not what the form is doing. But functionally, that&';s what happens. The result is displayed, then the form is cleared, if you didn&';t prevent it. And the form is cleared so quickly, that you&';ll never see the result. So, since the form now doesn&';t automatically clear, I&';ve added a reset button. I gave it the name Clear Form. For the few fields that there are on this example form, that may not have been necessary. Yet, it&';s still a nice touch.
The following menu form has three levels of menu (0,1,2). After the form, xf_menu_close is called to close all, but level 0. The triple-bar menu button toggles level 1. The 1More button opens level 2. The 2Less button closes level 2. Each menu item is a button with an onclick event or an <a href>
link. I&';ve only added the onclick events to expand / collapse the menu. Each menu button has a data-menulevel
attribute which tells us which level the menu is.
xf_open_menu opens a menu. xf_close_menu closes a menu. xf_toggle_menu opens a menu if it is closed. Otherwise, it opens a menu. Each of this functions is passed an array of menus to open / close / toggle.
<!DOCTYPE html><html><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="x_press.css" /><link rel="stylesheet" type="text/css" href="xf_form.css" />
<script src="x_press.js"></script><script>x_press_init()</script><script src="xf_form.js"></script><script>xf_form_init()</script>
</head>
<body>
<form id="menuform" class="xf_form_padding" onsubmit="event.preventDefault()">
<div class="xf_menu_container"><button type="button" style="float:left;background-color:azure" data-menulevel=0>menu_home;Home</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=0>menu_cart;Products</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=0>menu_about;About</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=0>menu_contact;Contact</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=0 onclick="xf_menu_close('menuform',[2]);xf_menu_toggle('menuform',[1])">menu;</button>
</div><div class="xf_menu_container"><button type="button" style="float:left;background-color:azure" data-menulevel=1>1Home</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=1>1Products</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=1>1About</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=1>1Contact</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=1 onclick="xf_menu_open('menuform',[2])">1More</button>
</div><div class="xf_menu_container"><button type="button" style="float:left;background-color:azure" data-menulevel=2>2Home</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=2>2Products</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=2>2About</button>
<button type="button" style="float:left;background-color:azure" data-menulevel=2 onclick="xf_menu_close('menuform',[2])">2Less</button>
</form>
<div style="clear:both"></div>
</div>
<script>xf_menu_close('menuform',[1,2])</script><script>x_press()</script></body></html>
Place an & before each of the menu...;
above. They&';ll change into emoji. x_press has more of these. Refer to that documentation. If your menu code is in Javascript, you&';ll need to replace the & with % for these entities, and call x_press for Javascript.
xf_form_lock_toggle(form_element)
locks or unlocks the fields for input of a form. If the form starts out locked, these fields should have the readonly
attribute. They also need data-lockable=true (whether the form is locked or not).
If you want to automatically style labels and fields depending on whether they&';re required or not, place <script>xf_add_class_by_attribute(formid)</script>
after </form>
. Use or override classes xf_label_required
, xf_label_optional
, xf_label_disabled
, xf_label_readonly
, xf_label_multiple
; and corresponding xf_field_...
classes.
If you have a checkbox that makes other fields disabled or enabled, use xf_disabled_toggle(checkbox_element, checked_action_array, affected_array, required_array)
. checked_action_array
is ['checked', 'disable']
or ['checked', 'enable']
or ['unchecked', 'disable']
or ['unchecked', 'enable']
. affected_array
is an array of the ids of the affected fields. required_array
contains 'required'
or 'optional'
for each affected field. Add onclick to the checkbox element. E.g. onclick="xf_disabled_toggle('frstbook',['checked','enable'],['byline','about','aboutshort','abouturl'], ['required','required','required','optional'])"
xf_disabled_toggle
calls xf_toggle_label_class(add_remove,xf_el,el_class)
to handle the labels.
xf_options_init(parent_element,options_array)
– Initialize <option>
s for <select>
, <optgroup>
, <datalist>
. options_array
is a nested array of text, value, defaultSelected, selected, disabled, hidden attributes for each option.
xf_options_clear(parent_element)
– Clear all options from <select>
, <optgroup>
, <datalist>
.
xf_options_filter(parent_element,options_array,filter_element)
– Filter options, based on filter_element.
xf_options_open(parent_element,options_array,options_number_of_options)
– open <select>
, <optgroup>
, or <datalist>
to number of options.
x=xf_validate_distinct(form_element, group_label, distinct_fields, skip_values)
validates fields to make certain they all have distinct (unique) values. This function returns true
or false
.
form_element
is the element id
group_label
is the label for this group of fields. Actually, group_label
is only used in the message that appears when the fields are not distinct. So, you can place all the labels or whatever is meaningful here.
distinct_fields
is an array of the ids of the fields to validate
skip_values
is an array of values to not check, like '0'
, ' '
, etc.