Contact Form Clean and Simple - Version 4.7.2

Version Description

  • Updated santization and escaping to current plugin directory recommendations
  • add email header to specify text to improve formatting
  • tested up to 5.8 beta 2 and PHP 8.0
Download this release

Release Info

Developer fullworks
Plugin Icon wp plugin Contact Form Clean and Simple
Version 4.7.2
Comparing to
See all releases

Code changes from version 4.7.1 to 4.7.2

ajax.php CHANGED
@@ -1,19 +1,21 @@
1
- <?php
2
- add_action("wp_ajax_cscf-submitform", "cscfsubmitform");
3
- add_action("wp_ajax_nopriv_cscf-submitform", "cscfsubmitform");
4
 
5
  //http://wp.smashingmagazine.com/2011/10/18/how-to-use-ajax-in-wordpress/
6
  function cscfsubmitform() {
7
-
8
- $contact = new cscf_Contact;
9
- $result['sent'] = false;
10
-
11
- $result['valid'] = $contact->IsValid();
12
- $result['errorlist'] = $contact->Errors;
13
-
14
- if ($result['valid']) $result['sent'] = $contact->SendMail();
15
-
16
- header('Content-type: application/json');
17
- echo json_encode($result);
18
- die();
 
 
19
  }
1
+ <?php
2
+ add_action( "wp_ajax_cscf-submitform", "cscfsubmitform" );
3
+ add_action( "wp_ajax_nopriv_cscf-submitform", "cscfsubmitform" );
4
 
5
  //http://wp.smashingmagazine.com/2011/10/18/how-to-use-ajax-in-wordpress/
6
  function cscfsubmitform() {
7
+
8
+ $contact = new cscf_Contact;
9
+ $result['sent'] = false;
10
+
11
+ $result['valid'] = $contact->IsValid();
12
+ $result['errorlist'] = $contact->Errors;
13
+
14
+ if ( $result['valid'] ) {
15
+ $result['sent'] = $contact->SendMail();
16
+ }
17
+
18
+ header( 'Content-type: application/json' );
19
+
20
+ wp_send_json( $result );
21
  }
class.cscf.php CHANGED
@@ -2,11 +2,11 @@
2
 
3
  class cscf
4
  {
5
- public
6
- function __construct()
7
  {
8
  //add settings link to plugins page
9
- add_filter("plugin_action_links", array(
10
  $this,
11
  'SettingsLink'
12
  ) , 10, 2);
@@ -19,79 +19,76 @@ class cscf
19
  $this,
20
  'RegisterScripts'
21
  ));
22
-
23
  add_action('admin_enqueue_scripts', array(
24
  $this,
25
  'RegisterAdminScripts'
26
- ));
27
-
28
  add_action('plugins_loaded', array(
29
  $this,
30
  'RegisterTextDomain'
31
  ));
32
 
33
  add_filter('cscf_spamfilter',array($this,'SpamFilter'));
34
-
35
  //create the settings page
36
  $settings = new cscf_settings();
37
-
38
  }
39
-
40
  //load text domain
41
  function RegisterTextDomain()
42
- {
43
  //$path = CSCF_PLUGIN_DIR . '/languages';
44
  $path = '/' . CSCF_PLUGIN_NAME . '/languages';
45
  load_plugin_textdomain('clean-and-simple-contact-form-by-meg-nicholas', false, $path );
46
  }
47
-
48
- function RegisterScripts()
49
  {
50
  wp_register_script('jquery-validate', CSCF_PLUGIN_URL . '/js/jquery.validate.min.js', array(
51
  'jquery'
52
- ) , '1.11.0', true);
53
-
54
- wp_register_script( 'cscf-validate', CSCF_PLUGIN_URL . "/js/jquery.validate.contact.form.js",
55
- 'jquery',
56
  CSCF_VERSION_NUM, true );
57
-
58
- wp_localize_script( 'cscf-validate', 'cscfvars',
59
  array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
60
 
61
- wp_register_style('cscf-bootstrap', CSCF_PLUGIN_URL . '/css/bootstrap-forms.min.css',
62
  null, CSCF_VERSION_NUM);
63
 
64
- // wp_register_script( 'csf-recaptcha2',
65
- // 'https://www.google.com/recaptcha/api.js?onload=onLoadRecaptcha2&render=explicit&hl=' . get_locale(), null, null, true );
66
-
67
  wp_register_script( 'csf-recaptcha2',
68
  'https://www.google.com/recaptcha/api.js?hl=' . get_locale(), null, null, true );
69
 
70
  }
71
-
72
  function RegisterAdminScripts($hook)
73
  {
74
  if ( $hook != 'settings_page_contact-form-settings')
75
  return;
76
-
77
- wp_register_script('cscf-admin-settings', CSCF_PLUGIN_URL . '/js/jquery.admin.settings.js',
78
  array(
79
  'jquery-ui-sortable',
80
- ) , CSCF_VERSION_NUM, false );
81
-
82
  wp_enqueue_script('cscf-admin-settings');
83
  }
84
-
85
- function Upgrade($oldVersion)
86
  {
87
-
88
  //turn on the confirm-email option
89
  if ( $oldVersion <= "4.2.3" ) {
90
  $options = get_option(CSCF_OPTIONS_KEY);
91
  $options['confirm-email'] = true;
92
  update_option(CSCF_OPTIONS_KEY, $options);
93
  }
94
-
95
  //change namespace of options
96
  if ( get_option('cff_options') != '') {
97
  update_option('cscf_options', get_option('cff_options'));
@@ -100,37 +97,37 @@ class cscf
100
  if ( get_option('cff_version') != '') {
101
  update_option('cscf_version', get_option('cff_version'));
102
  delete_option('cff_version');
103
- }
104
-
105
  $options = get_option('cscf_options');
106
  $updated = false;
107
-
108
- if (trim(get_option('recaptcha_public_key')) <> '')
109
  {
110
  $options['recaptcha_public_key'] = get_option('recaptcha_public_key');
111
  delete_option('recaptcha_public_key');
112
  $updated = true;
113
  }
114
-
115
- if (trim(get_option('recaptcha_private_key')) <> '')
116
  {
117
  $options['recaptcha_private_key'] = get_option('recaptcha_private_key');
118
  delete_option('recaptcha_private_key');
119
  $updated = true;
120
  }
121
-
122
  if ($updated) update_option('cscf_options', $options);
123
-
124
  //delete old array key array_key
125
  if (get_option('array_key') != FALSE) {
126
  $options = get_option('array_key');
127
-
128
  //check it was this plugin that created it by checking for a few values
129
  if (isset($options['sent_message_heading']) && isset($options['sent_message_body'])) {
130
  delete_option('array_key');
131
  }
132
  }
133
-
134
  //upgrade to 4.2.3 recipient_email becomes recipient_emails (array) for multiple recipients
135
  $options = get_option(CSCF_OPTIONS_KEY);
136
  if ( isset($options['recipient_email']) ) {
@@ -138,43 +135,43 @@ class cscf
138
  $options['recipient_emails'][] = $options['recipient_email'];
139
  update_option(CSCF_OPTIONS_KEY,$options);
140
  }
141
-
142
  }
143
 
144
  /*
145
  * Add the settings link to the plugin page
146
  */
147
-
148
- function SettingsLink($links, $file)
149
  {
150
-
151
- if ($file == CSCF_PLUGIN_NAME . '/' . CSCF_PLUGIN_NAME . '.php')
152
  {
153
 
154
  /*
155
  * Insert the link at the beginning
156
  */
157
- $in = '<a href="options-general.php?page=contact-form-settings">' . __('Settings', 'clean-and-simple-contact-form-by-meg-nicholas') . '</a>';
158
  array_unshift($links, $in);
159
 
160
  /*
161
  * Insert at the end
162
  */
163
 
164
- // $links[] = '<a href="options-general.php?page=contact-form-settings">'.__('Settings','contact-form').'</a>';
165
-
166
  }
167
-
168
  return $links;
169
  }
170
- static
171
- function Log($message)
172
  {
173
-
174
- if (WP_DEBUG === true)
175
  {
176
-
177
- if (is_array($message) || is_object($message))
178
  {
179
  error_log(print_r($message, true));
180
  }
@@ -184,14 +181,13 @@ class cscf
184
  }
185
  }
186
  }
187
-
188
  /*
189
  *This is all we need to do to weed out the spam.
190
  *If akismet plugin is enabled then it will be hooked into these filters.
191
  */
192
- public
193
- function SpamFilter($contact) {
194
-
195
  $commentData = apply_filters('preprocess_comment', array(
196
  'comment_post_ID' => $contact->PostID,
197
  'comment_author' => $contact->Name,
@@ -212,6 +208,6 @@ class cscf
212
  $contact->IsSpam = false;
213
  }
214
  return $contact;
215
- }
216
  }
217
 
2
 
3
  class cscf
4
  {
5
+ public
6
+ function __construct()
7
  {
8
  //add settings link to plugins page
9
+ add_filter('plugin_action_links', array(
10
  $this,
11
  'SettingsLink'
12
  ) , 10, 2);
19
  $this,
20
  'RegisterScripts'
21
  ));
22
+
23
  add_action('admin_enqueue_scripts', array(
24
  $this,
25
  'RegisterAdminScripts'
26
+ ));
27
+
28
  add_action('plugins_loaded', array(
29
  $this,
30
  'RegisterTextDomain'
31
  ));
32
 
33
  add_filter('cscf_spamfilter',array($this,'SpamFilter'));
34
+
35
  //create the settings page
36
  $settings = new cscf_settings();
37
+
38
  }
39
+
40
  //load text domain
41
  function RegisterTextDomain()
42
+ {
43
  //$path = CSCF_PLUGIN_DIR . '/languages';
44
  $path = '/' . CSCF_PLUGIN_NAME . '/languages';
45
  load_plugin_textdomain('clean-and-simple-contact-form-by-meg-nicholas', false, $path );
46
  }
47
+
48
+ function RegisterScripts()
49
  {
50
  wp_register_script('jquery-validate', CSCF_PLUGIN_URL . '/js/jquery.validate.min.js', array(
51
  'jquery'
52
+ ) , '1.19.3', true);
53
+
54
+ wp_register_script( 'cscf-validate', CSCF_PLUGIN_URL . "/js/jquery.validate.contact.form.js",
55
+ 'jquery',
56
  CSCF_VERSION_NUM, true );
57
+
58
+ wp_localize_script( 'cscf-validate', 'cscfvars',
59
  array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) ) );
60
 
61
+ wp_register_style('cscf-bootstrap', CSCF_PLUGIN_URL . '/css/bootstrap-forms.min.css',
62
  null, CSCF_VERSION_NUM);
63
 
 
 
 
64
  wp_register_script( 'csf-recaptcha2',
65
  'https://www.google.com/recaptcha/api.js?hl=' . get_locale(), null, null, true );
66
 
67
  }
68
+
69
  function RegisterAdminScripts($hook)
70
  {
71
  if ( $hook != 'settings_page_contact-form-settings')
72
  return;
73
+
74
+ wp_register_script('cscf-admin-settings', CSCF_PLUGIN_URL . '/js/jquery.admin.settings.js',
75
  array(
76
  'jquery-ui-sortable',
77
+ ) , CSCF_VERSION_NUM, false );
78
+
79
  wp_enqueue_script('cscf-admin-settings');
80
  }
81
+
82
+ function Upgrade($oldVersion)
83
  {
84
+
85
  //turn on the confirm-email option
86
  if ( $oldVersion <= "4.2.3" ) {
87
  $options = get_option(CSCF_OPTIONS_KEY);
88
  $options['confirm-email'] = true;
89
  update_option(CSCF_OPTIONS_KEY, $options);
90
  }
91
+
92
  //change namespace of options
93
  if ( get_option('cff_options') != '') {
94
  update_option('cscf_options', get_option('cff_options'));
97
  if ( get_option('cff_version') != '') {
98
  update_option('cscf_version', get_option('cff_version'));
99
  delete_option('cff_version');
100
+ }
101
+
102
  $options = get_option('cscf_options');
103
  $updated = false;
104
+
105
+ if (trim(get_option('recaptcha_public_key')) <> '')
106
  {
107
  $options['recaptcha_public_key'] = get_option('recaptcha_public_key');
108
  delete_option('recaptcha_public_key');
109
  $updated = true;
110
  }
111
+
112
+ if (trim(get_option('recaptcha_private_key')) <> '')
113
  {
114
  $options['recaptcha_private_key'] = get_option('recaptcha_private_key');
115
  delete_option('recaptcha_private_key');
116
  $updated = true;
117
  }
118
+
119
  if ($updated) update_option('cscf_options', $options);
120
+
121
  //delete old array key array_key
122
  if (get_option('array_key') != FALSE) {
123
  $options = get_option('array_key');
124
+
125
  //check it was this plugin that created it by checking for a few values
126
  if (isset($options['sent_message_heading']) && isset($options['sent_message_body'])) {
127
  delete_option('array_key');
128
  }
129
  }
130
+
131
  //upgrade to 4.2.3 recipient_email becomes recipient_emails (array) for multiple recipients
132
  $options = get_option(CSCF_OPTIONS_KEY);
133
  if ( isset($options['recipient_email']) ) {
135
  $options['recipient_emails'][] = $options['recipient_email'];
136
  update_option(CSCF_OPTIONS_KEY,$options);
137
  }
138
+
139
  }
140
 
141
  /*
142
  * Add the settings link to the plugin page
143
  */
144
+
145
+ function SettingsLink($links, $file)
146
  {
147
+
148
+ if ($file == CSCF_PLUGIN_NAME . '/' . CSCF_PLUGIN_NAME . '.php')
149
  {
150
 
151
  /*
152
  * Insert the link at the beginning
153
  */
154
+ $in = '<a href="options-general.php?page=contact-form-settings">' . esc_html__('Settings', 'clean-and-simple-contact-form-by-meg-nicholas') . '</a>';
155
  array_unshift($links, $in);
156
 
157
  /*
158
  * Insert at the end
159
  */
160
 
161
+ // $links[] = '<a href="options-general.php?page=contact-form-settings">'.esc_html__('Settings','contact-form').'</a>';
162
+
163
  }
164
+
165
  return $links;
166
  }
167
+ static
168
+ function Log($message)
169
  {
170
+
171
+ if (WP_DEBUG === true)
172
  {
173
+
174
+ if (is_array($message) || is_object($message))
175
  {
176
  error_log(print_r($message, true));
177
  }
181
  }
182
  }
183
  }
184
+
185
  /*
186
  *This is all we need to do to weed out the spam.
187
  *If akismet plugin is enabled then it will be hooked into these filters.
188
  */
189
+ public function SpamFilter($contact) {
190
+
 
191
  $commentData = apply_filters('preprocess_comment', array(
192
  'comment_post_ID' => $contact->PostID,
193
  'comment_author' => $contact->Name,
208
  $contact->IsSpam = false;
209
  }
210
  return $contact;
211
+ }
212
  }
213
 
class.cscf_contact.php CHANGED
@@ -26,34 +26,48 @@ class cscf_Contact {
26
  $this->RecaptchaPrivateKey = cscf_PluginSettings::PrivateKey();
27
  }
28
 
29
- if ( $_SERVER['REQUEST_METHOD'] == 'POST' && isset( $_POST['cscf'] ) ) {
30
- $cscf = $_POST['cscf'];
31
- $this->Name = filter_var( $cscf['name'], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES );
32
- $this->Email = filter_var( $cscf['email'], FILTER_SANITIZE_EMAIL );
33
-
34
- if ( isset( $cscf['confirm-email'] ) ) {
35
- $this->ConfirmEmail = filter_var( $cscf['confirm-email'], FILTER_SANITIZE_EMAIL );
36
- }
37
-
38
- $this->EmailToSender = isset( $cscf['email-sender'] );
39
-
40
- $this->Message = filter_var( $cscf['message'], FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES );
41
- if ( isset( $_POST['post-id'] ) ) {
42
- $this->PostID = $_POST['post-id'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  }
44
-
45
- if ( cscf_PluginSettings::ContactConsent() ) {
46
- $this->ContactConsent = isset( $cscf['contact-consent'] );
47
- }
48
-
49
- unset( $_POST['cscf'] );
50
  }
51
 
52
  $this->IsSpam = false;
53
  }
54
 
55
- public
56
- function IsValid() {
57
  $this->Errors = array();
58
 
59
  if ( $_SERVER['REQUEST_METHOD'] != 'POST' ) {
@@ -68,41 +82,41 @@ class cscf_Contact {
68
  // email and confirm email are the same
69
  if ( cscf_PluginSettings::ConfirmEmail() ) {
70
  if ( $this->Email != $this->ConfirmEmail ) {
71
- $this->Errors['confirm-email'] = __( 'Sorry the email addresses do not match.', 'clean-and-simple-contact-form-by-meg-nicholas' );
72
  }
73
  }
74
 
75
  //email
76
  if ( strlen( $this->Email ) == 0 ) {
77
- $this->Errors['email'] = __( 'Please give your email address.', 'clean-and-simple-contact-form-by-meg-nicholas' );
78
  }
79
 
80
  //confirm email
81
  if ( cscf_PluginSettings::ConfirmEmail() ) {
82
  if ( strlen( $this->ConfirmEmail ) == 0 ) {
83
- $this->Errors['confirm-email'] = __( 'Please confirm your email address.', 'clean-and-simple-contact-form-by-meg-nicholas' );
84
  }
85
  }
86
 
87
  //name
88
  if ( strlen( $this->Name ) == 0 ) {
89
- $this->Errors['name'] = __( 'Please give your name.', 'clean-and-simple-contact-form-by-meg-nicholas' );
90
  }
91
 
92
  //message
93
  if ( strlen( $this->Message ) == 0 ) {
94
- $this->Errors['message'] = __( 'Please enter a message.', 'clean-and-simple-contact-form-by-meg-nicholas' );
95
  }
96
 
97
  //email invalid address
98
  if ( strlen( $this->Email ) > 0 && ! filter_var( $this->Email, FILTER_VALIDATE_EMAIL ) ) {
99
- $this->Errors['email'] = __( 'Please enter a valid email address.', 'clean-and-simple-contact-form-by-meg-nicholas' );
100
  }
101
 
102
  //contact consent
103
  if ( cscf_PluginSettings::ContactConsent() ) {
104
  if ( ! $this->ContactConsent ) {
105
- $this->Errors['contact-consent'] = __( 'Please give your consent.', 'clean-and-simple-contact-form-by-meg-nicholas' );
106
  }
107
  }
108
 
@@ -111,15 +125,14 @@ class cscf_Contact {
111
  $resp = csf_RecaptchaV2::VerifyResponse( $_SERVER["REMOTE_ADDR"], $this->RecaptchaPrivateKey, $_POST["g-recaptcha-response"] );
112
 
113
  if ( ! $resp->success ) {
114
- $this->Errors['recaptcha'] = __( 'Please solve the recaptcha to continue.', 'clean-and-simple-contact-form-by-meg-nicholas' );
115
  }
116
  }
117
 
118
  return count( $this->Errors ) == 0;
119
  }
120
 
121
- public
122
- function SendMail() {
123
  apply_filters( 'cscf_spamfilter', $this );
124
 
125
  if ( $this->IsSpam === true ) {
@@ -134,21 +147,21 @@ class cscf_Contact {
134
  $filters->fromEmail = $this->Email;
135
  }
136
 
137
- $filters->fromName = $this->Name;
138
 
139
  //add filters
140
  $filters->add( 'wp_mail_from' );
141
  $filters->add( 'wp_mail_from_name' );
142
 
143
  //headers
144
- $header = "Reply-To: " . $this->Email . "\r\n";
145
 
146
  //message
147
- $message = __( 'From: ', 'clean-and-simple-contact-form-by-meg-nicholas' ) . $this->Name . "\n\n";
148
- $message .= __( 'Email: ', 'clean-and-simple-contact-form-by-meg-nicholas' ) . $this->Email . "\n\n";
149
- $message .= __( 'Page URL: ', 'clean-and-simple-contact-form-by-meg-nicholas' ) . get_permalink( $this->PostID ) . "\n\n";
150
- $message .= __( 'Message:', 'clean-and-simple-contact-form-by-meg-nicholas' ) . "\n\n" . $this->Message . "\n\n";
151
- $message .= cscf_PluginSettings::ContactConsentMsg() . ': ' . ( $this->ContactConsent ? __( 'yes', 'clean-and-simple-contact-form-by-meg-nicholas' ) : __( 'no', 'clean-and-simple-contact-form-by-meg-nicholas' ) );
152
 
153
 
154
  $result = ( wp_mail( cscf_PluginSettings::RecipientEmails(), cscf_PluginSettings::Subject(), stripslashes( $message ), $header ) );
@@ -167,7 +180,7 @@ class cscf_Contact {
167
  $filters->fromEmail = $recipients[0];
168
  }
169
 
170
- $filters->fromName = get_bloginfo( 'name' );
171
 
172
  //add filters
173
  $filters->add( 'wp_mail_from' );
@@ -175,7 +188,7 @@ class cscf_Contact {
175
 
176
  $header = "";
177
  $message = cscf_PluginSettings::SentMessageBody() . "\n\n";
178
- $message .= __( "Here is a copy of your message :", "clean-and-simple-contact-form-by-meg-nicholas" ) . "\n\n";
179
  $message .= $this->Message;
180
 
181
  $result = ( wp_mail( $this->Email, cscf_PluginSettings::Subject(), stripslashes( $message ), $header ) );
26
  $this->RecaptchaPrivateKey = cscf_PluginSettings::PrivateKey();
27
  }
28
 
29
+ if ( $_SERVER['REQUEST_METHOD'] == 'POST' ) {
30
+ if ( isset( $_POST['cscf'] ) ) {
31
+ $cscf = (array) $_POST['cscf'];
32
+ foreach ( $cscf as $key => $value ) {
33
+ switch ( $key ) {
34
+ case 'name':
35
+ $this->Name = sanitize_text_field( $value );
36
+ break;
37
+ case 'email':
38
+ $this->Email = sanitize_email( $value );
39
+ break;
40
+ case 'confirm-email':
41
+ $this->ConfirmEmail = sanitize_email( $value );
42
+ break;
43
+ case 'email-sender':
44
+ $this->EmailToSender = sanitize_text_field( $value );
45
+ break;
46
+ case 'message':
47
+ $this->Message = sanitize_textarea_field( $value );
48
+ break;
49
+ case 'contact-consent':
50
+ if ( cscf_PluginSettings::ContactConsent() ) {
51
+ $this->ContactConsent = sanitize_text_field( $value );
52
+ }
53
+ break;
54
+ default:
55
+ $cscf[ $key ] = null; // should never get this but just in case.
56
+ }
57
+ }
58
+
59
+ if ( isset( $_POST['post-id'] ) ) {
60
+ $this->PostID = sanitize_text_field( $_POST['post-id'] );
61
+ }
62
+
63
+ unset( $_POST['cscf'] );
64
  }
 
 
 
 
 
 
65
  }
66
 
67
  $this->IsSpam = false;
68
  }
69
 
70
+ public function IsValid() {
 
71
  $this->Errors = array();
72
 
73
  if ( $_SERVER['REQUEST_METHOD'] != 'POST' ) {
82
  // email and confirm email are the same
83
  if ( cscf_PluginSettings::ConfirmEmail() ) {
84
  if ( $this->Email != $this->ConfirmEmail ) {
85
+ $this->Errors['confirm-email'] = esc_html__( 'Sorry the email addresses do not match.', 'clean-and-simple-contact-form-by-meg-nicholas' );
86
  }
87
  }
88
 
89
  //email
90
  if ( strlen( $this->Email ) == 0 ) {
91
+ $this->Errors['email'] = esc_html__( 'Please give your email address.', 'clean-and-simple-contact-form-by-meg-nicholas' );
92
  }
93
 
94
  //confirm email
95
  if ( cscf_PluginSettings::ConfirmEmail() ) {
96
  if ( strlen( $this->ConfirmEmail ) == 0 ) {
97
+ $this->Errors['confirm-email'] = esc_html__( 'Please confirm your email address.', 'clean-and-simple-contact-form-by-meg-nicholas' );
98
  }
99
  }
100
 
101
  //name
102
  if ( strlen( $this->Name ) == 0 ) {
103
+ $this->Errors['name'] = esc_html__( 'Please give your name.', 'clean-and-simple-contact-form-by-meg-nicholas' );
104
  }
105
 
106
  //message
107
  if ( strlen( $this->Message ) == 0 ) {
108
+ $this->Errors['message'] = esc_html__( 'Please enter a message.', 'clean-and-simple-contact-form-by-meg-nicholas' );
109
  }
110
 
111
  //email invalid address
112
  if ( strlen( $this->Email ) > 0 && ! filter_var( $this->Email, FILTER_VALIDATE_EMAIL ) ) {
113
+ $this->Errors['email'] = esc_html__( 'Please enter a valid email address.', 'clean-and-simple-contact-form-by-meg-nicholas' );
114
  }
115
 
116
  //contact consent
117
  if ( cscf_PluginSettings::ContactConsent() ) {
118
  if ( ! $this->ContactConsent ) {
119
+ $this->Errors['contact-consent'] = esc_html__( 'Please give your consent.', 'clean-and-simple-contact-form-by-meg-nicholas' );
120
  }
121
  }
122
 
125
  $resp = csf_RecaptchaV2::VerifyResponse( $_SERVER["REMOTE_ADDR"], $this->RecaptchaPrivateKey, $_POST["g-recaptcha-response"] );
126
 
127
  if ( ! $resp->success ) {
128
+ $this->Errors['recaptcha'] = esc_html__( 'Please solve the recaptcha to continue.', 'clean-and-simple-contact-form-by-meg-nicholas' );
129
  }
130
  }
131
 
132
  return count( $this->Errors ) == 0;
133
  }
134
 
135
+ public function SendMail() {
 
136
  apply_filters( 'cscf_spamfilter', $this );
137
 
138
  if ( $this->IsSpam === true ) {
147
  $filters->fromEmail = $this->Email;
148
  }
149
 
150
+ $filters->from_name = $this->Name;
151
 
152
  //add filters
153
  $filters->add( 'wp_mail_from' );
154
  $filters->add( 'wp_mail_from_name' );
155
 
156
  //headers
157
+ $header = "Content-Type: text/plain\r\nReply-To: " . $this->Email . "\r\n";
158
 
159
  //message
160
+ $message = esc_html__( 'From: ', 'clean-and-simple-contact-form-by-meg-nicholas' ) . esc_attr( $this->Name ) . "\r\n";
161
+ $message .= esc_html__( 'Email: ', 'clean-and-simple-contact-form-by-meg-nicholas' ) . esc_attr( $this->Email ) . "\r\n";
162
+ $message .= esc_html__( 'Page URL: ', 'clean-and-simple-contact-form-by-meg-nicholas' ) . get_permalink( $this->PostID ) . "\r\n";
163
+ $message .= esc_html__( 'Message:', 'clean-and-simple-contact-form-by-meg-nicholas' ) . "\n\n" . esc_html( $this->Message ) . "\r\n";
164
+ $message .= cscf_PluginSettings::ContactConsentMsg() . ': ' . ( $this->ContactConsent ? esc_html__( 'yes', 'clean-and-simple-contact-form-by-meg-nicholas' ) : esc_html__( 'no', 'clean-and-simple-contact-form-by-meg-nicholas' ) );
165
 
166
 
167
  $result = ( wp_mail( cscf_PluginSettings::RecipientEmails(), cscf_PluginSettings::Subject(), stripslashes( $message ), $header ) );
180
  $filters->fromEmail = $recipients[0];
181
  }
182
 
183
+ $filters->from_name = get_bloginfo( 'name' );
184
 
185
  //add filters
186
  $filters->add( 'wp_mail_from' );
188
 
189
  $header = "";
190
  $message = cscf_PluginSettings::SentMessageBody() . "\n\n";
191
+ $message .= esc_html__( "Here is a copy of your message :", "clean-and-simple-contact-form" ) . "\n\n";
192
  $message .= $this->Message;
193
 
194
  $result = ( wp_mail( $this->Email, cscf_PluginSettings::Subject(), stripslashes( $message ), $header ) );
class.cscf_filters.php CHANGED
@@ -5,46 +5,49 @@
5
  */
6
 
7
  class cscf_Filters {
8
-
9
- var $fromEmail;
10
- var $fromName;
11
-
12
- function wp_mail_from ($orig) {
13
-
14
- // This is copied from pluggable.php lines 348-354 as at revision 10150
15
- // http://trac.wordpress.org/browser/branches/2.7/wp-includes/pluggable.php#L348
16
-
17
- // Get the site domain and get rid of www.
18
- $sitename = strtolower( $_SERVER['SERVER_NAME'] );
19
- if ( substr( $sitename, 0, 4 ) == 'www.' ) {
20
- $sitename = substr( $sitename, 4 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  }
22
 
23
- $default_from = 'wordpress@' . $sitename;
24
- // End of copied code
25
-
26
- // If the from email is not the default, return it unchanged
27
- if ( $orig != $default_from ) {
28
- return $orig;
29
- }
30
- return $this->fromEmail;
31
- }
32
-
33
- //strip slashes from the name
34
- function wp_mail_from_name ($orig) {
35
-
36
- if ( $orig != 'WordPress') {
37
- return $orig;
38
- }
39
- return stripslashes($this->fromName);
40
- }
41
-
42
- function add($filter, $priority = 10, $args = 1) {
43
- add_filter ($filter, array($this,$filter),$priority,$args);
44
- }
45
-
46
- function remove($filter, $priority = 10, $args = 1) {
47
- remove_filter ($filter, array($this,$filter),$priority,$args);
48
- }
49
-
50
  }
5
  */
6
 
7
  class cscf_Filters {
8
+
9
+
10
+ var $from_email;
11
+ var $from_name;
12
+
13
+ function wp_mail_from( $orig ) {
14
+
15
+ // This is copied from pluggable.php lines 348-354 as at revision 10150
16
+ // http://trac.wordpress.org/browser/branches/2.7/wp-includes/pluggable.php#L348
17
+
18
+ // Get the site domain and get rid of www.
19
+ $sitename = strtolower( $_SERVER['SERVER_NAME'] );
20
+ if ( substr( $sitename, 0, 4 ) == 'www.' ) {
21
+ $sitename = substr( $sitename, 4 );
22
+ }
23
+
24
+ $default_from = 'wordpress@' . $sitename;
25
+ // End of copied code
26
+
27
+ // If the from email is not the default, return it unchanged
28
+ if ( $orig != $default_from ) {
29
+ return $orig;
30
+ }
31
+
32
+ return $this->from_email;
33
+ }
34
+
35
+ //strip slashes from the name
36
+ function wp_mail_from_name( $orig ) {
37
+
38
+ if ( $orig != 'WordPress' ) {
39
+ return $orig;
40
+ }
41
+
42
+ return stripslashes( $this->from_name );
43
+ }
44
+
45
+ function add( $filter, $priority = 10, $args = 1 ) {
46
+ add_filter( $filter, array( $this, $filter ), $priority, $args );
47
+ }
48
+
49
+ function remove( $filter, $priority = 10, $args = 1 ) {
50
+ remove_filter( $filter, array( $this, $filter ), $priority, $args );
51
  }
52
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  }
class.cscf_pluginsettings.php CHANGED
@@ -41,7 +41,7 @@ class cscf_PluginSettings
41
  {
42
  $options = get_option(CSCF_OPTIONS_KEY);
43
 
44
- return isset($options['sent_message_heading']) ? __($options['sent_message_heading'], 'clean-and-simple-contact-form-by-meg-nicholas') : __('Message Sent', 'clean-and-simple-contact-form-by-meg-nicholas');
45
  }
46
 
47
  static
@@ -49,7 +49,7 @@ class cscf_PluginSettings
49
  {
50
  $options = get_option(CSCF_OPTIONS_KEY);
51
 
52
- return isset($options['sent_message_body']) ? __($options['sent_message_body'], 'clean-and-simple-contact-form-by-meg-nicholas') : __('Thank you for your message, we will be in touch very shortly.', 'clean-and-simple-contact-form-by-meg-nicholas');
53
  }
54
 
55
  static
@@ -57,7 +57,7 @@ class cscf_PluginSettings
57
  {
58
  $options = get_option(CSCF_OPTIONS_KEY);
59
 
60
- return isset($options['message']) ? __($options['message'], 'clean-and-simple-contact-form-by-meg-nicholas') : __('Please enter your contact details and a short message below and I will try to answer your query as soon as possible.', 'clean-and-simple-contact-form-by-meg-nicholas');
61
  }
62
 
63
  static
@@ -91,7 +91,7 @@ class cscf_PluginSettings
91
  {
92
  $options = get_option(CSCF_OPTIONS_KEY);
93
 
94
- return isset($options['subject']) ? __($options['subject'], 'clean-and-simple-contact-form-by-meg-nicholas') : get_bloginfo('name') . __(' - Web Enquiry', 'clean-and-simple-contact-form-by-meg-nicholas');
95
  }
96
 
97
  static
@@ -139,7 +139,7 @@ class cscf_PluginSettings
139
 
140
  $options = get_option(CSCF_OPTIONS_KEY);
141
 
142
- return isset( $options['contact-consent-msg'] ) ? $options['contact-consent-msg'] : __( 'I consent to my contact details being stored', 'clean-and-simple-contact-form-by-meg-nicholas' );
143
 
144
  }
145
 
@@ -159,14 +159,12 @@ class cscf_PluginSettings
159
 
160
  }
161
 
162
- static
163
- function InputIcons()
164
  {
165
  return false;
166
  }
167
 
168
- static
169
- function ConfirmEmail()
170
  {
171
  $options = get_option(CSCF_OPTIONS_KEY);
172
  return isset($options['confirm-email']) ? true : false;
41
  {
42
  $options = get_option(CSCF_OPTIONS_KEY);
43
 
44
+ return isset($options['sent_message_heading']) ? $options['sent_message_heading'] : esc_html__('Message Sent', 'clean-and-simple-contact-form-by-meg-nicholas');
45
  }
46
 
47
  static
49
  {
50
  $options = get_option(CSCF_OPTIONS_KEY);
51
 
52
+ return isset($options['sent_message_body']) ? $options['sent_message_body'] : esc_html__('Thank you for your message, we will be in touch very shortly.', 'clean-and-simple-contact-form-by-meg-nicholas');
53
  }
54
 
55
  static
57
  {
58
  $options = get_option(CSCF_OPTIONS_KEY);
59
 
60
+ return isset($options['message'])? $options['message'] : esc_html__('Please enter your contact details and a short message below and I will try to answer your query as soon as possible.', 'clean-and-simple-contact-form-by-meg-nicholas');
61
  }
62
 
63
  static
91
  {
92
  $options = get_option(CSCF_OPTIONS_KEY);
93
 
94
+ return isset($options['subject']) ? $options['subject']: get_bloginfo('name') . esc_html__(' - Web Enquiry', 'clean-and-simple-contact-form-by-meg-nicholas');
95
  }
96
 
97
  static
139
 
140
  $options = get_option(CSCF_OPTIONS_KEY);
141
 
142
+ return isset( $options['contact-consent-msg'] ) ? $options['contact-consent-msg'] : esc_html__( 'I consent to my contact details being stored', 'clean-and-simple-contact-form-by-meg-nicholas' );
143
 
144
  }
145
 
159
 
160
  }
161
 
162
+ static function InputIcons()
 
163
  {
164
  return false;
165
  }
166
 
167
+ static function ConfirmEmail()
 
168
  {
169
  $options = get_option(CSCF_OPTIONS_KEY);
170
  return isset($options['confirm-email']) ? true : false;
class.cscf_settings.php CHANGED
@@ -1,429 +1,407 @@
1
- <?php
2
-
3
- /*
4
- * creates the settings page for the plugin
5
- */
6
-
7
- class cscf_settings
8
- {
9
- public
10
- function __construct()
11
- {
12
-
13
- if (is_admin()) {
14
- add_action('admin_menu', array(
15
- $this,
16
- 'add_plugin_page'
17
- ));
18
- add_action('admin_init', array(
19
- $this,
20
- 'page_init'
21
- ));
22
- }
23
- }
24
-
25
- public
26
- function add_plugin_page()
27
- {
28
-
29
- // This page will be under "Settings"
30
- add_options_page(__('Contact Form Settings', 'clean-and-simple-contact-form-by-meg-nicholas'), __('Contact Form', 'clean-and-simple-contact-form-by-meg-nicholas'), 'manage_options', 'contact-form-settings', array(
31
- $this,
32
- 'create_admin_page'
33
- ));
34
- }
35
-
36
- public
37
- function create_admin_page()
38
- {
39
- ?>
40
-
41
- <h2><?php _e('Clean and Simple Contact Form Settings', 'clean-and-simple-contact-form-by-meg-nicholas'); ?></h2>
42
- <hr/>
43
-
44
- <div style="float:right;position: relative;width:250px;">
45
-
46
- <div style="border:1px solid;padding:5px;margin-bottom: 8px;text-align:center;">
47
- <h3><?php _e("Donate $10, $20 or $50!", "clean-and-simple-contact-form-by-meg-nicholas"); ?></h3>
48
-
49
- <div>
50
- <p><?php _e("If you like this plugin, please donate to support development and maintenance of:", "clean-and-simple-contact-form-by-meg-nicholas"); ?></p>
51
-
52
- <h3><?php _e("Clean and Simple Contact Form!", "clean-and-simple-contact-form-by-meg-nicholas"); ?></h3>
53
-
54
- <form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
55
- <input type="hidden" name="cmd" value="_s-xclick">
56
- <input type="hidden" name="hosted_button_id" value="ALAGLZ3APUZMW">
57
- <input type="image" src="https://www.paypalobjects.com/en_US/GB/i/btn/btn_donateCC_LG.gif"
58
- border="0" name="submit" alt="PayPal The safer, easier way to pay online.">
59
- <img alt="" border="0" src="https://www.paypalobjects.com/en_GB/i/scr/pixel.gif" width="1"
60
- height="1">
61
- </form>
62
-
63
- </div>
64
- </div>
65
- </div>
66
- <div style="float:left;">
67
- <p><?php _e('You are using version', 'clean-and-simple-contact-form-by-meg-nicholas'); ?> <?php echo CSCF_VERSION_NUM; ?></p>
68
-
69
- <p><?php _e('If you find this plugin useful please consider', 'clean-and-simple-contact-form-by-meg-nicholas'); ?>
70
- <a target="_blank"
71
- href="http://wordpress.org/support/view/plugin-reviews/<?php echo CSCF_PLUGIN_NAME; ?>">
72
- <?php _e('leaving a review', 'clean-and-simple-contact-form-by-meg-nicholas'); ?>
73
- </a>
74
- . <?php _e('Thank you!', 'clean-and-simple-contact-form-by-meg-nicholas'); ?>
75
- </p>
76
-
77
- <?php if (cscf_PluginSettings::IsJetPackContactFormEnabled()) { ?>
78
- <p class="highlight">
79
- <?php _e('NOTICE: You have JetPack\'s Contact Form enabled please deactivate it or use the shortcode [cscf-contact-form] instead.', 'clean-and-simple-contact-form-by-meg-nicholas'); ?>
80
- &nbsp; <a target="_blank"
81
- href="http://www.megnicholas.co.uk/articles/clean-and-simple-contact-form-and-jetpack/"><?php _e('Read More', 'clean-and-simple-contact-form-by-meg-nicholas'); ?></a>
82
- </p>
83
- <?php } ?>
84
-
85
- <p class="howto"><?php _e("Please Note: To add the contact form to your page please add the text", "clean-and-simple-contact-form-by-meg-nicholas"); ?>
86
- <code>[cscf-contact-form]</code> <?php _e("to your post or page.", "clean-and-simple-contact-form-by-meg-nicholas"); ?></p>
87
-
88
- <form method="post" action="options.php">
89
- <?php
90
- submit_button();
91
-
92
- /* This prints out all hidden setting fields*/
93
- settings_fields('test_option_group');
94
- do_settings_sections('contact-form-settings');
95
-
96
- submit_button();
97
- ?>
98
- </form>
99
- </div>
100
- <?php
101
- }
102
-
103
- public
104
- function page_init()
105
- {
106
- add_settings_section('section_recaptcha', '<h3>' . __('ReCAPTCHA Settings', 'clean-and-simple-contact-form-by-meg-nicholas') . '</h3>', array(
107
- $this,
108
- 'print_section_info_recaptcha'
109
- ), 'contact-form-settings');
110
- register_setting('test_option_group', CSCF_OPTIONS_KEY, array(
111
- $this,
112
- 'check_form'
113
- ));
114
- add_settings_field('use_recaptcha', __('Use reCAPTCHA :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
115
- $this,
116
- 'create_fields'
117
- ), 'contact-form-settings', 'section_recaptcha', array(
118
- 'use_recaptcha'
119
- ));
120
- add_settings_field('theme', __('reCAPTCHA Theme :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
121
- $this,
122
- 'create_fields'
123
- ), 'contact-form-settings', 'section_recaptcha', array(
124
- 'theme'
125
- ));
126
- add_settings_field('recaptcha_public_key', __('reCAPTCHA Public Key :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
127
- $this,
128
- 'create_fields'
129
- ), 'contact-form-settings', 'section_recaptcha', array(
130
- 'recaptcha_public_key'
131
- ));
132
- add_settings_field('recaptcha_private_key', __('reCAPTCHA Private Key :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
133
- $this,
134
- 'create_fields'
135
- ), 'contact-form-settings', 'section_recaptcha', array(
136
- 'recaptcha_private_key'
137
- ));
138
- add_settings_section('section_message', '<h3>' . __('Message Settings', 'clean-and-simple-contact-form-by-meg-nicholas') . '</h3>', array(
139
- $this,
140
- 'print_section_info_message'
141
- ), 'contact-form-settings');
142
- add_settings_field('recipient_emails', __('Recipient Emails :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
143
- $this,
144
- 'create_fields'
145
- ), 'contact-form-settings', 'section_message', array(
146
- 'recipient_emails'
147
- ));
148
- add_settings_field('confirm-email', __('Confirm Email Address :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
149
- $this,
150
- 'create_fields'
151
- ), 'contact-form-settings', 'section_message', array(
152
- 'confirm-email'
153
- ));
154
- add_settings_field('email-sender', __('Allow users to email themselves a copy :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
155
- $this,
156
- 'create_fields'
157
- ), 'contact-form-settings', 'section_message', array(
158
- 'email-sender'
159
- ));
160
- add_settings_field('contact-consent', '<span style="color:red;">' . __('*New*','clean-and-simple-contact-form-by-meg-nicholas') . '</span> ' . __('Add a consent checkbox :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
161
- $this,
162
- 'create_fields'
163
- ), 'contact-form-settings', 'section_message', array(
164
- 'contact-consent'
165
- ));
166
- add_settings_field('contact-consent-msg', '<span style="color:red;">' . __('*New*','clean-and-simple-contact-form-by-meg-nicholas') . '</span> ' . __('Consent message :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
167
- $this,
168
- 'create_fields'
169
- ), 'contact-form-settings', 'section_message', array(
170
- 'contact-consent-msg'
171
- ));
172
- add_settings_field('override-from', __('Override \'From\' Address :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
173
- $this,
174
- 'create_fields'
175
- ), 'contact-form-settings', 'section_message', array(
176
- 'override-from'
177
- ));
178
- add_settings_field('from-email', __('\'From\' Email Address :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
179
- $this,
180
- 'create_fields'
181
- ), 'contact-form-settings', 'section_message', array(
182
- 'from-email'
183
- ));
184
- add_settings_field('subject', __('Email Subject :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
185
- $this,
186
- 'create_fields'
187
- ), 'contact-form-settings', 'section_message', array(
188
- 'subject'
189
- ));
190
- add_settings_field('message', __('Message :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
191
- $this,
192
- 'create_fields'
193
- ), 'contact-form-settings', 'section_message', array(
194
- 'message'
195
- ));
196
- add_settings_field('sent_message_heading', __('Message Sent Heading :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
197
- $this,
198
- 'create_fields'
199
- ), 'contact-form-settings', 'section_message', array(
200
- 'sent_message_heading'
201
- ));
202
- add_settings_field('sent_message_body', __('Message Sent Content :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
203
- $this,
204
- 'create_fields'
205
- ), 'contact-form-settings', 'section_message', array(
206
- 'sent_message_body'
207
- ));
208
- add_settings_section('section_styling', '<h3>' . __('Styling and Validation', 'clean-and-simple-contact-form-by-meg-nicholas') . '</h3>', array(
209
- $this,
210
- 'print_section_info_styling'
211
- ), 'contact-form-settings');
212
- add_settings_field('load_stylesheet', __('Use the plugin default stylesheet (un-tick to use your theme style sheet instead) :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
213
- $this,
214
- 'create_fields'
215
- ), 'contact-form-settings', 'section_styling', array(
216
- 'load_stylesheet'
217
- ));
218
- add_settings_field('use_client_validation', __('Use client side validation (AJAX) :', 'clean-and-simple-contact-form-by-meg-nicholas'), array(
219
- $this,
220
- 'create_fields'
221
- ), 'contact-form-settings', 'section_styling', array(
222
- 'use_client_validation'
223
- ));
224
- }
225
-
226
- public
227
- function check_form($input)
228
- {
229
-
230
- //recaptcha theme
231
- if (isset($input['theme'])) $input['theme'] = filter_var($input['theme'], FILTER_SANITIZE_STRING);
232
-
233
- //recaptcha_public_key
234
- if (isset($input['recaptcha_public_key'])) $input['recaptcha_public_key'] = filter_var($input['recaptcha_public_key'], FILTER_SANITIZE_STRING);
235
-
236
- //recaptcha_private_key
237
- if (isset($input['recaptcha_private_key'])) $input['recaptcha_private_key'] = filter_var($input['recaptcha_private_key'], FILTER_SANITIZE_STRING);
238
-
239
- //sent_message_heading
240
- $input['sent_message_heading'] = filter_var($input['sent_message_heading'], FILTER_SANITIZE_STRING);
241
-
242
- //sent_message_body
243
- $input['sent_message_body'] = filter_var($input['sent_message_body'], FILTER_SANITIZE_STRING);
244
-
245
- //message
246
- $input['message'] = filter_var($input['message'], FILTER_SANITIZE_STRING);
247
-
248
-
249
- //consent message
250
- $input['contact-consent-msg'] = filter_var($input['contact-consent-msg'], FILTER_SANITIZE_STRING);
251
-
252
- //recipient_emails
253
- foreach ($input['recipient_emails'] as $key => $recipient) {
254
- if (!filter_var($input['recipient_emails'][$key], FILTER_VALIDATE_EMAIL)) {
255
- unset($input['recipient_emails'][$key]);
256
- }
257
- }
258
-
259
- //from
260
- if (!filter_var($input['from-email'], FILTER_VALIDATE_EMAIL)) {
261
- unset($input['from-email']);
262
- }
263
-
264
- //subject
265
- $input['subject'] = trim(filter_var($input['subject'], FILTER_SANITIZE_STRING));
266
- if (empty($input['subject'])) {
267
- unset($input['subject']);
268
- }
269
-
270
- if (isset($_POST['add_recipient'])) {
271
- $input['recipient_emails'][] = "";
272
- }
273
-
274
- if (isset($_POST['remove_recipient'])) {
275
- foreach ($_POST['remove_recipient'] as $key => $element) {
276
- unset($input['recipient_emails'][$key]);
277
- }
278
- }
279
-
280
- //tidy up the keys
281
- $tidiedRecipients = array();
282
- foreach ($input['recipient_emails'] as $recipient) {
283
- $tidiedRecipients[] = $recipient;
284
- }
285
- $input['recipient_emails'] = $tidiedRecipients;
286
-
287
-
288
- return $input;
289
- }
290
-
291
- public
292
- function print_section_info_recaptcha()
293
- {
294
- print __('Enter your reCAPTCHA settings below :', 'clean-and-simple-contact-form-by-meg-nicholas');
295
- print "<p>" . __('To use reCAPTCHA you must get an API key from', 'clean-and-simple-contact-form-by-meg-nicholas') . " <a target='_blank' href='" . csf_RecaptchaV2::$signUpUrl . "'>Google reCAPTCHA</a></p>";
296
- }
297
-
298
- public
299
- function print_section_info_message()
300
- {
301
- print __('Enter your message settings below :', 'clean-and-simple-contact-form-by-meg-nicholas');
302
- }
303
-
304
- public
305
- function print_section_info_styling()
306
- {
307
-
308
- //print 'Enter your styling settings below:';
309
-
310
- }
311
-
312
- public
313
- function create_fields($args)
314
- {
315
- $fieldname = $args[0];
316
-
317
- switch ($fieldname) {
318
- case 'use_recaptcha':
319
- $checked = cscf_PluginSettings::UseRecaptcha() == true ? "checked" : "";
320
- ?><input type="checkbox" <?php echo $checked; ?> id="use_recaptcha"
321
- name="<?php echo CSCF_OPTIONS_KEY; ?>[use_recaptcha]"><?php
322
- break;
323
- case 'load_stylesheet':
324
- $checked = cscf_PluginSettings::LoadStyleSheet() == true ? "checked" : "";
325
- ?><input type="checkbox" <?php echo $checked; ?> id="load_stylesheet"
326
- name="<?php echo CSCF_OPTIONS_KEY; ?>[load_stylesheet]"><?php
327
- break;
328
- case 'recaptcha_public_key':
329
- $disabled = cscf_PluginSettings::UseRecaptcha() == false ? "readonly" : "";
330
- ?><input <?php echo $disabled; ?> type="text" size="60" id="recaptcha_public_key"
331
- name="<?php echo CSCF_OPTIONS_KEY; ?>[recaptcha_public_key]"
332
- value="<?php echo cscf_PluginSettings::PublicKey(); ?>" /><?php
333
- break;
334
- case 'recaptcha_private_key':
335
- $disabled = cscf_PluginSettings::UseRecaptcha() == false ? "readonly" : "";
336
- ?><input <?php echo $disabled; ?> type="text" size="60" id="recaptcha_private_key"
337
- name="<?php echo CSCF_OPTIONS_KEY; ?>[recaptcha_private_key]"
338
- value="<?php echo cscf_PluginSettings::PrivateKey(); ?>" /><?php
339
- break;
340
- case 'recipient_emails':
341
- ?>
342
- <ul id="recipients"><?php
343
- foreach (cscf_PluginSettings::RecipientEmails() as $key => $recipientEmail) {
344
- ?>
345
- <li class="recipient_email" data-element="<?php echo $key; ?>">
346
- <input class="enter_recipient" type="email" size="50"
347
- name="<?php echo CSCF_OPTIONS_KEY; ?>[recipient_emails][<?php echo $key ?>]"
348
- value="<?php echo $recipientEmail; ?>"/>
349
- <input class="add_recipient" title="Add New Recipient" type="submit" name="add_recipient"
350
- value="+">
351
- <input class="remove_recipient" title="Remove This Recipient" type="submit"
352
- name="remove_recipient[<?php echo $key; ?>]" value="-">
353
- </li>
354
-
355
- <?php
356
- }
357
- ?></ul><?php
358
- break;
359
- case 'confirm-email':
360
- $checked = cscf_PluginSettings::ConfirmEmail() == true ? "checked" : "";
361
- ?><input type="checkbox" <?php echo $checked; ?> id="confirm-email"
362
- name="<?php echo CSCF_OPTIONS_KEY; ?>[confirm-email]"><?php
363
- break;
364
- case 'override-from':
365
- $checked = cscf_PluginSettings::OverrideFrom() == true ? "checked" : "";
366
- ?><input type="checkbox" <?php echo $checked; ?> id="override-from"
367
- name="<?php echo CSCF_OPTIONS_KEY; ?>[override-from]"><?php
368
- break;
369
- case 'email-sender':
370
- $checked = cscf_PluginSettings::EmailToSender() == true ? "checked" : "";
371
- ?><input type="checkbox" <?php echo $checked; ?> id="email-sender"
372
- name="<?php echo CSCF_OPTIONS_KEY; ?>[email-sender]"><?php
373
- break;
374
- case 'contact-consent':
375
- $checked = cscf_PluginSettings::ContactConsent() == true ? "checked" : "";
376
- ?><input type="checkbox" <?php echo $checked; ?> id="contact-consent"
377
- name="<?php echo CSCF_OPTIONS_KEY; ?>[contact-consent]"><?php
378
- break;
379
- case 'contact-consent-msg':
380
- ?><input type="text" size="60" id="contact-consent-msg"
381
- name="<?php echo CSCF_OPTIONS_KEY; ?>[contact-consent-msg]"
382
- value="<?php echo cscf_PluginSettings::ContactConsentMsg(); ?>"><?php
383
- break;
384
- case 'from-email':
385
- $disabled = cscf_PluginSettings::OverrideFrom() == false ? "readonly" : "";
386
- ?><input <?php echo $disabled; ?> type="text" size="60" id="from-email"
387
- name="<?php echo CSCF_OPTIONS_KEY; ?>[from-email]"
388
- value="<?php echo cscf_PluginSettings::FromEmail(); ?>" /><?php
389
- break;
390
- case 'subject':
391
- ?><input type="text" size="60" id="subject" name="<?php echo CSCF_OPTIONS_KEY; ?>[subject]"
392
- value="<?php echo cscf_PluginSettings::Subject(); ?>" /><?php
393
- break;
394
- case 'sent_message_heading':
395
- ?><input type="text" size="60" id="sent_message_heading"
396
- name="<?php echo CSCF_OPTIONS_KEY; ?>[sent_message_heading]"
397
- value="<?php echo cscf_PluginSettings::SentMessageHeading(); ?>" /><?php
398
- break;
399
- case 'sent_message_body':
400
- ?><textarea cols="63" rows="8"
401
- name="<?php echo CSCF_OPTIONS_KEY; ?>[sent_message_body]"><?php echo cscf_PluginSettings::SentMessageBody(); ?></textarea><?php
402
- break;
403
- case 'message':
404
- ?><textarea cols="63" rows="8"
405
- name="<?php echo CSCF_OPTIONS_KEY; ?>[message]"><?php echo cscf_PluginSettings::Message(); ?></textarea><?php
406
- break;
407
- case 'theme':
408
- $theme = cscf_PluginSettings::Theme();
409
- $disabled = cscf_PluginSettings::UseRecaptcha() == false ? "disabled" : "";
410
- ?>
411
- <select <?php echo $disabled; ?> id="theme" name="<?php echo CSCF_OPTIONS_KEY; ?>[theme]">
412
- <option <?php echo $theme == "light" ? "selected" : ""; ?>
413
- value="light"><?php _e('Light', 'clean-and-simple-contact-form-by-meg-nicholas'); ?></option>
414
- <option <?php echo $theme == "dark" ? "selected" : ""; ?>
415
- value="dark"><?php _e('Dark', 'clean-and-simple-contact-form-by-meg-nicholas'); ?></option>
416
- </select>
417
- <?php
418
- break;
419
- case 'use_client_validation':
420
- $checked = cscf_PluginSettings::UseClientValidation() == true ? "checked" : "";
421
- ?><input type="checkbox" <?php echo $checked; ?> id="use_client_validation"
422
- name="<?php echo CSCF_OPTIONS_KEY; ?>[use_client_validation]"><?php
423
- break;
424
- default:
425
- break;
426
- }
427
- }
428
- }
429
-
1
+ <?php
2
+
3
+ /*
4
+ * creates the settings page for the plugin
5
+ */
6
+
7
+ class cscf_settings {
8
+ public function __construct() {
9
+
10
+ if ( is_admin() ) {
11
+ add_action( 'admin_menu', array(
12
+ $this,
13
+ 'add_plugin_page'
14
+ ) );
15
+ add_action( 'admin_init', array(
16
+ $this,
17
+ 'page_init'
18
+ ) );
19
+ }
20
+ }
21
+
22
+ public function add_plugin_page() {
23
+
24
+ // This page will be under "Settings".
25
+ add_options_page(
26
+ esc_html__( 'Contact Form Settings', 'clean-and-simple-contact-form-by-meg-nicholas' ),
27
+ esc_html__( 'Contact Form', 'clean-and-simple-contact-form-by-meg-nicholas' ),
28
+ 'manage_options',
29
+ 'contact-form-settings',
30
+ array(
31
+ $this,
32
+ 'create_admin_page',
33
+ )
34
+ );
35
+ }
36
+
37
+ public function create_admin_page() {
38
+ ?>
39
+ <h2><?php esc_html_e( 'Clean and Simple Contact Form Settings', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></h2>
40
+ <hr/>
41
+ <div style="float:left;">
42
+ <p><?php esc_html_e( 'You are using version', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?><?php echo esc_attr(CSCF_VERSION_NUM); ?></p>
43
+
44
+ <p><?php esc_html_e( 'If you find this plugin useful please consider', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>
45
+ <a target="_blank"
46
+ href="http://wordpress.org/support/view/plugin-reviews/<?php echo esc_attr(CSCF_PLUGIN_NAME); ?>">
47
+ <?php esc_html_e( 'leaving a review', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>
48
+ </a>
49
+ . <?php esc_html_e( 'Thank you!', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>
50
+ </p>
51
+
52
+ <?php if ( cscf_PluginSettings::IsJetPackContactFormEnabled() ) { ?>
53
+ <p class="highlight">
54
+ <?php esc_html_e( 'NOTICE: You have JetPack\'s Contact Form enabled please deactivate it or use the shortcode [cscf-contact-form] instead.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>
55
+ &nbsp; </p>
56
+ <?php } ?>
57
+
58
+ <p class="howto"><?php esc_html_e( "Please Note: To add the contact form to your page please add the text", "clean-and-simple-contact-form" ); ?>
59
+ <code>[cscf-contact-form]</code> <?php esc_html_e( "to your post or page.", "clean-and-simple-contact-form" ); ?>
60
+ </p>
61
+
62
+ <form method="post" action="options.php">
63
+ <?php
64
+ submit_button();
65
+ /* This prints out all hidden setting fields*/
66
+ settings_fields( 'test_option_group' );
67
+ do_settings_sections( 'contact-form-settings' );
68
+ submit_button();
69
+ ?>
70
+ </form>
71
+ </div>
72
+ <?php
73
+ }
74
+
75
+ public function page_init() {
76
+ add_settings_section(
77
+ 'section_recaptcha',
78
+ '<h3>' . esc_html__( 'ReCAPTCHA Settings', 'clean-and-simple-contact-form-by-meg-nicholas' ) . '</h3>',
79
+ array(
80
+ $this,
81
+ 'print_section_info_recaptcha',
82
+ ),
83
+ 'contact-form-settings'
84
+ );
85
+ register_setting( 'test_option_group', CSCF_OPTIONS_KEY, array(
86
+ $this,
87
+ 'check_form'
88
+ ) );
89
+ add_settings_field( 'use_recaptcha', esc_html__( 'Use reCAPTCHA :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
90
+ $this,
91
+ 'create_fields'
92
+ ), 'contact-form-settings', 'section_recaptcha', array(
93
+ 'use_recaptcha'
94
+ ) );
95
+ add_settings_field( 'theme', esc_html__( 'reCAPTCHA Theme :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
96
+ $this,
97
+ 'create_fields'
98
+ ), 'contact-form-settings', 'section_recaptcha', array(
99
+ 'theme'
100
+ ) );
101
+ add_settings_field( 'recaptcha_public_key', esc_html__( 'reCAPTCHA Public Key :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
102
+ $this,
103
+ 'create_fields'
104
+ ), 'contact-form-settings', 'section_recaptcha', array(
105
+ 'recaptcha_public_key'
106
+ ) );
107
+ add_settings_field( 'recaptcha_private_key', esc_html__( 'reCAPTCHA Private Key :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
108
+ $this,
109
+ 'create_fields'
110
+ ), 'contact-form-settings', 'section_recaptcha', array(
111
+ 'recaptcha_private_key'
112
+ ) );
113
+ add_settings_section( 'section_message', '<h3>' . esc_html__( 'Message Settings', 'clean-and-simple-contact-form-by-meg-nicholas' ) . '</h3>', array(
114
+ $this,
115
+ 'print_section_info_message'
116
+ ), 'contact-form-settings' );
117
+ add_settings_field( 'recipient_emails', esc_html__( 'Recipient Emails :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
118
+ $this,
119
+ 'create_fields'
120
+ ), 'contact-form-settings', 'section_message', array(
121
+ 'recipient_emails'
122
+ ) );
123
+ add_settings_field( 'confirm-email', esc_html__( 'Confirm Email Address :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
124
+ $this,
125
+ 'create_fields'
126
+ ), 'contact-form-settings', 'section_message', array(
127
+ 'confirm-email'
128
+ ) );
129
+ add_settings_field( 'email-sender', esc_html__( 'Allow users to email themselves a copy :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
130
+ $this,
131
+ 'create_fields'
132
+ ), 'contact-form-settings', 'section_message', array(
133
+ 'email-sender'
134
+ ) );
135
+ add_settings_field( 'contact-consent', '<span style="color:red;">' . esc_html__( '*New*', 'clean-and-simple-contact-form-by-meg-nicholas' ) . '</span> ' . esc_html__( 'Add a consent checkbox :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
136
+ $this,
137
+ 'create_fields'
138
+ ), 'contact-form-settings', 'section_message', array(
139
+ 'contact-consent'
140
+ ) );
141
+ add_settings_field( 'contact-consent-msg', '<span style="color:red;">' . esc_html__( '*New*', 'clean-and-simple-contact-form-by-meg-nicholas' ) . '</span> ' . esc_html__( 'Consent message :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
142
+ $this,
143
+ 'create_fields'
144
+ ), 'contact-form-settings', 'section_message', array(
145
+ 'contact-consent-msg'
146
+ ) );
147
+ add_settings_field( 'override-from', esc_html__( 'Override \'From\' Address :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
148
+ $this,
149
+ 'create_fields'
150
+ ), 'contact-form-settings', 'section_message', array(
151
+ 'override-from'
152
+ ) );
153
+ add_settings_field( 'from-email', esc_html__( '\'From\' Email Address :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
154
+ $this,
155
+ 'create_fields'
156
+ ), 'contact-form-settings', 'section_message', array(
157
+ 'from-email'
158
+ ) );
159
+ add_settings_field( 'subject', esc_html__( 'Email Subject :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
160
+ $this,
161
+ 'create_fields'
162
+ ), 'contact-form-settings', 'section_message', array(
163
+ 'subject'
164
+ ) );
165
+ add_settings_field( 'message', esc_html__( 'Message :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
166
+ $this,
167
+ 'create_fields'
168
+ ), 'contact-form-settings', 'section_message', array(
169
+ 'message'
170
+ ) );
171
+ add_settings_field( 'sent_message_heading', esc_html__( 'Message Sent Heading :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
172
+ $this,
173
+ 'create_fields'
174
+ ), 'contact-form-settings', 'section_message', array(
175
+ 'sent_message_heading'
176
+ ) );
177
+ add_settings_field( 'sent_message_body', esc_html__( 'Message Sent Content :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
178
+ $this,
179
+ 'create_fields'
180
+ ), 'contact-form-settings', 'section_message', array(
181
+ 'sent_message_body'
182
+ ) );
183
+ add_settings_section( 'section_styling', '<h3>' . esc_html__( 'Styling and Validation', 'clean-and-simple-contact-form-by-meg-nicholas' ) . '</h3>', array(
184
+ $this,
185
+ 'print_section_info_styling'
186
+ ), 'contact-form-settings' );
187
+ add_settings_field( 'load_stylesheet', esc_html__( 'Use the plugin default stylesheet (un-tick to use your theme style sheet instead) :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
188
+ $this,
189
+ 'create_fields'
190
+ ), 'contact-form-settings', 'section_styling', array(
191
+ 'load_stylesheet'
192
+ ) );
193
+ add_settings_field( 'use_client_validation', esc_html__( 'Use client side validation (AJAX) :', 'clean-and-simple-contact-form-by-meg-nicholas' ), array(
194
+ $this,
195
+ 'create_fields'
196
+ ), 'contact-form-settings', 'section_styling', array(
197
+ 'use_client_validation'
198
+ ) );
199
+ }
200
+
201
+ public function check_form(
202
+ $input
203
+ ) {
204
+
205
+ //recaptcha theme
206
+ if ( isset( $input['theme'] ) ) {
207
+ $input['theme'] = sanitize_text_field( $input['theme'] );
208
+ }
209
+
210
+ //recaptcha_public_key
211
+ if ( isset( $input['recaptcha_public_key'] ) ) {
212
+ $input['recaptcha_public_key'] = sanitize_text_field( $input['recaptcha_public_key'] );
213
+ }
214
+
215
+ //recaptcha_private_key
216
+ if ( isset( $input['recaptcha_private_key'] ) ) {
217
+ $input['recaptcha_private_key'] = sanitize_text_field( $input['recaptcha_private_key'] );
218
+ }
219
+
220
+ //sent_message_heading
221
+ $input['sent_message_heading'] = sanitize_text_field( $input['sent_message_heading'] );
222
+
223
+ //sent_message_body
224
+ $input['sent_message_body'] = sanitize_text_field( $input['sent_message_body'] );
225
+
226
+ //message
227
+ $input['message'] = sanitize_textarea_field( $input['message'] );
228
+
229
+
230
+ //consent message
231
+ $input['contact-consent-msg'] = sanitize_text_field( $input['contact-consent-msg'] );
232
+
233
+ //recipient_emails
234
+ foreach ( $input['recipient_emails'] as $key => $recipient ) {
235
+ if ( ! filter_var( $input['recipient_emails'][ $key ] ) ) {
236
+ unset( $input['recipient_emails'][ $key ] );
237
+ } else {
238
+ $input['recipient_emails'][ $key ] = sanitize_email( $input['recipient_emails'][ $key ] );
239
+ }
240
+ }
241
+
242
+ //from
243
+ if ( ! filter_var( $input['from-email'], FILTER_VALIDATE_EMAIL ) ) {
244
+ unset( $input['from-email'] );
245
+ } else {
246
+ $input['from-email'] = sanitize_email( $input['from-email'] );
247
+ }
248
+
249
+ //subject
250
+ $input['subject'] = trim( sanitize_text_field( $input['subject'] ) );
251
+ if ( empty( $input['subject'] ) ) {
252
+ unset( $input['subject'] );
253
+ }
254
+
255
+ if ( isset( $_POST['add_recipient'] ) ) {
256
+ $input['recipient_emails'][] = "";
257
+ }
258
+
259
+ if ( isset( $_POST['remove_recipient'] ) ) {
260
+ foreach ( $_POST['remove_recipient'] as $key => $element ) {
261
+ unset( $input['recipient_emails'][ $key ] );
262
+ }
263
+ }
264
+
265
+ //tidy up the keys
266
+ $tidiedRecipients = array();
267
+ foreach ( $input['recipient_emails'] as $recipient ) {
268
+ $tidiedRecipients[] = $recipient;
269
+ }
270
+ $input['recipient_emails'] = $tidiedRecipients;
271
+
272
+
273
+ return $input;
274
+ }
275
+
276
+ public function print_section_info_recaptcha() {
277
+ print esc_html__( 'Enter your reCAPTCHA settings below :', 'clean-and-simple-contact-form-by-meg-nicholas' );
278
+ print "<p>" . esc_html__( 'To use reCAPTCHA you must get an API key from', 'clean-and-simple-contact-form-by-meg-nicholas' ) . " <a target='_blank' href='" . csf_RecaptchaV2::$signUpUrl . "'>Google reCAPTCHA</a></p>";
279
+ }
280
+
281
+ public function print_section_info_message() {
282
+ print esc_html__( 'Enter your message settings below :', 'clean-and-simple-contact-form-by-meg-nicholas' );
283
+ }
284
+
285
+ public function print_section_info_styling() {
286
+
287
+ //print 'Enter your styling settings below:';
288
+
289
+ }
290
+
291
+ public function create_fields(
292
+ $args
293
+ ) {
294
+ $fieldname = $args[0];
295
+
296
+ switch ( $fieldname ) {
297
+ case 'use_recaptcha':
298
+ $checked = cscf_PluginSettings::UseRecaptcha() === true ? 'checked' : '';
299
+ ?><input type="checkbox" <?php echo esc_attr( $checked ); ?> id="use_recaptcha"
300
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[use_recaptcha]"><?php
301
+ break;
302
+ case 'load_stylesheet':
303
+ $checked = cscf_PluginSettings::LoadStyleSheet() === true ? 'checked' : '';
304
+ ?><input type="checkbox" <?php echo esc_attr( $checked ); ?> id="load_stylesheet"
305
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[load_stylesheet]"><?php
306
+ break;
307
+ case 'recaptcha_public_key':
308
+ $disabled = cscf_PluginSettings::UseRecaptcha() === false ? 'readonly' : '';
309
+ ?><input <?php echo esc_attr( $disabled ); ?> type="text" size="60" id="recaptcha_public_key"
310
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[recaptcha_public_key]"
311
+ value="<?php echo esc_attr( cscf_PluginSettings::PublicKey() ); ?>" /><?php
312
+ break;
313
+ case 'recaptcha_private_key':
314
+ $disabled = cscf_PluginSettings::UseRecaptcha() === false ? 'readonly' : '';
315
+ ?><input <?php echo esc_attr( $disabled ); ?> type="text" size="60" id="recaptcha_private_key"
316
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[recaptcha_private_key]"
317
+ value="<?php echo esc_attr( cscf_PluginSettings::PrivateKey() ); ?>" /><?php
318
+ break;
319
+ case 'recipient_emails':
320
+ ?>
321
+ <ul id="recipients"><?php
322
+ foreach ( cscf_PluginSettings::RecipientEmails() as $key => $recipientEmail ) {
323
+ ?>
324
+ <li class="recipient_email" data-element="<?php echo esc_attr($key); ?>">
325
+ <input class="enter_recipient" type="email" size="50"
326
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[recipient_emails][<?php echo esc_attr($key) ?>]"
327
+ value="<?php echo esc_attr( $recipientEmail ); ?>"/>
328
+ <input class="add_recipient" title="Add New Recipient" type="submit" name="add_recipient"
329
+ value="+">
330
+ <input class="remove_recipient" title="Remove This Recipient" type="submit"
331
+ name="remove_recipient[<?php echo esc_attr( $key ); ?>]" value="-">
332
+ </li>
333
+
334
+ <?php
335
+ }
336
+ ?></ul><?php
337
+ break;
338
+ case 'confirm-email':
339
+ $checked = cscf_PluginSettings::ConfirmEmail() == true ? "checked" : "";
340
+ ?><input type="checkbox" <?php echo esc_attr( $checked ); ?> id="confirm-email"
341
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[confirm-email]"><?php
342
+ break;
343
+ case 'override-from':
344
+ $checked = cscf_PluginSettings::OverrideFrom() == true ? "checked" : "";
345
+ ?><input type="checkbox" <?php echo esc_attr( $checked ); ?> id="override-from"
346
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[override-from]"><?php
347
+ break;
348
+ case 'email-sender':
349
+ $checked = cscf_PluginSettings::EmailToSender() == true ? "checked" : "";
350
+ ?><input type="checkbox" <?php echo esc_attr( $checked ); ?> id="email-sender"
351
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[email-sender]"><?php
352
+ break;
353
+ case 'contact-consent':
354
+ $checked = cscf_PluginSettings::ContactConsent() == true ? "checked" : "";
355
+ ?><input type="checkbox" <?php echo esc_attr( $checked ); ?> id="contact-consent"
356
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[contact-consent]"><?php
357
+ break;
358
+ case 'contact-consent-msg':
359
+ ?><input type="text" size="60" id="contact-consent-msg"
360
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[contact-consent-msg]"
361
+ value="<?php echo esc_attr( cscf_PluginSettings::ContactConsentMsg() ); ?>"><?php
362
+ break;
363
+ case 'from-email':
364
+ $disabled = cscf_PluginSettings::OverrideFrom() === false ? "readonly" : "";
365
+ ?><input <?php echo esc_attr($disabled); ?> type="text" size="60" id="from-email"
366
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[from-email]"
367
+ value="<?php echo esc_attr( cscf_PluginSettings::FromEmail() ); ?>" /><?php
368
+ break;
369
+ case 'subject':
370
+ ?><input type="text" size="60" id="subject" name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[subject]"
371
+ value="<?php echo esc_attr( cscf_PluginSettings::Subject() ); ?>" /><?php
372
+ break;
373
+ case 'sent_message_heading':
374
+ ?><input type="text" size="60" id="sent_message_heading"
375
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[sent_message_heading]"
376
+ value="<?php echo esc_attr( cscf_PluginSettings::SentMessageHeading() ); ?>" /><?php
377
+ break;
378
+ case 'sent_message_body':
379
+ ?><textarea cols="63" rows="8"
380
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[sent_message_body]"><?php echo esc_attr( cscf_PluginSettings::SentMessageBody() ); ?></textarea><?php
381
+ break;
382
+ case 'message':
383
+ ?><textarea cols="63" rows="8"
384
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[message]"><?php echo esc_attr( cscf_PluginSettings::Message() ); ?></textarea><?php
385
+ break;
386
+ case 'theme':
387
+ $theme = cscf_PluginSettings::Theme();
388
+ $disabled = cscf_PluginSettings::UseRecaptcha() == false ? "disabled" : "";
389
+ ?>
390
+ <select <?php echo esc_attr($disabled); ?> id="theme" name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[theme]">
391
+ <option <?php echo ( 'light' == $theme ) ? 'selected' : ''; ?>
392
+ value="light"><?php esc_html_e( 'Light', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></option>
393
+ <option <?php echo ( 'dark' == $theme ) ? 'selected' : ''; ?>
394
+ value="dark"><?php esc_html_e( 'Dark', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></option>
395
+ </select>
396
+ <?php
397
+ break;
398
+ case 'use_client_validation':
399
+ $checked = cscf_PluginSettings::UseClientValidation() == true ? "checked" : "";
400
+ ?><input type="checkbox" <?php echo esc_attr( $checked ); ?> id="use_client_validation"
401
+ name="<?php echo esc_attr( CSCF_OPTIONS_KEY ); ?>[use_client_validation]"><?php
402
+ break;
403
+ default:
404
+ break;
405
+ }
406
+ }
407
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
class.view.php CHANGED
@@ -1,49 +1,48 @@
1
  <?php
2
 
3
- class CSCF_View
4
- {
5
- /**
6
- * Path of the view to render
7
- */
8
- var $view = "";
9
- /**
10
- * Variables for the view
11
- */
12
- var $vars = array();
13
- /**
14
- * Construct a view from a file in the
15
- */
16
- public
17
- function __construct($view)
18
- {
19
-
20
- if (file_exists(CSCF_PLUGIN_DIR . "/views/" . $view . ".view.php"))
21
- {
22
- $this->view = CSCF_PLUGIN_DIR . "/views/" . $view . ".view.php";
23
- }
24
- else
25
- {
26
- wp_die(__("View " . CSCF_PLUGIN_URL . "/views/" . $view . ".view.php" . " not found"));
27
- }
28
- }
29
- /**
30
- * set a variable which gets rendered in the view
31
- */
32
- public
33
- function Set($name, $value)
34
- {
35
- $this->vars[$name] = $value;
36
- }
37
- /**
38
- * render the view
39
- */
40
- public
41
- function Render()
42
- {
43
- extract($this->vars, EXTR_SKIP);
44
- ob_start();
45
- include $this->view;
46
- return str_replace(array("\n", "\r"), "", ob_get_clean());
47
- }
48
  }
49
 
1
  <?php
2
 
3
+ class CSCF_View {
4
+ /**
5
+ * Path of the view to render
6
+ */
7
+ var $view = '';
8
+ /**
9
+ * Variables for the view
10
+ */
11
+ var $vars = array();
12
+
13
+ /**
14
+ * Construct a view from a file in the
15
+ */
16
+ public
17
+ function __construct(
18
+ $view
19
+ ) {
20
+
21
+ if ( file_exists( CSCF_PLUGIN_DIR . '/views/' . $view . '.view.php' ) ) {
22
+ $this->view = CSCF_PLUGIN_DIR . '/views/' . $view . '.view.php';
23
+ } else {
24
+ wp_die( esc_html__( 'View ' . CSCF_PLUGIN_URL . '/views/' . $view . '.view.php' . ' not found' ) );
25
+ }
26
+ }
27
+
28
+ /**
29
+ * set a variable which gets rendered in the view
30
+ */
31
+ public function Set(
32
+ $name, $value
33
+ ) {
34
+ $this->vars[ $name ] = $value;
35
+ }
36
+
37
+ /**
38
+ * render the view
39
+ */
40
+ public function Render() {
41
+ extract( $this->vars, EXTR_SKIP );
42
+ ob_start();
43
+ include $this->view;
44
+
45
+ return str_replace( array( '\n', '\r' ), '', ob_get_clean() );
46
+ }
 
47
  }
48
 
clean-and-simple-contact-form-by-meg-nicholas.php CHANGED
@@ -1,79 +1,99 @@
1
- <?php
2
- /**
3
- * @package Clean and Simple Contact Form
4
- */
5
-
6
- /*
7
- Plugin Name: Clean and Simple Contact Form
8
- Plugin URI: http://www.megnicholas.co.uk/wordpress-plugins/clean-and-simple-contact-form
9
- Description: A clean and simple contact form with Google reCAPTCHA and Twitter Bootstrap markup.
10
- Version: 4.7.1
11
- Author: Meghan Nicholas
12
- Author URI: http://www.megnicholas.co.uk
13
- License: GPLv2 or later
14
- Text Domain: clean-and-simple-contact-form-by-meg-nicholas
15
- Domain Path: /languages
16
- */
17
-
18
- /*
19
- This program is free software; you can redistribute it and/or
20
- modify it under the terms of the GNU General Public License
21
- as published by the Free Software Foundation; either version 2
22
- of the License, or (at your option) any later version.
23
-
24
- This program is distributed in the hope that it will be useful,
25
- but WITHOUT ANY WARRANTY; without even the implied warranty of
26
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27
- GNU General Public License for more details.
28
-
29
- You should have received a copy of the GNU General Public License
30
- along with this program; if not, write to the Free Software
31
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
32
- */
33
-
34
- /*
35
- * @package Main
36
- */
37
- include ('shortcodes/contact-form.php');
38
- include ('class.cscf.php');
39
- include ('class.cscf_pluginsettings.php');
40
- include ('class.cscf_settings.php');
41
- include ('class.cscf_contact.php');
42
- include ('class.view.php');
43
- include ('class.cscf_filters.php');
44
- include ('ajax.php');
45
- include ('recaptchav2.php');
46
-
47
- if (!defined('CSCF_THEME_DIR')) define('CSCF_THEME_DIR', ABSPATH . 'wp-content/themes/' . get_template());
48
-
49
- if (!defined('CSCF_PLUGIN_NAME')) define('CSCF_PLUGIN_NAME', 'clean-and-simple-contact-form-by-meg-nicholas');
50
-
51
- if (!defined('CSCF_PLUGIN_DIR')) define('CSCF_PLUGIN_DIR', WP_PLUGIN_DIR . '/' . CSCF_PLUGIN_NAME);
52
-
53
- if (!defined('CSCF_PLUGIN_URL')) define('CSCF_PLUGIN_URL', WP_PLUGIN_URL . '/' . CSCF_PLUGIN_NAME);
54
-
55
- if (!defined('CSCF_VERSION_KEY')) define('CSCF_VERSION_KEY', 'cscf_version');
56
-
57
- if (!defined('CSCF_VERSION_NUM')) define('CSCF_VERSION_NUM', '4.7.1');
58
-
59
- if (!defined('CSCF_OPTIONS_KEY')) define('CSCF_OPTIONS_KEY', 'cscf_options');
60
-
61
- $cscf = new cscf();
62
-
63
- /*get the current version and update options to the new option*/
64
- $oldVersion = get_option(CSCF_VERSION_KEY);
65
- update_option(CSCF_VERSION_KEY, CSCF_VERSION_NUM);
66
-
67
- /*If this is a new installation then set some defaults*/
68
- if ( $oldVersion == false ) {
69
- $options = get_option(CSCF_OPTIONS_KEY);
70
- $options['use_client_validation'] = true;
71
- $options['load_stylesheet'] = true;
72
- $options['confirm-email'] = true;
73
- update_option(CSCF_OPTIONS_KEY,$options);
74
- }
75
-
76
- /*if necessary do an upgrade*/
77
- if ($oldVersion < CSCF_VERSION_NUM) {
78
- $cscf->Upgrade($oldVersion);
79
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @package Clean and Simple Contact Form
4
+ */
5
+
6
+ /*
7
+ Plugin Name: Clean and Simple Contact Form
8
+ Plugin URI: https://fullworks.net/productsclean-and-simple-contact-form
9
+ Description: A clean and simple contact form with Google reCAPTCHA and Twitter Bootstrap markup.
10
+ Version: 4.7.2
11
+ Author: Fullworks
12
+ Author URI: https://fullworks.net
13
+ License: GPLv2 or later
14
+ Text Domain: clean-and-simple-contact-form
15
+ Domain Path: /languages
16
+ */
17
+
18
+ /*
19
+ All code up to version 4.7.1 is attributed to
20
+ Author: Meghan Nicholas
21
+ Author URI: http://www.megnicholas.com
22
+ */
23
+
24
+ /*
25
+ This program is free software; you can redistribute it and/or
26
+ modify it under the terms of the GNU General Public License
27
+ as published by the Free Software Foundation; either version 2
28
+ of the License, or (at your option) any later version.
29
+
30
+ This program is distributed in the hope that it will be useful,
31
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
32
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
33
+ GNU General Public License for more details.
34
+
35
+ You should have received a copy of the GNU General Public License
36
+ along with this program; if not, write to the Free Software
37
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
38
+ */
39
+
40
+ /*
41
+ * @package Main
42
+ */
43
+ require 'shortcodes/contact-form.php';
44
+ require 'class.cscf.php';
45
+ require 'class.cscf_pluginsettings.php';
46
+ require 'class.cscf_settings.php';
47
+ require 'class.cscf_contact.php';
48
+ require 'class.view.php';
49
+ require 'class.cscf_filters.php';
50
+ require 'ajax.php';
51
+ require 'recaptchav2.php';
52
+
53
+ if ( ! defined( 'CSCF_THEME_DIR' ) ) {
54
+ define( 'CSCF_THEME_DIR', ABSPATH . 'wp-content/themes/' . get_template() );
55
+ }
56
+
57
+ if ( ! defined( 'CSCF_PLUGIN_NAME' ) ) {
58
+ define( 'CSCF_PLUGIN_NAME', 'clean-and-simple-contact-form-by-meg-nicholas' );
59
+ }
60
+
61
+ if ( ! defined( 'CSCF_PLUGIN_DIR' ) ) {
62
+ define( 'CSCF_PLUGIN_DIR', WP_PLUGIN_DIR . '/' . CSCF_PLUGIN_NAME );
63
+ }
64
+
65
+ if ( ! defined( 'CSCF_PLUGIN_URL' ) ) {
66
+ define( 'CSCF_PLUGIN_URL', WP_PLUGIN_URL . '/' . CSCF_PLUGIN_NAME );
67
+ }
68
+
69
+ if ( ! defined( 'CSCF_VERSION_KEY' ) ) {
70
+ define( 'CSCF_VERSION_KEY', 'cscf_version' );
71
+ }
72
+
73
+ if ( ! defined( 'CSCF_VERSION_NUM' ) ) {
74
+ define( 'CSCF_VERSION_NUM', '4.7.2' );
75
+ }
76
+
77
+ if ( ! defined( 'CSCF_OPTIONS_KEY' ) ) {
78
+ define( 'CSCF_OPTIONS_KEY', 'cscf_options' );
79
+ }
80
+
81
+ $cscf = new cscf();
82
+
83
+ /*get the current version and update options to the new option*/
84
+ $old_version = get_option( CSCF_VERSION_KEY );
85
+ update_option( CSCF_VERSION_KEY, CSCF_VERSION_NUM );
86
+
87
+ /*If this is a new installation then set some defaults*/
88
+ if ( false == $old_version ) {
89
+ $options = get_option( CSCF_OPTIONS_KEY );
90
+ $options['use_client_validation'] = true;
91
+ $options['load_stylesheet'] = true;
92
+ $options['confirm-email'] = true;
93
+ update_option( CSCF_OPTIONS_KEY, $options );
94
+ }
95
+
96
+ /*if necessary do an upgrade*/
97
+ if ( $old_version < CSCF_VERSION_NUM ) {
98
+ $cscf->Upgrade( $old_version );
99
+ }
images/managewp.png DELETED
Binary file
js/jquery.validate.js CHANGED
@@ -1,14 +1,27 @@
1
- /*! jQuery Validation Plugin - v1.11.0 - 7/13/2013
2
- * https://github.com/jzaefferer/jquery-validation
3
- * Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
- (function($) {
6
 
7
- $.extend($.fn, {
8
- // http://docs.jquery.com/Plugins/Validation/validate
9
  validate: function( options ) {
10
 
11
- // if nothing is selected, return nothing; can't chain anyway
12
  if ( !this.length ) {
13
  if ( options && options.debug && window.console ) {
14
  console.warn( "Nothing selected, can't validate, returning nothing." );
@@ -16,8 +29,8 @@ $.extend($.fn, {
16
  return;
17
  }
18
 
19
- // check if a validator for this form was already created
20
- var validator = $.data( this[0], "validator" );
21
  if ( validator ) {
22
  return validator;
23
  }
@@ -25,45 +38,67 @@ $.extend($.fn, {
25
  // Add novalidate tag if HTML5.
26
  this.attr( "novalidate", "novalidate" );
27
 
28
- validator = new $.validator( options, this[0] );
29
- $.data( this[0], "validator", validator );
30
 
31
  if ( validator.settings.onsubmit ) {
32
 
33
- this.validateDelegate( ":submit", "click", function( event ) {
34
- if ( validator.settings.submitHandler ) {
35
- validator.submitButton = event.target;
 
 
 
 
 
 
36
  }
37
- // allow suppressing validation by adding a cancel class to the submit button
38
- if ( $(event.target).hasClass("cancel") ) {
 
39
  validator.cancelSubmit = true;
40
  }
41
- });
42
 
43
- // validate the form on submit
44
- this.submit( function( event ) {
45
  if ( validator.settings.debug ) {
46
- // prevent form submit to be able to see console output
 
47
  event.preventDefault();
48
  }
 
49
  function handle() {
50
- var hidden;
51
- if ( validator.settings.submitHandler ) {
52
- if ( validator.submitButton ) {
53
- // insert a hidden input as a replacement for the missing submit button
54
- hidden = $("<input type='hidden'/>").attr("name", validator.submitButton.name).val(validator.submitButton.value).appendTo(validator.currentForm);
55
- }
56
- validator.settings.submitHandler.call( validator, validator.currentForm, event );
57
- if ( validator.submitButton ) {
58
- // and clean up afterwards; thanks to no-block-scope, hidden can be referenced
 
 
 
 
 
 
 
 
 
 
59
  hidden.remove();
60
  }
 
 
 
61
  return false;
62
  }
63
  return true;
64
  }
65
 
66
- // prevent submit for invalid forms or custom submit handlers
67
  if ( validator.cancelSubmit ) {
68
  validator.cancelSubmit = false;
69
  return handle();
@@ -78,188 +113,257 @@ $.extend($.fn, {
78
  validator.focusInvalid();
79
  return false;
80
  }
81
- });
82
  }
83
 
84
  return validator;
85
  },
86
- // http://docs.jquery.com/Plugins/Validation/valid
 
87
  valid: function() {
88
- if ( $(this[0]).is("form")) {
89
- return this.validate().form();
 
 
90
  } else {
91
- var valid = true;
92
- var validator = $(this[0].form).validate();
93
- this.each(function() {
94
- valid &= validator.element(this);
95
- });
96
- return valid;
 
 
 
 
97
  }
 
98
  },
99
- // attributes: space seperated list of attributes to retrieve and remove
100
- removeAttrs: function( attributes ) {
101
- var result = {},
102
- $element = this;
103
- $.each(attributes.split(/\s/), function( index, value ) {
104
- result[value] = $element.attr(value);
105
- $element.removeAttr(value);
106
- });
107
- return result;
108
- },
109
- // http://docs.jquery.com/Plugins/Validation/rules
110
  rules: function( command, argument ) {
111
- var element = this[0];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
 
113
  if ( command ) {
114
- var settings = $.data(element.form, "validator").settings;
115
- var staticRules = settings.rules;
116
- var existingRules = $.validator.staticRules(element);
117
- switch(command) {
118
  case "add":
119
- $.extend(existingRules, $.validator.normalizeRule(argument));
120
- staticRules[element.name] = existingRules;
 
 
 
121
  if ( argument.messages ) {
122
- settings.messages[element.name] = $.extend( settings.messages[element.name], argument.messages );
123
  }
124
  break;
125
  case "remove":
126
  if ( !argument ) {
127
- delete staticRules[element.name];
128
  return existingRules;
129
  }
130
- var filtered = {};
131
- $.each(argument.split(/\s/), function( index, method ) {
132
- filtered[method] = existingRules[method];
133
- delete existingRules[method];
134
- });
135
  return filtered;
136
  }
137
  }
138
 
139
- var data = $.validator.normalizeRules(
140
  $.extend(
141
  {},
142
- $.validator.classRules(element),
143
- $.validator.attributeRules(element),
144
- $.validator.dataRules(element),
145
- $.validator.staticRules(element)
146
- ), element);
147
 
148
- // make sure required is at front
149
  if ( data.required ) {
150
- var param = data.required;
151
  delete data.required;
152
- data = $.extend({required: param}, data);
 
 
 
 
 
 
 
153
  }
154
 
155
  return data;
156
  }
157
- });
 
 
 
 
 
 
 
158
 
159
  // Custom selectors
160
- $.extend($.expr[":"], {
161
- // http://docs.jquery.com/Plugins/Validation/blank
162
- blank: function( a ) { return !$.trim("" + a.value); },
163
- // http://docs.jquery.com/Plugins/Validation/filled
164
- filled: function( a ) { return !!$.trim("" + a.value); },
165
- // http://docs.jquery.com/Plugins/Validation/unchecked
166
- unchecked: function( a ) { return !a.checked; }
167
- });
168
-
169
- // constructor for validator
 
 
 
 
 
 
 
 
 
 
170
  $.validator = function( options, form ) {
171
  this.settings = $.extend( true, {}, $.validator.defaults, options );
172
  this.currentForm = form;
173
  this.init();
174
  };
175
 
 
176
  $.validator.format = function( source, params ) {
177
  if ( arguments.length === 1 ) {
178
  return function() {
179
- var args = $.makeArray(arguments);
180
- args.unshift(source);
181
  return $.validator.format.apply( this, args );
182
  };
183
  }
 
 
 
184
  if ( arguments.length > 2 && params.constructor !== Array ) {
185
- params = $.makeArray(arguments).slice(1);
186
  }
187
  if ( params.constructor !== Array ) {
188
  params = [ params ];
189
  }
190
- $.each(params, function( i, n ) {
191
- source = source.replace( new RegExp("\\{" + i + "\\}", "g"), function() {
192
  return n;
193
- });
194
- });
195
  return source;
196
  };
197
 
198
- $.extend($.validator, {
199
 
200
  defaults: {
201
  messages: {},
202
  groups: {},
203
  rules: {},
204
  errorClass: "error",
 
205
  validClass: "valid",
206
  errorElement: "label",
 
207
  focusInvalid: true,
208
- errorContainer: $([]),
209
- errorLabelContainer: $([]),
210
  onsubmit: true,
211
  ignore: ":hidden",
212
  ignoreTitle: false,
213
- onfocusin: function( element, event ) {
214
  this.lastActive = element;
215
 
216
- // hide error label and remove error class on focus if enabled
217
- if ( this.settings.focusCleanup && !this.blockFocusCleanup ) {
218
  if ( this.settings.unhighlight ) {
219
  this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
220
  }
221
- this.addWrapper(this.errorsFor(element)).hide();
222
  }
223
  },
224
- onfocusout: function( element, event ) {
225
- if ( !this.checkable(element) && (element.name in this.submitted || !this.optional(element)) ) {
226
- this.element(element);
227
  }
228
  },
229
  onkeyup: function( element, event ) {
230
- if ( event.which === 9 && this.elementValue(element) === "" ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  return;
232
- } else if ( element.name in this.submitted || element === this.lastElement ) {
233
- this.element(element);
234
  }
235
  },
236
- onclick: function( element, event ) {
237
- // click on selects, radiobuttons and checkboxes
 
238
  if ( element.name in this.submitted ) {
239
- this.element(element);
240
- }
241
- // or option elements, check parent select in that case
242
- else if ( element.parentNode.name in this.submitted ) {
243
- this.element(element.parentNode);
244
  }
245
  },
246
  highlight: function( element, errorClass, validClass ) {
247
  if ( element.type === "radio" ) {
248
- this.findByName(element.name).addClass(errorClass).removeClass(validClass);
249
  } else {
250
- $(element).addClass(errorClass).removeClass(validClass);
251
  }
252
  },
253
  unhighlight: function( element, errorClass, validClass ) {
254
  if ( element.type === "radio" ) {
255
- this.findByName(element.name).removeClass(errorClass).addClass(validClass);
256
  } else {
257
- $(element).removeClass(errorClass).addClass(validClass);
258
  }
259
  }
260
  },
261
 
262
- // http://docs.jquery.com/Plugins/Validation/Validator/setDefaults
263
  setDefaults: function( settings ) {
264
  $.extend( $.validator.defaults, settings );
265
  },
@@ -273,14 +377,14 @@ $.extend($.validator, {
273
  dateISO: "Please enter a valid date (ISO).",
274
  number: "Please enter a valid number.",
275
  digits: "Please enter only digits.",
276
- creditcard: "Please enter a valid credit card number.",
277
  equalTo: "Please enter the same value again.",
278
- maxlength: $.validator.format("Please enter no more than {0} characters."),
279
- minlength: $.validator.format("Please enter at least {0} characters."),
280
- rangelength: $.validator.format("Please enter a value between {0} and {1} characters long."),
281
- range: $.validator.format("Please enter a value between {0} and {1}."),
282
- max: $.validator.format("Please enter a value less than or equal to {0}."),
283
- min: $.validator.format("Please enter a value greater than or equal to {0}.")
 
284
  },
285
 
286
  autoCreateRanges: false,
@@ -288,9 +392,9 @@ $.extend($.validator, {
288
  prototype: {
289
 
290
  init: function() {
291
- this.labelContainer = $(this.settings.errorLabelContainer);
292
- this.errorContext = this.labelContainer.length && this.labelContainer || $(this.currentForm);
293
- this.containers = $(this.settings.errorContainer).add( this.settings.errorLabelContainer );
294
  this.submitted = {};
295
  this.valueCache = {};
296
  this.pendingRequest = 0;
@@ -298,48 +402,68 @@ $.extend($.validator, {
298
  this.invalid = {};
299
  this.reset();
300
 
301
- var groups = (this.groups = {});
302
- $.each(this.settings.groups, function( key, value ) {
 
 
303
  if ( typeof value === "string" ) {
304
- value = value.split(/\s/);
305
  }
306
- $.each(value, function( index, name ) {
307
- groups[name] = key;
308
- });
309
- });
310
- var rules = this.settings.rules;
311
- $.each(rules, function( key, value ) {
312
- rules[key] = $.validator.normalizeRule(value);
313
- });
314
-
315
- function delegate(event) {
316
- var validator = $.data(this[0].form, "validator"),
317
- eventType = "on" + event.type.replace(/^validate/, "");
318
- if ( validator.settings[eventType] ) {
319
- validator.settings[eventType].call(validator, this[0], event);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
320
  }
321
  }
322
- $(this.currentForm)
323
- .validateDelegate(":text, [type='password'], [type='file'], select, textarea, " +
324
- "[type='number'], [type='search'] ,[type='tel'], [type='url'], " +
325
- "[type='email'], [type='datetime'], [type='date'], [type='month'], " +
326
- "[type='week'], [type='time'], [type='datetime-local'], " +
327
- "[type='range'], [type='color'] ",
328
- "focusin focusout keyup", delegate)
329
- .validateDelegate("[type='radio'], [type='checkbox'], select, option", "click", delegate);
 
 
 
330
 
331
  if ( this.settings.invalidHandler ) {
332
- $(this.currentForm).bind("invalid-form.validate", this.settings.invalidHandler);
333
  }
334
  },
335
 
336
- // http://docs.jquery.com/Plugins/Validation/Validator/form
337
  form: function() {
338
  this.checkForm();
339
- $.extend(this.submitted, this.errorMap);
340
- this.invalid = $.extend({}, this.errorMap);
341
  if ( !this.valid() ) {
342
- $(this.currentForm).triggerHandler("invalid-form", [this]);
343
  }
344
  this.showErrors();
345
  return this.valid();
@@ -347,48 +471,81 @@ $.extend($.validator, {
347
 
348
  checkForm: function() {
349
  this.prepareForm();
350
- for ( var i = 0, elements = (this.currentElements = this.elements()); elements[i]; i++ ) {
351
- this.check( elements[i] );
352
  }
353
  return this.valid();
354
  },
355
 
356
- // http://docs.jquery.com/Plugins/Validation/Validator/element
357
  element: function( element ) {
358
- element = this.validationTargetFor( this.clean( element ) );
359
- this.lastElement = element;
360
- this.prepareElement( element );
361
- this.currentElements = $(element);
362
- var result = this.check( element ) !== false;
363
- if ( result ) {
364
- delete this.invalid[element.name];
 
365
  } else {
366
- this.invalid[element.name] = true;
367
- }
368
- if ( !this.numberOfInvalids() ) {
369
- // Hide error containers on last error
370
- this.toHide = this.toHide.add( this.containers );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
371
  }
372
- this.showErrors();
373
  return result;
374
  },
375
 
376
- // http://docs.jquery.com/Plugins/Validation/Validator/showErrors
377
  showErrors: function( errors ) {
378
  if ( errors ) {
379
- // add items to error list and map
 
 
380
  $.extend( this.errorMap, errors );
381
- this.errorList = [];
382
- for ( var name in errors ) {
383
- this.errorList.push({
384
- message: errors[name],
385
- element: this.findByName(name)[0]
386
- });
387
- }
388
- // remove items from success list
389
  this.successList = $.grep( this.successList, function( element ) {
390
- return !(element.name in errors);
391
- });
392
  }
393
  if ( this.settings.showErrors ) {
394
  this.settings.showErrors.call( this, this.errorMap, this.errorList );
@@ -397,32 +554,64 @@ $.extend($.validator, {
397
  }
398
  },
399
 
400
- // http://docs.jquery.com/Plugins/Validation/Validator/resetForm
401
  resetForm: function() {
402
  if ( $.fn.resetForm ) {
403
- $(this.currentForm).resetForm();
404
  }
 
405
  this.submitted = {};
406
- this.lastElement = null;
407
  this.prepareForm();
408
  this.hideErrors();
409
- this.elements().removeClass( this.settings.errorClass ).removeData( "previousValue" );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
410
  },
411
 
412
  numberOfInvalids: function() {
413
- return this.objectLength(this.invalid);
414
  },
415
 
416
  objectLength: function( obj ) {
417
- var count = 0;
418
- for ( var i in obj ) {
419
- count++;
 
 
 
 
 
 
 
420
  }
421
  return count;
422
  },
423
 
424
  hideErrors: function() {
425
- this.addWrapper( this.toHide ).hide();
 
 
 
 
 
426
  },
427
 
428
  valid: function() {
@@ -436,64 +625,84 @@ $.extend($.validator, {
436
  focusInvalid: function() {
437
  if ( this.settings.focusInvalid ) {
438
  try {
439
- $(this.findLastActive() || this.errorList.length && this.errorList[0].element || [])
440
- .filter(":visible")
441
- .focus()
442
- // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
443
- .trigger("focusin");
444
- } catch(e) {
445
- // ignore IE throwing errors when focusing hidden elements
 
 
446
  }
447
  }
448
  },
449
 
450
  findLastActive: function() {
451
  var lastActive = this.lastActive;
452
- return lastActive && $.grep(this.errorList, function( n ) {
453
  return n.element.name === lastActive.name;
454
- }).length === 1 && lastActive;
455
  },
456
 
457
  elements: function() {
458
  var validator = this,
459
  rulesCache = {};
460
 
461
- // select all valid inputs inside the form (no submit or reset buttons)
462
- return $(this.currentForm)
463
- .find("input, select, textarea")
464
- .not(":submit, :reset, :image, [disabled]")
465
  .not( this.settings.ignore )
466
- .filter(function() {
467
- if ( !this.name && validator.settings.debug && window.console ) {
468
- console.error( "%o has no name assigned", this);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
469
  }
470
 
471
- // select only the first element for each name, and only those with rules specified
472
- if ( this.name in rulesCache || !validator.objectLength($(this).rules()) ) {
473
  return false;
474
  }
475
 
476
- rulesCache[this.name] = true;
477
  return true;
478
- });
479
  },
480
 
481
  clean: function( selector ) {
482
- return $(selector)[0];
483
  },
484
 
485
  errors: function() {
486
- var errorClass = this.settings.errorClass.replace(" ", ".");
487
- return $(this.settings.errorElement + "." + errorClass, this.errorContext);
488
  },
489
 
490
- reset: function() {
491
  this.successList = [];
492
  this.errorList = [];
493
  this.errorMap = {};
494
- this.toShow = $([]);
495
- this.toHide = $([]);
496
- this.currentElements = $([]);
 
 
 
 
497
  },
498
 
499
  prepareForm: function() {
@@ -503,19 +712,53 @@ $.extend($.validator, {
503
 
504
  prepareElement: function( element ) {
505
  this.reset();
506
- this.toHide = this.errorsFor(element);
507
  },
508
 
509
  elementValue: function( element ) {
510
- var type = $(element).attr("type"),
511
- val = $(element).val();
 
 
512
 
513
  if ( type === "radio" || type === "checkbox" ) {
514
- return $("input[name='" + $(element).attr("name") + "']:checked").val();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
515
  }
516
 
517
  if ( typeof val === "string" ) {
518
- return val.replace(/\r/g, "");
519
  }
520
  return val;
521
  },
@@ -523,27 +766,47 @@ $.extend($.validator, {
523
  check: function( element ) {
524
  element = this.validationTargetFor( this.clean( element ) );
525
 
526
- var rules = $(element).rules();
527
- var dependencyMismatch = false;
528
- var val = this.elementValue(element);
529
- var result;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
530
 
531
- for (var method in rules ) {
532
- var rule = { method: method, parameters: rules[method] };
533
- try {
534
 
535
- result = $.validator.methods[method].call( this, val, element, rule.parameters );
 
 
 
536
 
537
- // if a method indicates that the field is optional and therefore valid,
538
  // don't mark it as valid when there are no other rules
539
- if ( result === "dependency-mismatch" ) {
540
  dependencyMismatch = true;
541
  continue;
542
  }
543
  dependencyMismatch = false;
544
 
545
  if ( result === "pending" ) {
546
- this.toHide = this.toHide.not( this.errorsFor(element) );
547
  return;
548
  }
549
 
@@ -551,70 +814,94 @@ $.extend($.validator, {
551
  this.formatAndAdd( element, rule );
552
  return false;
553
  }
554
- } catch(e) {
555
  if ( this.settings.debug && window.console ) {
556
- console.log( "Exception occured when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
557
  }
 
 
 
 
558
  throw e;
559
  }
560
  }
561
  if ( dependencyMismatch ) {
562
  return;
563
  }
564
- if ( this.objectLength(rules) ) {
565
- this.successList.push(element);
566
  }
567
  return true;
568
  },
569
 
570
- // return the custom message for the given element and validation method
571
  // specified in the element's HTML5 data attribute
 
572
  customDataMessage: function( element, method ) {
573
- return $(element).data("msg-" + method.toLowerCase()) || (element.attributes && $(element).attr("data-msg-" + method.toLowerCase()));
 
574
  },
575
 
576
- // return the custom message for the given element name and validation method
577
  customMessage: function( name, method ) {
578
- var m = this.settings.messages[name];
579
- return m && (m.constructor === String ? m : m[method]);
580
  },
581
 
582
- // return the first defined argument, allowing empty strings
583
  findDefined: function() {
584
- for(var i = 0; i < arguments.length; i++) {
585
- if ( arguments[i] !== undefined ) {
586
- return arguments[i];
587
  }
588
  }
589
  return undefined;
590
  },
591
 
592
- defaultMessage: function( element, method ) {
593
- return this.findDefined(
594
- this.customMessage( element.name, method ),
595
- this.customDataMessage( element, method ),
596
- // title is never undefined, so handle empty string as undefined
597
- !this.settings.ignoreTitle && element.title || undefined,
598
- $.validator.messages[method],
599
- "<strong>Warning: No message defined for " + element.name + "</strong>"
600
- );
601
- },
 
 
 
602
 
603
- formatAndAdd: function( element, rule ) {
604
- var message = this.defaultMessage( element, rule.method ),
 
 
 
 
 
 
 
605
  theregex = /\$?\{(\d+)\}/g;
606
  if ( typeof message === "function" ) {
607
- message = message.call(this, rule.parameters, element);
608
- } else if (theregex.test(message)) {
609
- message = $.validator.format(message.replace(theregex, "{$1}"), rule.parameters);
610
  }
611
- this.errorList.push({
 
 
 
 
 
 
 
612
  message: message,
613
- element: element
614
- });
 
615
 
616
- this.errorMap[element.name] = message;
617
- this.submitted[element.name] = message;
618
  },
619
 
620
  addWrapper: function( toToggle ) {
@@ -625,9 +912,9 @@ $.extend($.validator, {
625
  },
626
 
627
  defaultShowErrors: function() {
628
- var i, elements;
629
- for ( i = 0; this.errorList[i]; i++ ) {
630
- var error = this.errorList[i];
631
  if ( this.settings.highlight ) {
632
  this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
633
  }
@@ -637,13 +924,13 @@ $.extend($.validator, {
637
  this.toShow = this.toShow.add( this.containers );
638
  }
639
  if ( this.settings.success ) {
640
- for ( i = 0; this.successList[i]; i++ ) {
641
- this.showLabel( this.successList[i] );
642
  }
643
  }
644
  if ( this.settings.unhighlight ) {
645
- for ( i = 0, elements = this.validElements(); elements[i]; i++ ) {
646
- this.settings.unhighlight.call( this, elements[i], this.settings.errorClass, this.settings.validClass );
647
  }
648
  }
649
  this.toHide = this.toHide.not( this.toShow );
@@ -652,207 +939,332 @@ $.extend($.validator, {
652
  },
653
 
654
  validElements: function() {
655
- return this.currentElements.not(this.invalidElements());
656
  },
657
 
658
  invalidElements: function() {
659
- return $(this.errorList).map(function() {
660
  return this.element;
661
- });
662
  },
663
 
664
  showLabel: function( element, message ) {
665
- var label = this.errorsFor( element );
666
- if ( label.length ) {
667
- // refresh error/success class
668
- label.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
669
- // replace message on existing label
670
- label.html(message);
 
 
 
 
 
 
671
  } else {
672
- // create label
673
- label = $("<" + this.settings.errorElement + ">")
674
- .attr("for", this.idOrName(element))
675
- .addClass(this.settings.errorClass)
676
- .html(message || "");
 
 
 
 
677
  if ( this.settings.wrapper ) {
678
- // make sure the element is visible, even in IE
 
679
  // actually showing the wrapped element is handled elsewhere
680
- label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
681
  }
682
- if ( !this.labelContainer.append(label).length ) {
683
- if ( this.settings.errorPlacement ) {
684
- this.settings.errorPlacement(label, $(element) );
685
- } else {
686
- label.insertAfter(element);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
687
  }
688
  }
689
  }
690
  if ( !message && this.settings.success ) {
691
- label.text("");
692
  if ( typeof this.settings.success === "string" ) {
693
- label.addClass( this.settings.success );
694
  } else {
695
- this.settings.success( label, element );
696
  }
697
  }
698
- this.toShow = this.toShow.add(label);
699
  },
700
 
701
  errorsFor: function( element ) {
702
- var name = this.idOrName(element);
703
- return this.errors().filter(function() {
704
- return $(this).attr("for") === name;
705
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
706
  },
707
 
708
  idOrName: function( element ) {
709
- return this.groups[element.name] || (this.checkable(element) ? element.name : element.id || element.name);
710
  },
711
 
712
  validationTargetFor: function( element ) {
713
- // if radio/checkbox, validate first element in group instead
714
- if ( this.checkable(element) ) {
715
- element = this.findByName( element.name ).not(this.settings.ignore)[0];
 
716
  }
717
- return element;
 
 
718
  },
719
 
720
  checkable: function( element ) {
721
- return (/radio|checkbox/i).test(element.type);
722
  },
723
 
724
  findByName: function( name ) {
725
- return $(this.currentForm).find("[name='" + name + "']");
726
  },
727
 
728
  getLength: function( value, element ) {
729
- switch( element.nodeName.toLowerCase() ) {
730
  case "select":
731
- return $("option:selected", element).length;
732
  case "input":
733
- if ( this.checkable( element) ) {
734
- return this.findByName(element.name).filter(":checked").length;
735
  }
736
  }
737
  return value.length;
738
  },
739
 
740
  depend: function( param, element ) {
741
- return this.dependTypes[typeof param] ? this.dependTypes[typeof param](param, element) : true;
742
  },
743
 
744
  dependTypes: {
745
- "boolean": function( param, element ) {
746
  return param;
747
  },
748
  "string": function( param, element ) {
749
- return !!$(param, element.form).length;
750
  },
751
  "function": function( param, element ) {
752
- return param(element);
753
  }
754
  },
755
 
756
  optional: function( element ) {
757
- var val = this.elementValue(element);
758
- return !$.validator.methods.required.call(this, val, element) && "dependency-mismatch";
759
  },
760
 
761
  startRequest: function( element ) {
762
- if ( !this.pending[element.name] ) {
763
  this.pendingRequest++;
764
- this.pending[element.name] = true;
 
765
  }
766
  },
767
 
768
  stopRequest: function( element, valid ) {
769
  this.pendingRequest--;
770
- // sometimes synchronization fails, make sure pendingRequest is never < 0
 
771
  if ( this.pendingRequest < 0 ) {
772
  this.pendingRequest = 0;
773
  }
774
- delete this.pending[element.name];
 
775
  if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
776
- $(this.currentForm).submit();
 
 
 
 
 
 
 
 
 
777
  this.formSubmitted = false;
778
- } else if (!valid && this.pendingRequest === 0 && this.formSubmitted) {
779
- $(this.currentForm).triggerHandler("invalid-form", [this]);
780
  this.formSubmitted = false;
781
  }
782
  },
783
 
784
- previousValue: function( element ) {
785
- return $.data(element, "previousValue") || $.data(element, "previousValue", {
 
 
786
  old: null,
787
  valid: true,
788
- message: this.defaultMessage( element, "remote" )
789
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
790
  }
791
 
792
  },
793
 
794
  classRuleSettings: {
795
- required: {required: true},
796
- email: {email: true},
797
- url: {url: true},
798
- date: {date: true},
799
- dateISO: {dateISO: true},
800
- number: {number: true},
801
- digits: {digits: true},
802
- creditcard: {creditcard: true}
803
  },
804
 
805
  addClassRules: function( className, rules ) {
806
  if ( className.constructor === String ) {
807
- this.classRuleSettings[className] = rules;
808
  } else {
809
- $.extend(this.classRuleSettings, className);
810
  }
811
  },
812
 
813
  classRules: function( element ) {
814
- var rules = {};
815
- var classes = $(element).attr("class");
 
816
  if ( classes ) {
817
- $.each(classes.split(" "), function() {
818
  if ( this in $.validator.classRuleSettings ) {
819
- $.extend(rules, $.validator.classRuleSettings[this]);
820
  }
821
- });
822
  }
823
  return rules;
824
  },
825
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
826
  attributeRules: function( element ) {
827
- var rules = {};
828
- var $element = $(element);
 
 
829
 
830
- for (var method in $.validator.methods) {
831
- var value;
832
 
833
- // support for <input required> in both html5 and older browsers
834
  if ( method === "required" ) {
835
- value = $element.get(0).getAttribute(method);
 
836
  // Some browsers return an empty string for the required attribute
837
  // and non-HTML5 browsers might have required="" markup
838
  if ( value === "" ) {
839
  value = true;
840
  }
841
- // force non-HTML5 browsers to return bool
 
842
  value = !!value;
843
  } else {
844
- value = $element.attr(method);
845
  }
846
 
847
- if ( value ) {
848
- rules[method] = value;
849
- } else if ( $element[0].getAttribute("type") === method ) {
850
- rules[method] = true;
851
- }
852
  }
853
 
854
- // maxlength may be returned as -1, 2147483647 (IE) and 524288 (safari) for text inputs
855
- if ( rules.maxlength && /-1|2147483647|524288/.test(rules.maxlength) ) {
856
  delete rules.maxlength;
857
  }
858
 
@@ -860,84 +1272,96 @@ $.extend($.validator, {
860
  },
861
 
862
  dataRules: function( element ) {
863
- var method, value,
864
- rules = {}, $element = $(element);
865
- for (method in $.validator.methods) {
866
- value = $element.data("rule-" + method.toLowerCase());
867
- if ( value !== undefined ) {
868
- rules[method] = value;
 
 
 
 
 
869
  }
 
 
870
  }
871
  return rules;
872
  },
873
 
874
  staticRules: function( element ) {
875
- var rules = {};
876
- var validator = $.data(element.form, "validator");
 
877
  if ( validator.settings.rules ) {
878
- rules = $.validator.normalizeRule(validator.settings.rules[element.name]) || {};
879
  }
880
  return rules;
881
  },
882
 
883
  normalizeRules: function( rules, element ) {
884
- // handle dependency check
885
- $.each(rules, function( prop, val ) {
886
- // ignore rule when param is explicitly false, eg. required:false
 
 
887
  if ( val === false ) {
888
- delete rules[prop];
889
  return;
890
  }
891
  if ( val.param || val.depends ) {
892
  var keepRule = true;
893
- switch (typeof val.depends) {
894
  case "string":
895
- keepRule = !!$(val.depends, element.form).length;
896
  break;
897
  case "function":
898
- keepRule = val.depends.call(element, element);
899
  break;
900
  }
901
  if ( keepRule ) {
902
- rules[prop] = val.param !== undefined ? val.param : true;
903
  } else {
904
- delete rules[prop];
 
905
  }
906
  }
907
- });
908
 
909
- // evaluate parameters
910
- $.each(rules, function( rule, parameter ) {
911
- rules[rule] = $.isFunction(parameter) ? parameter(element) : parameter;
912
- });
913
 
914
- // clean number parameters
915
- $.each(['minlength', 'maxlength'], function() {
916
- if ( rules[this] ) {
917
- rules[this] = Number(rules[this]);
918
  }
919
- });
920
- $.each(['rangelength'], function() {
921
  var parts;
922
- if ( rules[this] ) {
923
- if ( $.isArray(rules[this]) ) {
924
- rules[this] = [Number(rules[this][0]), Number(rules[this][1])];
925
- } else if ( typeof rules[this] === "string" ) {
926
- parts = rules[this].split(/[\s,]+/);
927
- rules[this] = [Number(parts[0]), Number(parts[1])];
928
  }
929
  }
930
- });
931
 
932
  if ( $.validator.autoCreateRanges ) {
933
- // auto-create ranges
934
- if ( rules.min && rules.max ) {
935
- rules.range = [rules.min, rules.max];
 
936
  delete rules.min;
937
  delete rules.max;
938
  }
939
- if ( rules.minlength && rules.maxlength ) {
940
- rules.rangelength = [rules.minlength, rules.maxlength];
941
  delete rules.minlength;
942
  delete rules.maxlength;
943
  }
@@ -950,258 +1374,284 @@ $.extend($.validator, {
950
  normalizeRule: function( data ) {
951
  if ( typeof data === "string" ) {
952
  var transformed = {};
953
- $.each(data.split(/\s/), function() {
954
- transformed[this] = true;
955
- });
956
  data = transformed;
957
  }
958
  return data;
959
  },
960
 
961
- // http://docs.jquery.com/Plugins/Validation/Validator/addMethod
962
  addMethod: function( name, method, message ) {
963
- $.validator.methods[name] = method;
964
- $.validator.messages[name] = message !== undefined ? message : $.validator.messages[name];
965
  if ( method.length < 3 ) {
966
- $.validator.addClassRules(name, $.validator.normalizeRule(name));
967
  }
968
  },
969
 
 
970
  methods: {
971
 
972
- // http://docs.jquery.com/Plugins/Validation/Methods/required
973
  required: function( value, element, param ) {
974
- // check if dependency is met
975
- if ( !this.depend(param, element) ) {
 
976
  return "dependency-mismatch";
977
  }
978
  if ( element.nodeName.toLowerCase() === "select" ) {
979
- // could be an array for select-multiple or a string, both are fine this way
980
- var val = $(element).val();
 
981
  return val && val.length > 0;
982
  }
983
- if ( this.checkable(element) ) {
984
- return this.getLength(value, element) > 0;
985
  }
986
- return $.trim(value).length > 0;
987
  },
988
 
989
- // http://docs.jquery.com/Plugins/Validation/Methods/remote
990
- remote: function( value, element, param ) {
991
- if ( this.optional(element) ) {
992
- return "dependency-mismatch";
993
- }
994
 
995
- var previous = this.previousValue(element);
996
- if (!this.settings.messages[element.name] ) {
997
- this.settings.messages[element.name] = {};
998
- }
999
- previous.originalMessage = this.settings.messages[element.name].remote;
1000
- this.settings.messages[element.name].remote = previous.message;
1001
 
1002
- param = typeof param === "string" && {url:param} || param;
 
1003
 
1004
- if ( previous.old === value ) {
1005
- return previous.valid;
1006
- }
 
 
 
1007
 
1008
- previous.old = value;
1009
- var validator = this;
1010
- this.startRequest(element);
1011
- var data = {};
1012
- data[element.name] = value;
1013
- $.ajax($.extend(true, {
1014
- url: param,
1015
- mode: "abort",
1016
- port: "validate" + element.name,
1017
- dataType: "json",
1018
- data: data,
1019
- success: function( response ) {
1020
- validator.settings.messages[element.name].remote = previous.originalMessage;
1021
- var valid = response === true || response === "true";
1022
- if ( valid ) {
1023
- var submitted = validator.formSubmitted;
1024
- validator.prepareElement(element);
1025
- validator.formSubmitted = submitted;
1026
- validator.successList.push(element);
1027
- delete validator.invalid[element.name];
1028
- validator.showErrors();
1029
- } else {
1030
- var errors = {};
1031
- var message = response || validator.defaultMessage( element, "remote" );
1032
- errors[element.name] = previous.message = $.isFunction(message) ? message(value) : message;
1033
- validator.invalid[element.name] = true;
1034
- validator.showErrors(errors);
1035
  }
1036
- previous.valid = valid;
1037
- validator.stopRequest(element, valid);
1038
  }
1039
- }, param));
1040
- return "pending";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1041
  },
1042
 
1043
- // http://docs.jquery.com/Plugins/Validation/Methods/minlength
1044
  minlength: function( value, element, param ) {
1045
- var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1046
- return this.optional(element) || length >= param;
1047
  },
1048
 
1049
- // http://docs.jquery.com/Plugins/Validation/Methods/maxlength
1050
  maxlength: function( value, element, param ) {
1051
- var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1052
- return this.optional(element) || length <= param;
1053
  },
1054
 
1055
- // http://docs.jquery.com/Plugins/Validation/Methods/rangelength
1056
  rangelength: function( value, element, param ) {
1057
- var length = $.isArray( value ) ? value.length : this.getLength($.trim(value), element);
1058
- return this.optional(element) || ( length >= param[0] && length <= param[1] );
1059
  },
1060
 
1061
- // http://docs.jquery.com/Plugins/Validation/Methods/min
1062
  min: function( value, element, param ) {
1063
- return this.optional(element) || value >= param;
1064
  },
1065
 
1066
- // http://docs.jquery.com/Plugins/Validation/Methods/max
1067
  max: function( value, element, param ) {
1068
- return this.optional(element) || value <= param;
1069
  },
1070
 
1071
- // http://docs.jquery.com/Plugins/Validation/Methods/range
1072
  range: function( value, element, param ) {
1073
- return this.optional(element) || ( value >= param[0] && value <= param[1] );
1074
  },
1075
 
1076
- // http://docs.jquery.com/Plugins/Validation/Methods/email
1077
- email: function( value, element ) {
1078
- // contributed by Scott Gonzalez: http://projects.scottsplayground.com/email_address_validation/
1079
- return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value);
1080
- },
 
 
 
 
 
 
 
1081
 
1082
- // http://docs.jquery.com/Plugins/Validation/Methods/url
1083
- url: function( value, element ) {
1084
- // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
1085
- return this.optional(element) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(value);
1086
- },
 
 
 
 
 
 
 
 
 
1087
 
1088
- // http://docs.jquery.com/Plugins/Validation/Methods/date
1089
- date: function( value, element ) {
1090
- return this.optional(element) || !/Invalid|NaN/.test(new Date(value).toString());
1091
- },
1092
 
1093
- // http://docs.jquery.com/Plugins/Validation/Methods/dateISO
1094
- dateISO: function( value, element ) {
1095
- return this.optional(element) || /^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(value);
1096
- },
1097
 
1098
- // http://docs.jquery.com/Plugins/Validation/Methods/number
1099
- number: function( value, element ) {
1100
- return this.optional(element) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(value);
1101
  },
1102
 
1103
- // http://docs.jquery.com/Plugins/Validation/Methods/digits
1104
- digits: function( value, element ) {
1105
- return this.optional(element) || /^\d+$/.test(value);
 
 
 
 
 
 
 
 
1106
  },
1107
 
1108
- // http://docs.jquery.com/Plugins/Validation/Methods/creditcard
1109
- // based on http://en.wikipedia.org/wiki/Luhn
1110
- creditcard: function( value, element ) {
1111
- if ( this.optional(element) ) {
1112
  return "dependency-mismatch";
1113
  }
1114
- // accept only spaces, digits and dashes
1115
- if ( /[^0-9 \-]+/.test(value) ) {
1116
- return false;
1117
- }
1118
- var nCheck = 0,
1119
- nDigit = 0,
1120
- bEven = false;
1121
-
1122
- value = value.replace(/\D/g, "");
1123
 
1124
- for (var n = value.length - 1; n >= 0; n--) {
1125
- var cDigit = value.charAt(n);
1126
- nDigit = parseInt(cDigit, 10);
1127
- if ( bEven ) {
1128
- if ( (nDigit *= 2) > 9 ) {
1129
- nDigit -= 9;
1130
- }
1131
- }
1132
- nCheck += nDigit;
1133
- bEven = !bEven;
1134
- }
1135
 
1136
- return (nCheck % 10) === 0;
1137
- },
1138
 
1139
- // http://docs.jquery.com/Plugins/Validation/Methods/equalTo
1140
- equalTo: function( value, element, param ) {
1141
- // bind to the blur event of the target in order to revalidate whenever the target field is updated
1142
- // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead
1143
- var target = $(param);
1144
- if ( this.settings.onfocusout ) {
1145
- target.unbind(".validate-equalTo").bind("blur.validate-equalTo", function() {
1146
- $(element).valid();
1147
- });
1148
  }
1149
- return value === target.val();
1150
- }
1151
 
1152
- }
 
 
 
 
1153
 
1154
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
1155
 
1156
- // deprecated, use $.validator.format instead
1157
- $.format = $.validator.format;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1158
 
1159
- }(jQuery));
1160
 
1161
- // ajax mode: abort
1162
  // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1163
  // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1164
- (function($) {
1165
- var pendingRequests = {};
1166
- // Use a prefilter if available (1.5+)
1167
- if ( $.ajaxPrefilter ) {
1168
- $.ajaxPrefilter(function( settings, _, xhr ) {
1169
- var port = settings.port;
1170
- if ( settings.mode === "abort" ) {
1171
- if ( pendingRequests[port] ) {
1172
- pendingRequests[port].abort();
1173
- }
1174
- pendingRequests[port] = xhr;
1175
  }
1176
- });
1177
- } else {
1178
- // Proxy ajax
1179
- var ajax = $.ajax;
1180
- $.ajax = function( settings ) {
1181
- var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1182
- port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1183
- if ( mode === "abort" ) {
1184
- if ( pendingRequests[port] ) {
1185
- pendingRequests[port].abort();
1186
- }
1187
- return (pendingRequests[port] = ajax.apply(this, arguments));
 
1188
  }
1189
- return ajax.apply(this, arguments);
1190
- };
1191
- }
1192
- }(jQuery));
1193
-
1194
- // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation
1195
- // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target
1196
- (function($) {
1197
- $.extend($.fn, {
1198
- validateDelegate: function( delegate, type, handler ) {
1199
- return this.bind(type, function( event ) {
1200
- var target = $(event.target);
1201
- if ( target.is(delegate) ) {
1202
- return handler.apply(target, arguments);
1203
- }
1204
- });
1205
  }
1206
- });
1207
- }(jQuery));
 
 
 
1
+ /*!
2
+ * jQuery Validation Plugin v1.19.3
3
+ *
4
+ * https://jqueryvalidation.org/
5
+ *
6
+ * Copyright (c) 2021 Jörn Zaefferer
7
+ * Released under the MIT license
8
+ */
9
+ (function( factory ) {
10
+ if ( typeof define === "function" && define.amd ) {
11
+ define( ["jquery"], factory );
12
+ } else if (typeof module === "object" && module.exports) {
13
+ module.exports = factory( require( "jquery" ) );
14
+ } else {
15
+ factory( jQuery );
16
+ }
17
+ }(function( $ ) {
18
 
19
+ $.extend( $.fn, {
20
 
21
+ // https://jqueryvalidation.org/validate/
 
22
  validate: function( options ) {
23
 
24
+ // If nothing is selected, return nothing; can't chain anyway
25
  if ( !this.length ) {
26
  if ( options && options.debug && window.console ) {
27
  console.warn( "Nothing selected, can't validate, returning nothing." );
29
  return;
30
  }
31
 
32
+ // Check if a validator for this form was already created
33
+ var validator = $.data( this[ 0 ], "validator" );
34
  if ( validator ) {
35
  return validator;
36
  }
38
  // Add novalidate tag if HTML5.
39
  this.attr( "novalidate", "novalidate" );
40
 
41
+ validator = new $.validator( options, this[ 0 ] );
42
+ $.data( this[ 0 ], "validator", validator );
43
 
44
  if ( validator.settings.onsubmit ) {
45
 
46
+ this.on( "click.validate", ":submit", function( event ) {
47
+
48
+ // Track the used submit button to properly handle scripted
49
+ // submits later.
50
+ validator.submitButton = event.currentTarget;
51
+
52
+ // Allow suppressing validation by adding a cancel class to the submit button
53
+ if ( $( this ).hasClass( "cancel" ) ) {
54
+ validator.cancelSubmit = true;
55
  }
56
+
57
+ // Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
58
+ if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
59
  validator.cancelSubmit = true;
60
  }
61
+ } );
62
 
63
+ // Validate the form on submit
64
+ this.on( "submit.validate", function( event ) {
65
  if ( validator.settings.debug ) {
66
+
67
+ // Prevent form submit to be able to see console output
68
  event.preventDefault();
69
  }
70
+
71
  function handle() {
72
+ var hidden, result;
73
+
74
+ // Insert a hidden input as a replacement for the missing submit button
75
+ // The hidden input is inserted in two cases:
76
+ // - A user defined a `submitHandler`
77
+ // - There was a pending request due to `remote` method and `stopRequest()`
78
+ // was called to submit the form in case it's valid
79
+ if ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {
80
+ hidden = $( "<input type='hidden'/>" )
81
+ .attr( "name", validator.submitButton.name )
82
+ .val( $( validator.submitButton ).val() )
83
+ .appendTo( validator.currentForm );
84
+ }
85
+
86
+ if ( validator.settings.submitHandler && !validator.settings.debug ) {
87
+ result = validator.settings.submitHandler.call( validator, validator.currentForm, event );
88
+ if ( hidden ) {
89
+
90
+ // And clean up afterwards; thanks to no-block-scope, hidden can be referenced
91
  hidden.remove();
92
  }
93
+ if ( result !== undefined ) {
94
+ return result;
95
+ }
96
  return false;
97
  }
98
  return true;
99
  }
100
 
101
+ // Prevent submit for invalid forms or custom submit handlers
102
  if ( validator.cancelSubmit ) {
103
  validator.cancelSubmit = false;
104
  return handle();
113
  validator.focusInvalid();
114
  return false;
115
  }
116
+ } );
117
  }
118
 
119
  return validator;
120
  },
121
+
122
+ // https://jqueryvalidation.org/valid/
123
  valid: function() {
124
+ var valid, validator, errorList;
125
+
126
+ if ( $( this[ 0 ] ).is( "form" ) ) {
127
+ valid = this.validate().form();
128
  } else {
129
+ errorList = [];
130
+ valid = true;
131
+ validator = $( this[ 0 ].form ).validate();
132
+ this.each( function() {
133
+ valid = validator.element( this ) && valid;
134
+ if ( !valid ) {
135
+ errorList = errorList.concat( validator.errorList );
136
+ }
137
+ } );
138
+ validator.errorList = errorList;
139
  }
140
+ return valid;
141
  },
142
+
143
+ // https://jqueryvalidation.org/rules/
 
 
 
 
 
 
 
 
 
144
  rules: function( command, argument ) {
145
+ var element = this[ 0 ],
146
+ isContentEditable = typeof this.attr( "contenteditable" ) !== "undefined" && this.attr( "contenteditable" ) !== "false",
147
+ settings, staticRules, existingRules, data, param, filtered;
148
+
149
+ // If nothing is selected, return empty object; can't chain anyway
150
+ if ( element == null ) {
151
+ return;
152
+ }
153
+
154
+ if ( !element.form && isContentEditable ) {
155
+ element.form = this.closest( "form" )[ 0 ];
156
+ element.name = this.attr( "name" );
157
+ }
158
+
159
+ if ( element.form == null ) {
160
+ return;
161
+ }
162
 
163
  if ( command ) {
164
+ settings = $.data( element.form, "validator" ).settings;
165
+ staticRules = settings.rules;
166
+ existingRules = $.validator.staticRules( element );
167
+ switch ( command ) {
168
  case "add":
169
+ $.extend( existingRules, $.validator.normalizeRule( argument ) );
170
+
171
+ // Remove messages from rules, but allow them to be set separately
172
+ delete existingRules.messages;
173
+ staticRules[ element.name ] = existingRules;
174
  if ( argument.messages ) {
175
+ settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );
176
  }
177
  break;
178
  case "remove":
179
  if ( !argument ) {
180
+ delete staticRules[ element.name ];
181
  return existingRules;
182
  }
183
+ filtered = {};
184
+ $.each( argument.split( /\s/ ), function( index, method ) {
185
+ filtered[ method ] = existingRules[ method ];
186
+ delete existingRules[ method ];
187
+ } );
188
  return filtered;
189
  }
190
  }
191
 
192
+ data = $.validator.normalizeRules(
193
  $.extend(
194
  {},
195
+ $.validator.classRules( element ),
196
+ $.validator.attributeRules( element ),
197
+ $.validator.dataRules( element ),
198
+ $.validator.staticRules( element )
199
+ ), element );
200
 
201
+ // Make sure required is at front
202
  if ( data.required ) {
203
+ param = data.required;
204
  delete data.required;
205
+ data = $.extend( { required: param }, data );
206
+ }
207
+
208
+ // Make sure remote is at back
209
+ if ( data.remote ) {
210
+ param = data.remote;
211
+ delete data.remote;
212
+ data = $.extend( data, { remote: param } );
213
  }
214
 
215
  return data;
216
  }
217
+ } );
218
+
219
+ // JQuery trim is deprecated, provide a trim method based on String.prototype.trim
220
+ var trim = function( str ) {
221
+
222
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill
223
+ return str.replace( /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, "" );
224
+ };
225
 
226
  // Custom selectors
227
+ $.extend( $.expr.pseudos || $.expr[ ":" ], { // '|| $.expr[ ":" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support
228
+
229
+ // https://jqueryvalidation.org/blank-selector/
230
+ blank: function( a ) {
231
+ return !trim( "" + $( a ).val() );
232
+ },
233
+
234
+ // https://jqueryvalidation.org/filled-selector/
235
+ filled: function( a ) {
236
+ var val = $( a ).val();
237
+ return val !== null && !!trim( "" + val );
238
+ },
239
+
240
+ // https://jqueryvalidation.org/unchecked-selector/
241
+ unchecked: function( a ) {
242
+ return !$( a ).prop( "checked" );
243
+ }
244
+ } );
245
+
246
+ // Constructor for validator
247
  $.validator = function( options, form ) {
248
  this.settings = $.extend( true, {}, $.validator.defaults, options );
249
  this.currentForm = form;
250
  this.init();
251
  };
252
 
253
+ // https://jqueryvalidation.org/jQuery.validator.format/
254
  $.validator.format = function( source, params ) {
255
  if ( arguments.length === 1 ) {
256
  return function() {
257
+ var args = $.makeArray( arguments );
258
+ args.unshift( source );
259
  return $.validator.format.apply( this, args );
260
  };
261
  }
262
+ if ( params === undefined ) {
263
+ return source;
264
+ }
265
  if ( arguments.length > 2 && params.constructor !== Array ) {
266
+ params = $.makeArray( arguments ).slice( 1 );
267
  }
268
  if ( params.constructor !== Array ) {
269
  params = [ params ];
270
  }
271
+ $.each( params, function( i, n ) {
272
+ source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() {
273
  return n;
274
+ } );
275
+ } );
276
  return source;
277
  };
278
 
279
+ $.extend( $.validator, {
280
 
281
  defaults: {
282
  messages: {},
283
  groups: {},
284
  rules: {},
285
  errorClass: "error",
286
+ pendingClass: "pending",
287
  validClass: "valid",
288
  errorElement: "label",
289
+ focusCleanup: false,
290
  focusInvalid: true,
291
+ errorContainer: $( [] ),
292
+ errorLabelContainer: $( [] ),
293
  onsubmit: true,
294
  ignore: ":hidden",
295
  ignoreTitle: false,
296
+ onfocusin: function( element ) {
297
  this.lastActive = element;
298
 
299
+ // Hide error label and remove error class on focus if enabled
300
+ if ( this.settings.focusCleanup ) {
301
  if ( this.settings.unhighlight ) {
302
  this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );
303
  }
304
+ this.hideThese( this.errorsFor( element ) );
305
  }
306
  },
307
+ onfocusout: function( element ) {
308
+ if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {
309
+ this.element( element );
310
  }
311
  },
312
  onkeyup: function( element, event ) {
313
+
314
+ // Avoid revalidate the field when pressing one of the following keys
315
+ // Shift => 16
316
+ // Ctrl => 17
317
+ // Alt => 18
318
+ // Caps lock => 20
319
+ // End => 35
320
+ // Home => 36
321
+ // Left arrow => 37
322
+ // Up arrow => 38
323
+ // Right arrow => 39
324
+ // Down arrow => 40
325
+ // Insert => 45
326
+ // Num lock => 144
327
+ // AltGr key => 225
328
+ var excludedKeys = [
329
+ 16, 17, 18, 20, 35, 36, 37,
330
+ 38, 39, 40, 45, 144, 225
331
+ ];
332
+
333
+ if ( event.which === 9 && this.elementValue( element ) === "" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {
334
  return;
335
+ } else if ( element.name in this.submitted || element.name in this.invalid ) {
336
+ this.element( element );
337
  }
338
  },
339
+ onclick: function( element ) {
340
+
341
+ // Click on selects, radiobuttons and checkboxes
342
  if ( element.name in this.submitted ) {
343
+ this.element( element );
344
+
345
+ // Or option elements, check parent select in that case
346
+ } else if ( element.parentNode.name in this.submitted ) {
347
+ this.element( element.parentNode );
348
  }
349
  },
350
  highlight: function( element, errorClass, validClass ) {
351
  if ( element.type === "radio" ) {
352
+ this.findByName( element.name ).addClass( errorClass ).removeClass( validClass );
353
  } else {
354
+ $( element ).addClass( errorClass ).removeClass( validClass );
355
  }
356
  },
357
  unhighlight: function( element, errorClass, validClass ) {
358
  if ( element.type === "radio" ) {
359
+ this.findByName( element.name ).removeClass( errorClass ).addClass( validClass );
360
  } else {
361
+ $( element ).removeClass( errorClass ).addClass( validClass );
362
  }
363
  }
364
  },
365
 
366
+ // https://jqueryvalidation.org/jQuery.validator.setDefaults/
367
  setDefaults: function( settings ) {
368
  $.extend( $.validator.defaults, settings );
369
  },
377
  dateISO: "Please enter a valid date (ISO).",
378
  number: "Please enter a valid number.",
379
  digits: "Please enter only digits.",
 
380
  equalTo: "Please enter the same value again.",
381
+ maxlength: $.validator.format( "Please enter no more than {0} characters." ),
382
+ minlength: $.validator.format( "Please enter at least {0} characters." ),
383
+ rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ),
384
+ range: $.validator.format( "Please enter a value between {0} and {1}." ),
385
+ max: $.validator.format( "Please enter a value less than or equal to {0}." ),
386
+ min: $.validator.format( "Please enter a value greater than or equal to {0}." ),
387
+ step: $.validator.format( "Please enter a multiple of {0}." )
388
  },
389
 
390
  autoCreateRanges: false,
392
  prototype: {
393
 
394
  init: function() {
395
+ this.labelContainer = $( this.settings.errorLabelContainer );
396
+ this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );
397
+ this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );
398
  this.submitted = {};
399
  this.valueCache = {};
400
  this.pendingRequest = 0;
402
  this.invalid = {};
403
  this.reset();
404
 
405
+ var currentForm = this.currentForm,
406
+ groups = ( this.groups = {} ),
407
+ rules;
408
+ $.each( this.settings.groups, function( key, value ) {
409
  if ( typeof value === "string" ) {
410
+ value = value.split( /\s/ );
411
  }
412
+ $.each( value, function( index, name ) {
413
+ groups[ name ] = key;
414
+ } );
415
+ } );
416
+ rules = this.settings.rules;
417
+ $.each( rules, function( key, value ) {
418
+ rules[ key ] = $.validator.normalizeRule( value );
419
+ } );
420
+
421
+ function delegate( event ) {
422
+ var isContentEditable = typeof $( this ).attr( "contenteditable" ) !== "undefined" && $( this ).attr( "contenteditable" ) !== "false";
423
+
424
+ // Set form expando on contenteditable
425
+ if ( !this.form && isContentEditable ) {
426
+ this.form = $( this ).closest( "form" )[ 0 ];
427
+ this.name = $( this ).attr( "name" );
428
+ }
429
+
430
+ // Ignore the element if it belongs to another form. This will happen mainly
431
+ // when setting the `form` attribute of an input to the id of another form.
432
+ if ( currentForm !== this.form ) {
433
+ return;
434
+ }
435
+
436
+ var validator = $.data( this.form, "validator" ),
437
+ eventType = "on" + event.type.replace( /^validate/, "" ),
438
+ settings = validator.settings;
439
+ if ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {
440
+ settings[ eventType ].call( validator, this, event );
441
  }
442
  }
443
+
444
+ $( this.currentForm )
445
+ .on( "focusin.validate focusout.validate keyup.validate",
446
+ ":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], " +
447
+ "[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], " +
448
+ "[type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], " +
449
+ "[type='radio'], [type='checkbox'], [contenteditable], [type='button']", delegate )
450
+
451
+ // Support: Chrome, oldIE
452
+ // "select" is provided as event.target when clicking a option
453
+ .on( "click.validate", "select, option, [type='radio'], [type='checkbox']", delegate );
454
 
455
  if ( this.settings.invalidHandler ) {
456
+ $( this.currentForm ).on( "invalid-form.validate", this.settings.invalidHandler );
457
  }
458
  },
459
 
460
+ // https://jqueryvalidation.org/Validator.form/
461
  form: function() {
462
  this.checkForm();
463
+ $.extend( this.submitted, this.errorMap );
464
+ this.invalid = $.extend( {}, this.errorMap );
465
  if ( !this.valid() ) {
466
+ $( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
467
  }
468
  this.showErrors();
469
  return this.valid();
471
 
472
  checkForm: function() {
473
  this.prepareForm();
474
+ for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {
475
+ this.check( elements[ i ] );
476
  }
477
  return this.valid();
478
  },
479
 
480
+ // https://jqueryvalidation.org/Validator.element/
481
  element: function( element ) {
482
+ var cleanElement = this.clean( element ),
483
+ checkElement = this.validationTargetFor( cleanElement ),
484
+ v = this,
485
+ result = true,
486
+ rs, group;
487
+
488
+ if ( checkElement === undefined ) {
489
+ delete this.invalid[ cleanElement.name ];
490
  } else {
491
+ this.prepareElement( checkElement );
492
+ this.currentElements = $( checkElement );
493
+
494
+ // If this element is grouped, then validate all group elements already
495
+ // containing a value
496
+ group = this.groups[ checkElement.name ];
497
+ if ( group ) {
498
+ $.each( this.groups, function( name, testgroup ) {
499
+ if ( testgroup === group && name !== checkElement.name ) {
500
+ cleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );
501
+ if ( cleanElement && cleanElement.name in v.invalid ) {
502
+ v.currentElements.push( cleanElement );
503
+ result = v.check( cleanElement ) && result;
504
+ }
505
+ }
506
+ } );
507
+ }
508
+
509
+ rs = this.check( checkElement ) !== false;
510
+ result = result && rs;
511
+ if ( rs ) {
512
+ this.invalid[ checkElement.name ] = false;
513
+ } else {
514
+ this.invalid[ checkElement.name ] = true;
515
+ }
516
+
517
+ if ( !this.numberOfInvalids() ) {
518
+
519
+ // Hide error containers on last error
520
+ this.toHide = this.toHide.add( this.containers );
521
+ }
522
+ this.showErrors();
523
+
524
+ // Add aria-invalid status for screen readers
525
+ $( element ).attr( "aria-invalid", !rs );
526
  }
527
+
528
  return result;
529
  },
530
 
531
+ // https://jqueryvalidation.org/Validator.showErrors/
532
  showErrors: function( errors ) {
533
  if ( errors ) {
534
+ var validator = this;
535
+
536
+ // Add items to error list and map
537
  $.extend( this.errorMap, errors );
538
+ this.errorList = $.map( this.errorMap, function( message, name ) {
539
+ return {
540
+ message: message,
541
+ element: validator.findByName( name )[ 0 ]
542
+ };
543
+ } );
544
+
545
+ // Remove items from success list
546
  this.successList = $.grep( this.successList, function( element ) {
547
+ return !( element.name in errors );
548
+ } );
549
  }
550
  if ( this.settings.showErrors ) {
551
  this.settings.showErrors.call( this, this.errorMap, this.errorList );
554
  }
555
  },
556
 
557
+ // https://jqueryvalidation.org/Validator.resetForm/
558
  resetForm: function() {
559
  if ( $.fn.resetForm ) {
560
+ $( this.currentForm ).resetForm();
561
  }
562
+ this.invalid = {};
563
  this.submitted = {};
 
564
  this.prepareForm();
565
  this.hideErrors();
566
+ var elements = this.elements()
567
+ .removeData( "previousValue" )
568
+ .removeAttr( "aria-invalid" );
569
+
570
+ this.resetElements( elements );
571
+ },
572
+
573
+ resetElements: function( elements ) {
574
+ var i;
575
+
576
+ if ( this.settings.unhighlight ) {
577
+ for ( i = 0; elements[ i ]; i++ ) {
578
+ this.settings.unhighlight.call( this, elements[ i ],
579
+ this.settings.errorClass, "" );
580
+ this.findByName( elements[ i ].name ).removeClass( this.settings.validClass );
581
+ }
582
+ } else {
583
+ elements
584
+ .removeClass( this.settings.errorClass )
585
+ .removeClass( this.settings.validClass );
586
+ }
587
  },
588
 
589
  numberOfInvalids: function() {
590
+ return this.objectLength( this.invalid );
591
  },
592
 
593
  objectLength: function( obj ) {
594
+ /* jshint unused: false */
595
+ var count = 0,
596
+ i;
597
+ for ( i in obj ) {
598
+
599
+ // This check allows counting elements with empty error
600
+ // message as invalid elements
601
+ if ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {
602
+ count++;
603
+ }
604
  }
605
  return count;
606
  },
607
 
608
  hideErrors: function() {
609
+ this.hideThese( this.toHide );
610
+ },
611
+
612
+ hideThese: function( errors ) {
613
+ errors.not( this.containers ).text( "" );
614
+ this.addWrapper( errors ).hide();
615
  },
616
 
617
  valid: function() {
625
  focusInvalid: function() {
626
  if ( this.settings.focusInvalid ) {
627
  try {
628
+ $( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )
629
+ .filter( ":visible" )
630
+ .trigger( "focus" )
631
+
632
+ // Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find
633
+ .trigger( "focusin" );
634
+ } catch ( e ) {
635
+
636
+ // Ignore IE throwing errors when focusing hidden elements
637
  }
638
  }
639
  },
640
 
641
  findLastActive: function() {
642
  var lastActive = this.lastActive;
643
+ return lastActive && $.grep( this.errorList, function( n ) {
644
  return n.element.name === lastActive.name;
645
+ } ).length === 1 && lastActive;
646
  },
647
 
648
  elements: function() {
649
  var validator = this,
650
  rulesCache = {};
651
 
652
+ // Select all valid inputs inside the form (no submit or reset buttons)
653
+ return $( this.currentForm )
654
+ .find( "input, select, textarea, [contenteditable]" )
655
+ .not( ":submit, :reset, :image, :disabled" )
656
  .not( this.settings.ignore )
657
+ .filter( function() {
658
+ var name = this.name || $( this ).attr( "name" ); // For contenteditable
659
+ var isContentEditable = typeof $( this ).attr( "contenteditable" ) !== "undefined" && $( this ).attr( "contenteditable" ) !== "false";
660
+
661
+ if ( !name && validator.settings.debug && window.console ) {
662
+ console.error( "%o has no name assigned", this );
663
+ }
664
+
665
+ // Set form expando on contenteditable
666
+ if ( isContentEditable ) {
667
+ this.form = $( this ).closest( "form" )[ 0 ];
668
+ this.name = name;
669
+ }
670
+
671
+ // Ignore elements that belong to other/nested forms
672
+ if ( this.form !== validator.currentForm ) {
673
+ return false;
674
  }
675
 
676
+ // Select only the first element for each name, and only those with rules specified
677
+ if ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {
678
  return false;
679
  }
680
 
681
+ rulesCache[ name ] = true;
682
  return true;
683
+ } );
684
  },
685
 
686
  clean: function( selector ) {
687
+ return $( selector )[ 0 ];
688
  },
689
 
690
  errors: function() {
691
+ var errorClass = this.settings.errorClass.split( " " ).join( "." );
692
+ return $( this.settings.errorElement + "." + errorClass, this.errorContext );
693
  },
694
 
695
+ resetInternals: function() {
696
  this.successList = [];
697
  this.errorList = [];
698
  this.errorMap = {};
699
+ this.toShow = $( [] );
700
+ this.toHide = $( [] );
701
+ },
702
+
703
+ reset: function() {
704
+ this.resetInternals();
705
+ this.currentElements = $( [] );
706
  },
707
 
708
  prepareForm: function() {
712
 
713
  prepareElement: function( element ) {
714
  this.reset();
715
+ this.toHide = this.errorsFor( element );
716
  },
717
 
718
  elementValue: function( element ) {
719
+ var $element = $( element ),
720
+ type = element.type,
721
+ isContentEditable = typeof $element.attr( "contenteditable" ) !== "undefined" && $element.attr( "contenteditable" ) !== "false",
722
+ val, idx;
723
 
724
  if ( type === "radio" || type === "checkbox" ) {
725
+ return this.findByName( element.name ).filter( ":checked" ).val();
726
+ } else if ( type === "number" && typeof element.validity !== "undefined" ) {
727
+ return element.validity.badInput ? "NaN" : $element.val();
728
+ }
729
+
730
+ if ( isContentEditable ) {
731
+ val = $element.text();
732
+ } else {
733
+ val = $element.val();
734
+ }
735
+
736
+ if ( type === "file" ) {
737
+
738
+ // Modern browser (chrome & safari)
739
+ if ( val.substr( 0, 12 ) === "C:\\fakepath\\" ) {
740
+ return val.substr( 12 );
741
+ }
742
+
743
+ // Legacy browsers
744
+ // Unix-based path
745
+ idx = val.lastIndexOf( "/" );
746
+ if ( idx >= 0 ) {
747
+ return val.substr( idx + 1 );
748
+ }
749
+
750
+ // Windows-based path
751
+ idx = val.lastIndexOf( "\\" );
752
+ if ( idx >= 0 ) {
753
+ return val.substr( idx + 1 );
754
+ }
755
+
756
+ // Just the file name
757
+ return val;
758
  }
759
 
760
  if ( typeof val === "string" ) {
761
+ return val.replace( /\r/g, "" );
762
  }
763
  return val;
764
  },
766
  check: function( element ) {
767
  element = this.validationTargetFor( this.clean( element ) );
768
 
769
+ var rules = $( element ).rules(),
770
+ rulesCount = $.map( rules, function( n, i ) {
771
+ return i;
772
+ } ).length,
773
+ dependencyMismatch = false,
774
+ val = this.elementValue( element ),
775
+ result, method, rule, normalizer;
776
+
777
+ // Prioritize the local normalizer defined for this element over the global one
778
+ // if the former exists, otherwise user the global one in case it exists.
779
+ if ( typeof rules.normalizer === "function" ) {
780
+ normalizer = rules.normalizer;
781
+ } else if ( typeof this.settings.normalizer === "function" ) {
782
+ normalizer = this.settings.normalizer;
783
+ }
784
+
785
+ // If normalizer is defined, then call it to retreive the changed value instead
786
+ // of using the real one.
787
+ // Note that `this` in the normalizer is `element`.
788
+ if ( normalizer ) {
789
+ val = normalizer.call( element, val );
790
 
791
+ // Delete the normalizer from rules to avoid treating it as a pre-defined method.
792
+ delete rules.normalizer;
793
+ }
794
 
795
+ for ( method in rules ) {
796
+ rule = { method: method, parameters: rules[ method ] };
797
+ try {
798
+ result = $.validator.methods[ method ].call( this, val, element, rule.parameters );
799
 
800
+ // If a method indicates that the field is optional and therefore valid,
801
  // don't mark it as valid when there are no other rules
802
+ if ( result === "dependency-mismatch" && rulesCount === 1 ) {
803
  dependencyMismatch = true;
804
  continue;
805
  }
806
  dependencyMismatch = false;
807
 
808
  if ( result === "pending" ) {
809
+ this.toHide = this.toHide.not( this.errorsFor( element ) );
810
  return;
811
  }
812
 
814
  this.formatAndAdd( element, rule );
815
  return false;
816
  }
817
+ } catch ( e ) {
818
  if ( this.settings.debug && window.console ) {
819
+ console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e );
820
  }
821
+ if ( e instanceof TypeError ) {
822
+ e.message += ". Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.";
823
+ }
824
+
825
  throw e;
826
  }
827
  }
828
  if ( dependencyMismatch ) {
829
  return;
830
  }
831
+ if ( this.objectLength( rules ) ) {
832
+ this.successList.push( element );
833
  }
834
  return true;
835
  },
836
 
837
+ // Return the custom message for the given element and validation method
838
  // specified in the element's HTML5 data attribute
839
+ // return the generic message if present and no method specific message is present
840
  customDataMessage: function( element, method ) {
841
+ return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() +
842
+ method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" );
843
  },
844
 
845
+ // Return the custom message for the given element name and validation method
846
  customMessage: function( name, method ) {
847
+ var m = this.settings.messages[ name ];
848
+ return m && ( m.constructor === String ? m : m[ method ] );
849
  },
850
 
851
+ // Return the first defined argument, allowing empty strings
852
  findDefined: function() {
853
+ for ( var i = 0; i < arguments.length; i++ ) {
854
+ if ( arguments[ i ] !== undefined ) {
855
+ return arguments[ i ];
856
  }
857
  }
858
  return undefined;
859
  },
860
 
861
+ // The second parameter 'rule' used to be a string, and extended to an object literal
862
+ // of the following form:
863
+ // rule = {
864
+ // method: "method name",
865
+ // parameters: "the given method parameters"
866
+ // }
867
+ //
868
+ // The old behavior still supported, kept to maintain backward compatibility with
869
+ // old code, and will be removed in the next major release.
870
+ defaultMessage: function( element, rule ) {
871
+ if ( typeof rule === "string" ) {
872
+ rule = { method: rule };
873
+ }
874
 
875
+ var message = this.findDefined(
876
+ this.customMessage( element.name, rule.method ),
877
+ this.customDataMessage( element, rule.method ),
878
+
879
+ // 'title' is never undefined, so handle empty string as undefined
880
+ !this.settings.ignoreTitle && element.title || undefined,
881
+ $.validator.messages[ rule.method ],
882
+ "<strong>Warning: No message defined for " + element.name + "</strong>"
883
+ ),
884
  theregex = /\$?\{(\d+)\}/g;
885
  if ( typeof message === "function" ) {
886
+ message = message.call( this, rule.parameters, element );
887
+ } else if ( theregex.test( message ) ) {
888
+ message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters );
889
  }
890
+
891
+ return message;
892
+ },
893
+
894
+ formatAndAdd: function( element, rule ) {
895
+ var message = this.defaultMessage( element, rule );
896
+
897
+ this.errorList.push( {
898
  message: message,
899
+ element: element,
900
+ method: rule.method
901
+ } );
902
 
903
+ this.errorMap[ element.name ] = message;
904
+ this.submitted[ element.name ] = message;
905
  },
906
 
907
  addWrapper: function( toToggle ) {
912
  },
913
 
914
  defaultShowErrors: function() {
915
+ var i, elements, error;
916
+ for ( i = 0; this.errorList[ i ]; i++ ) {
917
+ error = this.errorList[ i ];
918
  if ( this.settings.highlight ) {
919
  this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );
920
  }
924
  this.toShow = this.toShow.add( this.containers );
925
  }
926
  if ( this.settings.success ) {
927
+ for ( i = 0; this.successList[ i ]; i++ ) {
928
+ this.showLabel( this.successList[ i ] );
929
  }
930
  }
931
  if ( this.settings.unhighlight ) {
932
+ for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {
933
+ this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );
934
  }
935
  }
936
  this.toHide = this.toHide.not( this.toShow );
939
  },
940
 
941
  validElements: function() {
942
+ return this.currentElements.not( this.invalidElements() );
943
  },
944
 
945
  invalidElements: function() {
946
+ return $( this.errorList ).map( function() {
947
  return this.element;
948
+ } );
949
  },
950
 
951
  showLabel: function( element, message ) {
952
+ var place, group, errorID, v,
953
+ error = this.errorsFor( element ),
954
+ elementID = this.idOrName( element ),
955
+ describedBy = $( element ).attr( "aria-describedby" );
956
+
957
+ if ( error.length ) {
958
+
959
+ // Refresh error/success class
960
+ error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );
961
+
962
+ // Replace message on existing label
963
+ error.html( message );
964
  } else {
965
+
966
+ // Create error element
967
+ error = $( "<" + this.settings.errorElement + ">" )
968
+ .attr( "id", elementID + "-error" )
969
+ .addClass( this.settings.errorClass )
970
+ .html( message || "" );
971
+
972
+ // Maintain reference to the element to be placed into the DOM
973
+ place = error;
974
  if ( this.settings.wrapper ) {
975
+
976
+ // Make sure the element is visible, even in IE
977
  // actually showing the wrapped element is handled elsewhere
978
+ place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent();
979
  }
980
+ if ( this.labelContainer.length ) {
981
+ this.labelContainer.append( place );
982
+ } else if ( this.settings.errorPlacement ) {
983
+ this.settings.errorPlacement.call( this, place, $( element ) );
984
+ } else {
985
+ place.insertAfter( element );
986
+ }
987
+
988
+ // Link error back to the element
989
+ if ( error.is( "label" ) ) {
990
+
991
+ // If the error is a label, then associate using 'for'
992
+ error.attr( "for", elementID );
993
+
994
+ // If the element is not a child of an associated label, then it's necessary
995
+ // to explicitly apply aria-describedby
996
+ } else if ( error.parents( "label[for='" + this.escapeCssMeta( elementID ) + "']" ).length === 0 ) {
997
+ errorID = error.attr( "id" );
998
+
999
+ // Respect existing non-error aria-describedby
1000
+ if ( !describedBy ) {
1001
+ describedBy = errorID;
1002
+ } else if ( !describedBy.match( new RegExp( "\\b" + this.escapeCssMeta( errorID ) + "\\b" ) ) ) {
1003
+
1004
+ // Add to end of list if not already present
1005
+ describedBy += " " + errorID;
1006
+ }
1007
+ $( element ).attr( "aria-describedby", describedBy );
1008
+
1009
+ // If this element is grouped, then assign to all elements in the same group
1010
+ group = this.groups[ element.name ];
1011
+ if ( group ) {
1012
+ v = this;
1013
+ $.each( v.groups, function( name, testgroup ) {
1014
+ if ( testgroup === group ) {
1015
+ $( "[name='" + v.escapeCssMeta( name ) + "']", v.currentForm )
1016
+ .attr( "aria-describedby", error.attr( "id" ) );
1017
+ }
1018
+ } );
1019
  }
1020
  }
1021
  }
1022
  if ( !message && this.settings.success ) {
1023
+ error.text( "" );
1024
  if ( typeof this.settings.success === "string" ) {
1025
+ error.addClass( this.settings.success );
1026
  } else {
1027
+ this.settings.success( error, element );
1028
  }
1029
  }
1030
+ this.toShow = this.toShow.add( error );
1031
  },
1032
 
1033
  errorsFor: function( element ) {
1034
+ var name = this.escapeCssMeta( this.idOrName( element ) ),
1035
+ describer = $( element ).attr( "aria-describedby" ),
1036
+ selector = "label[for='" + name + "'], label[for='" + name + "'] *";
1037
+
1038
+ // 'aria-describedby' should directly reference the error element
1039
+ if ( describer ) {
1040
+ selector = selector + ", #" + this.escapeCssMeta( describer )
1041
+ .replace( /\s+/g, ", #" );
1042
+ }
1043
+
1044
+ return this
1045
+ .errors()
1046
+ .filter( selector );
1047
+ },
1048
+
1049
+ // See https://api.jquery.com/category/selectors/, for CSS
1050
+ // meta-characters that should be escaped in order to be used with JQuery
1051
+ // as a literal part of a name/id or any selector.
1052
+ escapeCssMeta: function( string ) {
1053
+ return string.replace( /([\\!"#$%&'()*+,./:;<=>?@\[\]^`{|}~])/g, "\\$1" );
1054
  },
1055
 
1056
  idOrName: function( element ) {
1057
+ return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );
1058
  },
1059
 
1060
  validationTargetFor: function( element ) {
1061
+
1062
+ // If radio/checkbox, validate first element in group instead
1063
+ if ( this.checkable( element ) ) {
1064
+ element = this.findByName( element.name );
1065
  }
1066
+
1067
+ // Always apply ignore filter
1068
+ return $( element ).not( this.settings.ignore )[ 0 ];
1069
  },
1070
 
1071
  checkable: function( element ) {
1072
+ return ( /radio|checkbox/i ).test( element.type );
1073
  },
1074
 
1075
  findByName: function( name ) {
1076
+ return $( this.currentForm ).find( "[name='" + this.escapeCssMeta( name ) + "']" );
1077
  },
1078
 
1079
  getLength: function( value, element ) {
1080
+ switch ( element.nodeName.toLowerCase() ) {
1081
  case "select":
1082
+ return $( "option:selected", element ).length;
1083
  case "input":
1084
+ if ( this.checkable( element ) ) {
1085
+ return this.findByName( element.name ).filter( ":checked" ).length;
1086
  }
1087
  }
1088
  return value.length;
1089
  },
1090
 
1091
  depend: function( param, element ) {
1092
+ return this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;
1093
  },
1094
 
1095
  dependTypes: {
1096
+ "boolean": function( param ) {
1097
  return param;
1098
  },
1099
  "string": function( param, element ) {
1100
+ return !!$( param, element.form ).length;
1101
  },
1102
  "function": function( param, element ) {
1103
+ return param( element );
1104
  }
1105
  },
1106
 
1107
  optional: function( element ) {
1108
+ var val = this.elementValue( element );
1109
+ return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch";
1110
  },
1111
 
1112
  startRequest: function( element ) {
1113
+ if ( !this.pending[ element.name ] ) {
1114
  this.pendingRequest++;
1115
+ $( element ).addClass( this.settings.pendingClass );
1116
+ this.pending[ element.name ] = true;
1117
  }
1118
  },
1119
 
1120
  stopRequest: function( element, valid ) {
1121
  this.pendingRequest--;
1122
+
1123
+ // Sometimes synchronization fails, make sure pendingRequest is never < 0
1124
  if ( this.pendingRequest < 0 ) {
1125
  this.pendingRequest = 0;
1126
  }
1127
+ delete this.pending[ element.name ];
1128
+ $( element ).removeClass( this.settings.pendingClass );
1129
  if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) {
1130
+ $( this.currentForm ).submit();
1131
+
1132
+ // Remove the hidden input that was used as a replacement for the
1133
+ // missing submit button. The hidden input is added by `handle()`
1134
+ // to ensure that the value of the used submit button is passed on
1135
+ // for scripted submits triggered by this method
1136
+ if ( this.submitButton ) {
1137
+ $( "input:hidden[name='" + this.submitButton.name + "']", this.currentForm ).remove();
1138
+ }
1139
+
1140
  this.formSubmitted = false;
1141
+ } else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {
1142
+ $( this.currentForm ).triggerHandler( "invalid-form", [ this ] );
1143
  this.formSubmitted = false;
1144
  }
1145
  },
1146
 
1147
+ previousValue: function( element, method ) {
1148
+ method = typeof method === "string" && method || "remote";
1149
+
1150
+ return $.data( element, "previousValue" ) || $.data( element, "previousValue", {
1151
  old: null,
1152
  valid: true,
1153
+ message: this.defaultMessage( element, { method: method } )
1154
+ } );
1155
+ },
1156
+
1157
+ // Cleans up all forms and elements, removes validator-specific events
1158
+ destroy: function() {
1159
+ this.resetForm();
1160
+
1161
+ $( this.currentForm )
1162
+ .off( ".validate" )
1163
+ .removeData( "validator" )
1164
+ .find( ".validate-equalTo-blur" )
1165
+ .off( ".validate-equalTo" )
1166
+ .removeClass( "validate-equalTo-blur" )
1167
+ .find( ".validate-lessThan-blur" )
1168
+ .off( ".validate-lessThan" )
1169
+ .removeClass( "validate-lessThan-blur" )
1170
+ .find( ".validate-lessThanEqual-blur" )
1171
+ .off( ".validate-lessThanEqual" )
1172
+ .removeClass( "validate-lessThanEqual-blur" )
1173
+ .find( ".validate-greaterThanEqual-blur" )
1174
+ .off( ".validate-greaterThanEqual" )
1175
+ .removeClass( "validate-greaterThanEqual-blur" )
1176
+ .find( ".validate-greaterThan-blur" )
1177
+ .off( ".validate-greaterThan" )
1178
+ .removeClass( "validate-greaterThan-blur" );
1179
  }
1180
 
1181
  },
1182
 
1183
  classRuleSettings: {
1184
+ required: { required: true },
1185
+ email: { email: true },
1186
+ url: { url: true },
1187
+ date: { date: true },
1188
+ dateISO: { dateISO: true },
1189
+ number: { number: true },
1190
+ digits: { digits: true },
1191
+ creditcard: { creditcard: true }
1192
  },
1193
 
1194
  addClassRules: function( className, rules ) {
1195
  if ( className.constructor === String ) {
1196
+ this.classRuleSettings[ className ] = rules;
1197
  } else {
1198
+ $.extend( this.classRuleSettings, className );
1199
  }
1200
  },
1201
 
1202
  classRules: function( element ) {
1203
+ var rules = {},
1204
+ classes = $( element ).attr( "class" );
1205
+
1206
  if ( classes ) {
1207
+ $.each( classes.split( " " ), function() {
1208
  if ( this in $.validator.classRuleSettings ) {
1209
+ $.extend( rules, $.validator.classRuleSettings[ this ] );
1210
  }
1211
+ } );
1212
  }
1213
  return rules;
1214
  },
1215
 
1216
+ normalizeAttributeRule: function( rules, type, method, value ) {
1217
+
1218
+ // Convert the value to a number for number inputs, and for text for backwards compability
1219
+ // allows type="date" and others to be compared as strings
1220
+ if ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {
1221
+ value = Number( value );
1222
+
1223
+ // Support Opera Mini, which returns NaN for undefined minlength
1224
+ if ( isNaN( value ) ) {
1225
+ value = undefined;
1226
+ }
1227
+ }
1228
+
1229
+ if ( value || value === 0 ) {
1230
+ rules[ method ] = value;
1231
+ } else if ( type === method && type !== "range" ) {
1232
+
1233
+ // Exception: the jquery validate 'range' method
1234
+ // does not test for the html5 'range' type
1235
+ rules[ method ] = true;
1236
+ }
1237
+ },
1238
+
1239
  attributeRules: function( element ) {
1240
+ var rules = {},
1241
+ $element = $( element ),
1242
+ type = element.getAttribute( "type" ),
1243
+ method, value;
1244
 
1245
+ for ( method in $.validator.methods ) {
 
1246
 
1247
+ // Support for <input required> in both html5 and older browsers
1248
  if ( method === "required" ) {
1249
+ value = element.getAttribute( method );
1250
+
1251
  // Some browsers return an empty string for the required attribute
1252
  // and non-HTML5 browsers might have required="" markup
1253
  if ( value === "" ) {
1254
  value = true;
1255
  }
1256
+
1257
+ // Force non-HTML5 browsers to return bool
1258
  value = !!value;
1259
  } else {
1260
+ value = $element.attr( method );
1261
  }
1262
 
1263
+ this.normalizeAttributeRule( rules, type, method, value );
 
 
 
 
1264
  }
1265
 
1266
+ // 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs
1267
+ if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {
1268
  delete rules.maxlength;
1269
  }
1270
 
1272
  },
1273
 
1274
  dataRules: function( element ) {
1275
+ var rules = {},
1276
+ $element = $( element ),
1277
+ type = element.getAttribute( "type" ),
1278
+ method, value;
1279
+
1280
+ for ( method in $.validator.methods ) {
1281
+ value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );
1282
+
1283
+ // Cast empty attributes like `data-rule-required` to `true`
1284
+ if ( value === "" ) {
1285
+ value = true;
1286
  }
1287
+
1288
+ this.normalizeAttributeRule( rules, type, method, value );
1289
  }
1290
  return rules;
1291
  },
1292
 
1293
  staticRules: function( element ) {
1294
+ var rules = {},
1295
+ validator = $.data( element.form, "validator" );
1296
+
1297
  if ( validator.settings.rules ) {
1298
+ rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};
1299
  }
1300
  return rules;
1301
  },
1302
 
1303
  normalizeRules: function( rules, element ) {
1304
+
1305
+ // Handle dependency check
1306
+ $.each( rules, function( prop, val ) {
1307
+
1308
+ // Ignore rule when param is explicitly false, eg. required:false
1309
  if ( val === false ) {
1310
+ delete rules[ prop ];
1311
  return;
1312
  }
1313
  if ( val.param || val.depends ) {
1314
  var keepRule = true;
1315
+ switch ( typeof val.depends ) {
1316
  case "string":
1317
+ keepRule = !!$( val.depends, element.form ).length;
1318
  break;
1319
  case "function":
1320
+ keepRule = val.depends.call( element, element );
1321
  break;
1322
  }
1323
  if ( keepRule ) {
1324
+ rules[ prop ] = val.param !== undefined ? val.param : true;
1325
  } else {
1326
+ $.data( element.form, "validator" ).resetElements( $( element ) );
1327
+ delete rules[ prop ];
1328
  }
1329
  }
1330
+ } );
1331
 
1332
+ // Evaluate parameters
1333
+ $.each( rules, function( rule, parameter ) {
1334
+ rules[ rule ] = typeof parameter === "function" && rule !== "normalizer" ? parameter( element ) : parameter;
1335
+ } );
1336
 
1337
+ // Clean number parameters
1338
+ $.each( [ "minlength", "maxlength" ], function() {
1339
+ if ( rules[ this ] ) {
1340
+ rules[ this ] = Number( rules[ this ] );
1341
  }
1342
+ } );
1343
+ $.each( [ "rangelength", "range" ], function() {
1344
  var parts;
1345
+ if ( rules[ this ] ) {
1346
+ if ( Array.isArray( rules[ this ] ) ) {
1347
+ rules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];
1348
+ } else if ( typeof rules[ this ] === "string" ) {
1349
+ parts = rules[ this ].replace( /[\[\]]/g, "" ).split( /[\s,]+/ );
1350
+ rules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];
1351
  }
1352
  }
1353
+ } );
1354
 
1355
  if ( $.validator.autoCreateRanges ) {
1356
+
1357
+ // Auto-create ranges
1358
+ if ( rules.min != null && rules.max != null ) {
1359
+ rules.range = [ rules.min, rules.max ];
1360
  delete rules.min;
1361
  delete rules.max;
1362
  }
1363
+ if ( rules.minlength != null && rules.maxlength != null ) {
1364
+ rules.rangelength = [ rules.minlength, rules.maxlength ];
1365
  delete rules.minlength;
1366
  delete rules.maxlength;
1367
  }
1374
  normalizeRule: function( data ) {
1375
  if ( typeof data === "string" ) {
1376
  var transformed = {};
1377
+ $.each( data.split( /\s/ ), function() {
1378
+ transformed[ this ] = true;
1379
+ } );
1380
  data = transformed;
1381
  }
1382
  return data;
1383
  },
1384
 
1385
+ // https://jqueryvalidation.org/jQuery.validator.addMethod/
1386
  addMethod: function( name, method, message ) {
1387
+ $.validator.methods[ name ] = method;
1388
+ $.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];
1389
  if ( method.length < 3 ) {
1390
+ $.validator.addClassRules( name, $.validator.normalizeRule( name ) );
1391
  }
1392
  },
1393
 
1394
+ // https://jqueryvalidation.org/jQuery.validator.methods/
1395
  methods: {
1396
 
1397
+ // https://jqueryvalidation.org/required-method/
1398
  required: function( value, element, param ) {
1399
+
1400
+ // Check if dependency is met
1401
+ if ( !this.depend( param, element ) ) {
1402
  return "dependency-mismatch";
1403
  }
1404
  if ( element.nodeName.toLowerCase() === "select" ) {
1405
+
1406
+ // Could be an array for select-multiple or a string, both are fine this way
1407
+ var val = $( element ).val();
1408
  return val && val.length > 0;
1409
  }
1410
+ if ( this.checkable( element ) ) {
1411
+ return this.getLength( value, element ) > 0;
1412
  }
1413
+ return value !== undefined && value !== null && value.length > 0;
1414
  },
1415
 
1416
+ // https://jqueryvalidation.org/email-method/
1417
+ email: function( value, element ) {
 
 
 
1418
 
1419
+ // From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address
1420
+ // Retrieved 2014-01-14
1421
+ // If you have a problem with this implementation, report a bug against the above spec
1422
+ // Or use custom methods to implement your own email validation
1423
+ return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );
1424
+ },
1425
 
1426
+ // https://jqueryvalidation.org/url-method/
1427
+ url: function( value, element ) {
1428
 
1429
+ // Copyright (c) 2010-2013 Diego Perini, MIT licensed
1430
+ // https://gist.github.com/dperini/729294
1431
+ // see also https://mathiasbynens.be/demo/url-regex
1432
+ // modified to allow protocol-relative URLs
1433
+ return this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[/?#]\S*)?$/i.test( value );
1434
+ },
1435
 
1436
+ // https://jqueryvalidation.org/date-method/
1437
+ date: ( function() {
1438
+ var called = false;
1439
+
1440
+ return function( value, element ) {
1441
+ if ( !called ) {
1442
+ called = true;
1443
+ if ( this.settings.debug && window.console ) {
1444
+ console.warn(
1445
+ "The `date` method is deprecated and will be removed in version '2.0.0'.\n" +
1446
+ "Please don't use it, since it relies on the Date constructor, which\n" +
1447
+ "behaves very differently across browsers and locales. Use `dateISO`\n" +
1448
+ "instead or one of the locale specific methods in `localizations/`\n" +
1449
+ "and `additional-methods.js`."
1450
+ );
 
 
 
 
 
 
 
 
 
 
 
 
1451
  }
 
 
1452
  }
1453
+
1454
+ return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );
1455
+ };
1456
+ }() ),
1457
+
1458
+ // https://jqueryvalidation.org/dateISO-method/
1459
+ dateISO: function( value, element ) {
1460
+ return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );
1461
+ },
1462
+
1463
+ // https://jqueryvalidation.org/number-method/
1464
+ number: function( value, element ) {
1465
+ return this.optional( element ) || /^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value );
1466
+ },
1467
+
1468
+ // https://jqueryvalidation.org/digits-method/
1469
+ digits: function( value, element ) {
1470
+ return this.optional( element ) || /^\d+$/.test( value );
1471
  },
1472
 
1473
+ // https://jqueryvalidation.org/minlength-method/
1474
  minlength: function( value, element, param ) {
1475
+ var length = Array.isArray( value ) ? value.length : this.getLength( value, element );
1476
+ return this.optional( element ) || length >= param;
1477
  },
1478
 
1479
+ // https://jqueryvalidation.org/maxlength-method/
1480
  maxlength: function( value, element, param ) {
1481
+ var length = Array.isArray( value ) ? value.length : this.getLength( value, element );
1482
+ return this.optional( element ) || length <= param;
1483
  },
1484
 
1485
+ // https://jqueryvalidation.org/rangelength-method/
1486
  rangelength: function( value, element, param ) {
1487
+ var length = Array.isArray( value ) ? value.length : this.getLength( value, element );
1488
+ return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );
1489
  },
1490
 
1491
+ // https://jqueryvalidation.org/min-method/
1492
  min: function( value, element, param ) {
1493
+ return this.optional( element ) || value >= param;
1494
  },
1495
 
1496
+ // https://jqueryvalidation.org/max-method/
1497
  max: function( value, element, param ) {
1498
+ return this.optional( element ) || value <= param;
1499
  },
1500
 
1501
+ // https://jqueryvalidation.org/range-method/
1502
  range: function( value, element, param ) {
1503
+ return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
1504
  },
1505
 
1506
+ // https://jqueryvalidation.org/step-method/
1507
+ step: function( value, element, param ) {
1508
+ var type = $( element ).attr( "type" ),
1509
+ errorMessage = "Step attribute on input type " + type + " is not supported.",
1510
+ supportedTypes = [ "text", "number", "range" ],
1511
+ re = new RegExp( "\\b" + type + "\\b" ),
1512
+ notSupported = type && !re.test( supportedTypes.join() ),
1513
+ decimalPlaces = function( num ) {
1514
+ var match = ( "" + num ).match( /(?:\.(\d+))?$/ );
1515
+ if ( !match ) {
1516
+ return 0;
1517
+ }
1518
 
1519
+ // Number of digits right of decimal point.
1520
+ return match[ 1 ] ? match[ 1 ].length : 0;
1521
+ },
1522
+ toInt = function( num ) {
1523
+ return Math.round( num * Math.pow( 10, decimals ) );
1524
+ },
1525
+ valid = true,
1526
+ decimals;
1527
+
1528
+ // Works only for text, number and range input types
1529
+ // TODO find a way to support input types date, datetime, datetime-local, month, time and week
1530
+ if ( notSupported ) {
1531
+ throw new Error( errorMessage );
1532
+ }
1533
 
1534
+ decimals = decimalPlaces( param );
 
 
 
1535
 
1536
+ // Value can't have too many decimals
1537
+ if ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {
1538
+ valid = false;
1539
+ }
1540
 
1541
+ return this.optional( element ) || valid;
 
 
1542
  },
1543
 
1544
+ // https://jqueryvalidation.org/equalTo-method/
1545
+ equalTo: function( value, element, param ) {
1546
+
1547
+ // Bind to the blur event of the target in order to revalidate whenever the target field is updated
1548
+ var target = $( param );
1549
+ if ( this.settings.onfocusout && target.not( ".validate-equalTo-blur" ).length ) {
1550
+ target.addClass( "validate-equalTo-blur" ).on( "blur.validate-equalTo", function() {
1551
+ $( element ).valid();
1552
+ } );
1553
+ }
1554
+ return value === target.val();
1555
  },
1556
 
1557
+ // https://jqueryvalidation.org/remote-method/
1558
+ remote: function( value, element, param, method ) {
1559
+ if ( this.optional( element ) ) {
 
1560
  return "dependency-mismatch";
1561
  }
 
 
 
 
 
 
 
 
 
1562
 
1563
+ method = typeof method === "string" && method || "remote";
 
 
 
 
 
 
 
 
 
 
1564
 
1565
+ var previous = this.previousValue( element, method ),
1566
+ validator, data, optionDataString;
1567
 
1568
+ if ( !this.settings.messages[ element.name ] ) {
1569
+ this.settings.messages[ element.name ] = {};
 
 
 
 
 
 
 
1570
  }
1571
+ previous.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];
1572
+ this.settings.messages[ element.name ][ method ] = previous.message;
1573
 
1574
+ param = typeof param === "string" && { url: param } || param;
1575
+ optionDataString = $.param( $.extend( { data: value }, param.data ) );
1576
+ if ( previous.old === optionDataString ) {
1577
+ return previous.valid;
1578
+ }
1579
 
1580
+ previous.old = optionDataString;
1581
+ validator = this;
1582
+ this.startRequest( element );
1583
+ data = {};
1584
+ data[ element.name ] = value;
1585
+ $.ajax( $.extend( true, {
1586
+ mode: "abort",
1587
+ port: "validate" + element.name,
1588
+ dataType: "json",
1589
+ data: data,
1590
+ context: validator.currentForm,
1591
+ success: function( response ) {
1592
+ var valid = response === true || response === "true",
1593
+ errors, message, submitted;
1594
 
1595
+ validator.settings.messages[ element.name ][ method ] = previous.originalMessage;
1596
+ if ( valid ) {
1597
+ submitted = validator.formSubmitted;
1598
+ validator.resetInternals();
1599
+ validator.toHide = validator.errorsFor( element );
1600
+ validator.formSubmitted = submitted;
1601
+ validator.successList.push( element );
1602
+ validator.invalid[ element.name ] = false;
1603
+ validator.showErrors();
1604
+ } else {
1605
+ errors = {};
1606
+ message = response || validator.defaultMessage( element, { method: method, parameters: value } );
1607
+ errors[ element.name ] = previous.message = message;
1608
+ validator.invalid[ element.name ] = true;
1609
+ validator.showErrors( errors );
1610
+ }
1611
+ previous.valid = valid;
1612
+ validator.stopRequest( element, valid );
1613
+ }
1614
+ }, param ) );
1615
+ return "pending";
1616
+ }
1617
+ }
1618
 
1619
+ } );
1620
 
1621
+ // Ajax mode: abort
1622
  // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]});
1623
  // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()
1624
+
1625
+ var pendingRequests = {},
1626
+ ajax;
1627
+
1628
+ // Use a prefilter if available (1.5+)
1629
+ if ( $.ajaxPrefilter ) {
1630
+ $.ajaxPrefilter( function( settings, _, xhr ) {
1631
+ var port = settings.port;
1632
+ if ( settings.mode === "abort" ) {
1633
+ if ( pendingRequests[ port ] ) {
1634
+ pendingRequests[ port ].abort();
1635
  }
1636
+ pendingRequests[ port ] = xhr;
1637
+ }
1638
+ } );
1639
+ } else {
1640
+
1641
+ // Proxy ajax
1642
+ ajax = $.ajax;
1643
+ $.ajax = function( settings ) {
1644
+ var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode,
1645
+ port = ( "port" in settings ? settings : $.ajaxSettings ).port;
1646
+ if ( mode === "abort" ) {
1647
+ if ( pendingRequests[ port ] ) {
1648
+ pendingRequests[ port ].abort();
1649
  }
1650
+ pendingRequests[ port ] = ajax.apply( this, arguments );
1651
+ return pendingRequests[ port ];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1652
  }
1653
+ return ajax.apply( this, arguments );
1654
+ };
1655
+ }
1656
+ return $;
1657
+ }));
js/jquery.validate.min.js CHANGED
@@ -1,4 +1,4 @@
1
- /*! jQuery Validation Plugin - v1.11.0 - 7/13/2013
2
- * https://github.com/jzaefferer/jquery-validation
3
- * Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */
4
- (function(e){e.extend(e.fn,{validate:function(t){if(!this.length){t&&t.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing.");return}var n=e.data(this[0],"validator");return n?n:(this.attr("novalidate","novalidate"),n=new e.validator(t,this[0]),e.data(this[0],"validator",n),n.settings.onsubmit&&(this.validateDelegate(":submit","click",function(t){n.settings.submitHandler&&(n.submitButton=t.target),e(t.target).hasClass("cancel")&&(n.cancelSubmit=!0)}),this.submit(function(t){function r(){var r;return n.settings.submitHandler?(n.submitButton&&(r=e("<input type='hidden'/>").attr("name",n.submitButton.name).val(n.submitButton.value).appendTo(n.currentForm)),n.settings.submitHandler.call(n,n.currentForm,t),n.submitButton&&r.remove(),!1):!0}return n.settings.debug&&t.preventDefault(),n.cancelSubmit?(n.cancelSubmit=!1,r()):n.form()?n.pendingRequest?(n.formSubmitted=!0,!1):r():(n.focusInvalid(),!1)})),n)},valid:function(){if(e(this[0]).is("form"))return this.validate().form();var t=!0,n=e(this[0].form).validate();return this.each(function(){t&=n.element(this)}),t},removeAttrs:function(t){var n={},r=this;return e.each(t.split(/\s/),function(e,t){n[t]=r.attr(t),r.removeAttr(t)}),n},rules:function(t,n){var r=this[0];if(t){var i=e.data(r.form,"validator").settings,s=i.rules,o=e.validator.staticRules(r);switch(t){case"add":e.extend(o,e.validator.normalizeRule(n)),s[r.name]=o,n.messages&&(i.messages[r.name]=e.extend(i.messages[r.name],n.messages));break;case"remove":if(!n)return delete s[r.name],o;var u={};return e.each(n.split(/\s/),function(e,t){u[t]=o[t],delete o[t]}),u}}var a=e.validator.normalizeRules(e.extend({},e.validator.classRules(r),e.validator.attributeRules(r),e.validator.dataRules(r),e.validator.staticRules(r)),r);if(a.required){var f=a.required;delete a.required,a=e.extend({required:f},a)}return a}}),e.extend(e.expr[":"],{blank:function(t){return!e.trim(""+t.value)},filled:function(t){return!!e.trim(""+t.value)},unchecked:function(e){return!e.checked}}),e.validator=function(t,n){this.settings=e.extend(!0,{},e.validator.defaults,t),this.currentForm=n,this.init()},e.validator.format=function(t,n){return arguments.length===1?function(){var n=e.makeArray(arguments);return n.unshift(t),e.validator.format.apply(this,n)}:(arguments.length>2&&n.constructor!==Array&&(n=e.makeArray(arguments).slice(1)),n.constructor!==Array&&(n=[n]),e.each(n,function(e,n){t=t.replace(new RegExp("\\{"+e+"\\}","g"),function(){return n})}),t)},e.extend(e.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:!0,errorContainer:e([]),errorLabelContainer:e([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(e,t){this.lastActive=e,this.settings.focusCleanup&&!this.blockFocusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,e,this.settings.errorClass,this.settings.validClass),this.addWrapper(this.errorsFor(e)).hide())},onfocusout:function(e,t){!this.checkable(e)&&(e.name in this.submitted||!this.optional(e))&&this.element(e)},onkeyup:function(e,t){if(t.which===9&&this.elementValue(e)==="")return;(e.name in this.submitted||e===this.lastElement)&&this.element(e)},onclick:function(e,t){e.name in this.submitted?this.element(e):e.parentNode.name in this.submitted&&this.element(e.parentNode)},highlight:function(t,n,r){t.type==="radio"?this.findByName(t.name).addClass(n).removeClass(r):e(t).addClass(n).removeClass(r)},unhighlight:function(t,n,r){t.type==="radio"?this.findByName(t.name).removeClass(n).addClass(r):e(t).removeClass(n).addClass(r)}},setDefaults:function(t){e.extend(e.validator.defaults,t)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:e.validator.format("Please enter no more than {0} characters."),minlength:e.validator.format("Please enter at least {0} characters."),rangelength:e.validator.format("Please enter a value between {0} and {1} characters long."),range:e.validator.format("Please enter a value between {0} and {1}."),max:e.validator.format("Please enter a value less than or equal to {0}."),min:e.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function r(t){var n=e.data(this[0].form,"validator"),r="on"+t.type.replace(/^validate/,"");n.settings[r]&&n.settings[r].call(n,this[0],t)}this.labelContainer=e(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||e(this.currentForm),this.containers=e(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var t=this.groups={};e.each(this.settings.groups,function(n,r){typeof r=="string"&&(r=r.split(/\s/)),e.each(r,function(e,r){t[r]=n})});var n=this.settings.rules;e.each(n,function(t,r){n[t]=e.validator.normalizeRule(r)}),e(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'] ","focusin focusout keyup",r).validateDelegate("[type='radio'], [type='checkbox'], select, option","click",r),this.settings.invalidHandler&&e(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),e.extend(this.submitted,this.errorMap),this.invalid=e.extend({},this.errorMap),this.valid()||e(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var e=0,t=this.currentElements=this.elements();t[e];e++)this.check(t[e]);return this.valid()},element:function(t){t=this.validationTargetFor(this.clean(t)),this.lastElement=t,this.prepareElement(t),this.currentElements=e(t);var n=this.check(t)!==!1;return n?delete this.invalid[t.name]:this.invalid[t.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),n},showErrors:function(t){if(t){e.extend(this.errorMap,t),this.errorList=[];for(var n in t)this.errorList.push({message:t[n],element:this.findByName(n)[0]});this.successList=e.grep(this.successList,function(e){return!(e.name in t)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){e.fn.resetForm&&e(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(e){var t=0;for(var n in e)t++;return t},hideErrors:function(){this.addWrapper(this.toHide).hide()},valid:function(){return this.size()===0},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{e(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(t){}},findLastActive:function(){var t=this.lastActive;return t&&e.grep(this.errorList,function(e){return e.element.name===t.name}).length===1&&t},elements:function(){var t=this,n={};return e(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){return!this.name&&t.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in n||!t.objectLength(e(this).rules())?!1:(n[this.name]=!0,!0)})},clean:function(t){return e(t)[0]},errors:function(){var t=this.settings.errorClass.replace(" ",".");return e(this.settings.errorElement+"."+t,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=e([]),this.toHide=e([]),this.currentElements=e([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(e){this.reset(),this.toHide=this.errorsFor(e)},elementValue:function(t){var n=e(t).attr("type"),r=e(t).val();return n==="radio"||n==="checkbox"?e("input[name='"+e(t).attr("name")+"']:checked").val():typeof r=="string"?r.replace(/\r/g,""):r},check:function(t){t=this.validationTargetFor(this.clean(t));var n=e(t).rules(),r=!1,i=this.elementValue(t),s;for(var o in n){var u={method:o,parameters:n[o]};try{s=e.validator.methods[o].call(this,i,t,u.parameters);if(s==="dependency-mismatch"){r=!0;continue}r=!1;if(s==="pending"){this.toHide=this.toHide.not(this.errorsFor(t));return}if(!s)return this.formatAndAdd(t,u),!1}catch(a){throw this.settings.debug&&window.console&&console.log("Exception occured when checking element "+t.id+", check the '"+u.method+"' method.",a),a}}if(r)return;return this.objectLength(n)&&this.successList.push(t),!0},customDataMessage:function(t,n){return e(t).data("msg-"+n.toLowerCase())||t.attributes&&e(t).attr("data-msg-"+n.toLowerCase())},customMessage:function(e,t){var n=this.settings.messages[e];return n&&(n.constructor===String?n:n[t])},findDefined:function(){for(var e=0;e<arguments.length;e++)if(arguments[e]!==undefined)return arguments[e];return undefined},defaultMessage:function(t,n){return this.findDefined(this.customMessage(t.name,n),this.customDataMessage(t,n),!this.settings.ignoreTitle&&t.title||undefined,e.validator.messages[n],"<strong>Warning: No message defined for "+t.name+"</strong>")},formatAndAdd:function(t,n){var r=this.defaultMessage(t,n.method),i=/\$?\{(\d+)\}/g;typeof r=="function"?r=r.call(this,n.parameters,t):i.test(r)&&(r=e.validator.format(r.replace(i,"{$1}"),n.parameters)),this.errorList.push({message:r,element:t}),this.errorMap[t.name]=r,this.submitted[t.name]=r},addWrapper:function(e){return this.settings.wrapper&&(e=e.add(e.parent(this.settings.wrapper))),e},defaultShowErrors:function(){var e,t;for(e=0;this.errorList[e];e++){var n=this.errorList[e];this.settings.highlight&&this.settings.highlight.call(this,n.element,this.settings.errorClass,this.settings.validClass),this.showLabel(n.element,n.message)}this.errorList.length&&(this.toShow=this.toShow.add(this.containers));if(this.settings.success)for(e=0;this.successList[e];e++)this.showLabel(this.successList[e]);if(this.settings.unhighlight)for(e=0,t=this.validElements();t[e];e++)this.settings.unhighlight.call(this,t[e],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return e(this.errorList).map(function(){return this.element})},showLabel:function(t,n){var r=this.errorsFor(t);r.length?(r.removeClass(this.settings.validClass).addClass(this.settings.errorClass),r.html(n)):(r=e("<"+this.settings.errorElement+">").attr("for",this.idOrName(t)).addClass(this.settings.errorClass).html(n||""),this.settings.wrapper&&(r=r.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.append(r).length||(this.settings.errorPlacement?this.settings.errorPlacement(r,e(t)):r.insertAfter(t))),!n&&this.settings.success&&(r.text(""),typeof this.settings.success=="string"?r.addClass(this.settings.success):this.settings.success(r,t)),this.toShow=this.toShow.add(r)},errorsFor:function(t){var n=this.idOrName(t);return this.errors().filter(function(){return e(this).attr("for")===n})},idOrName:function(e){return this.groups[e.name]||(this.checkable(e)?e.name:e.id||e.name)},validationTargetFor:function(e){return this.checkable(e)&&(e=this.findByName(e.name).not(this.settings.ignore)[0]),e},checkable:function(e){return/radio|checkbox/i.test(e.type)},findByName:function(t){return e(this.currentForm).find("[name='"+t+"']")},getLength:function(t,n){switch(n.nodeName.toLowerCase()){case"select":return e("option:selected",n).length;case"input":if(this.checkable(n))return this.findByName(n.name).filter(":checked").length}return t.length},depend:function(e,t){return this.dependTypes[typeof e]?this.dependTypes[typeof e](e,t):!0},dependTypes:{"boolean":function(e,t){return e},string:function(t,n){return!!e(t,n.form).length},"function":function(e,t){return e(t)}},optional:function(t){var n=this.elementValue(t);return!e.validator.methods.required.call(this,n,t)&&"dependency-mismatch"},startRequest:function(e){this.pending[e.name]||(this.pendingRequest++,this.pending[e.name]=!0)},stopRequest:function(t,n){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[t.name],n&&this.pendingRequest===0&&this.formSubmitted&&this.form()?(e(this.currentForm).submit(),this.formSubmitted=!1):!n&&this.pendingRequest===0&&this.formSubmitted&&(e(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(t){return e.data(t,"previousValue")||e.data(t,"previousValue",{old:null,valid:!0,message:this.defaultMessage(t,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(t,n){t.constructor===String?this.classRuleSettings[t]=n:e.extend(this.classRuleSettings,t)},classRules:function(t){var n={},r=e(t).attr("class");return r&&e.each(r.split(" "),function(){this in e.validator.classRuleSettings&&e.extend(n,e.validator.classRuleSettings[this])}),n},attributeRules:function(t){var n={},r=e(t);for(var i in e.validator.methods){var s;i==="required"?(s=r.get(0).getAttribute(i),s===""&&(s=!0),s=!!s):s=r.attr(i),s?n[i]=s:r[0].getAttribute("type")===i&&(n[i]=!0)}return n.maxlength&&/-1|2147483647|524288/.test(n.maxlength)&&delete n.maxlength,n},dataRules:function(t){var n,r,i={},s=e(t);for(n in e.validator.methods)r=s.data("rule-"+n.toLowerCase()),r!==undefined&&(i[n]=r);return i},staticRules:function(t){var n={},r=e.data(t.form,"validator");return r.settings.rules&&(n=e.validator.normalizeRule(r.settings.rules[t.name])||{}),n},normalizeRules:function(t,n){return e.each(t,function(r,i){if(i===!1){delete t[r];return}if(i.param||i.depends){var s=!0;switch(typeof i.depends){case"string":s=!!e(i.depends,n.form).length;break;case"function":s=i.depends.call(n,n)}s?t[r]=i.param!==undefined?i.param:!0:delete t[r]}}),e.each(t,function(r,i){t[r]=e.isFunction(i)?i(n):i}),e.each(["minlength","maxlength"],function(){t[this]&&(t[this]=Number(t[this]))}),e.each(["rangelength"],function(){var n;t[this]&&(e.isArray(t[this])?t[this]=[Number(t[this][0]),Number(t[this][1])]:typeof t[this]=="string"&&(n=t[this].split(/[\s,]+/),t[this]=[Number(n[0]),Number(n[1])]))}),e.validator.autoCreateRanges&&(t.min&&t.max&&(t.range=[t.min,t.max],delete t.min,delete t.max),t.minlength&&t.maxlength&&(t.rangelength=[t.minlength,t.maxlength],delete t.minlength,delete t.maxlength)),t},normalizeRule:function(t){if(typeof t=="string"){var n={};e.each(t.split(/\s/),function(){n[this]=!0}),t=n}return t},addMethod:function(t,n,r){e.validator.methods[t]=n,e.validator.messages[t]=r!==undefined?r:e.validator.messages[t],n.length<3&&e.validator.addClassRules(t,e.validator.normalizeRule(t))},methods:{required:function(t,n,r){if(!this.depend(r,n))return"dependency-mismatch";if(n.nodeName.toLowerCase()==="select"){var i=e(n).val();return i&&i.length>0}return this.checkable(n)?this.getLength(t,n)>0:e.trim(t).length>0},remote:function(t,n,r){if(this.optional(n))return"dependency-mismatch";var i=this.previousValue(n);this.settings.messages[n.name]||(this.settings.messages[n.name]={}),i.originalMessage=this.settings.messages[n.name].remote,this.settings.messages[n.name].remote=i.message,r=typeof r=="string"&&{url:r}||r;if(i.old===t)return i.valid;i.old=t;var s=this;this.startRequest(n);var o={};return o[n.name]=t,e.ajax(e.extend(!0,{url:r,mode:"abort",port:"validate"+n.name,dataType:"json",data:o,success:function(r){s.settings.messages[n.name].remote=i.originalMessage;var o=r===!0||r==="true";if(o){var u=s.formSubmitted;s.prepareElement(n),s.formSubmitted=u,s.successList.push(n),delete s.invalid[n.name],s.showErrors()}else{var a={},f=r||s.defaultMessage(n,"remote");a[n.name]=i.message=e.isFunction(f)?f(t):f,s.invalid[n.name]=!0,s.showErrors(a)}i.valid=o,s.stopRequest(n,o)}},r)),"pending"},minlength:function(t,n,r){var i=e.isArray(t)?t.length:this.getLength(e.trim(t),n);return this.optional(n)||i>=r},maxlength:function(t,n,r){var i=e.isArray(t)?t.length:this.getLength(e.trim(t),n);return this.optional(n)||i<=r},rangelength:function(t,n,r){var i=e.isArray(t)?t.length:this.getLength(e.trim(t),n);return this.optional(n)||i>=r[0]&&i<=r[1]},min:function(e,t,n){return this.optional(t)||e>=n},max:function(e,t,n){return this.optional(t)||e<=n},range:function(e,t,n){return this.optional(t)||e>=n[0]&&e<=n[1]},email:function(e,t){return this.optional(t)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(e)},url:function(e,t){return this.optional(t)||/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(e)},date:function(e,t){return this.optional(t)||!/Invalid|NaN/.test((new Date(e)).toString())},dateISO:function(e,t){return this.optional(t)||/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(e)},number:function(e,t){return this.optional(t)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(e)},digits:function(e,t){return this.optional(t)||/^\d+$/.test(e)},creditcard:function(e,t){if(this.optional(t))return"dependency-mismatch";if(/[^0-9 \-]+/.test(e))return!1;var n=0,r=0,i=!1;e=e.replace(/\D/g,"");for(var s=e.length-1;s>=0;s--){var o=e.charAt(s);r=parseInt(o,10),i&&(r*=2)>9&&(r-=9),n+=r,i=!i}return n%10===0},equalTo:function(t,n,r){var i=e(r);return this.settings.onfocusout&&i.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){e(n).valid()}),t===i.val()}}}),e.format=e.validator.format})(jQuery),function(e){var t={};if(e.ajaxPrefilter)e.ajaxPrefilter(function(e,n,r){var i=e.port;e.mode==="abort"&&(t[i]&&t[i].abort(),t[i]=r)});else{var n=e.ajax;e.ajax=function(r){var i=("mode"in r?r:e.ajaxSettings).mode,s=("port"in r?r:e.ajaxSettings).port;return i==="abort"?(t[s]&&t[s].abort(),t[s]=n.apply(this,arguments)):n.apply(this,arguments)}}}(jQuery),function(e){e.extend(e.fn,{validateDelegate:function(t,n,r){return this.bind(n,function(n){var i=e(n.target);if(i.is(t))return r.apply(i,arguments)})}})}(jQuery);
1
+ /*! jQuery Validation Plugin - v1.19.3 - 1/9/2021
2
+ * https://jqueryvalidation.org/
3
+ * Copyright (c) 2021 Jörn Zaefferer; Licensed MIT */
4
+ !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof module&&module.exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.extend(a.fn,{validate:function(b){if(!this.length)return void(b&&b.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."));var c=a.data(this[0],"validator");return c?c:(this.attr("novalidate","novalidate"),c=new a.validator(b,this[0]),a.data(this[0],"validator",c),c.settings.onsubmit&&(this.on("click.validate",":submit",function(b){c.submitButton=b.currentTarget,a(this).hasClass("cancel")&&(c.cancelSubmit=!0),void 0!==a(this).attr("formnovalidate")&&(c.cancelSubmit=!0)}),this.on("submit.validate",function(b){function d(){var d,e;return c.submitButton&&(c.settings.submitHandler||c.formSubmitted)&&(d=a("<input type='hidden'/>").attr("name",c.submitButton.name).val(a(c.submitButton).val()).appendTo(c.currentForm)),!(c.settings.submitHandler&&!c.settings.debug)||(e=c.settings.submitHandler.call(c,c.currentForm,b),d&&d.remove(),void 0!==e&&e)}return c.settings.debug&&b.preventDefault(),c.cancelSubmit?(c.cancelSubmit=!1,d()):c.form()?c.pendingRequest?(c.formSubmitted=!0,!1):d():(c.focusInvalid(),!1)})),c)},valid:function(){var b,c,d;return a(this[0]).is("form")?b=this.validate().form():(d=[],b=!0,c=a(this[0].form).validate(),this.each(function(){b=c.element(this)&&b,b||(d=d.concat(c.errorList))}),c.errorList=d),b},rules:function(b,c){var d,e,f,g,h,i,j=this[0],k="undefined"!=typeof this.attr("contenteditable")&&"false"!==this.attr("contenteditable");if(null!=j&&(!j.form&&k&&(j.form=this.closest("form")[0],j.name=this.attr("name")),null!=j.form)){if(b)switch(d=a.data(j.form,"validator").settings,e=d.rules,f=a.validator.staticRules(j),b){case"add":a.extend(f,a.validator.normalizeRule(c)),delete f.messages,e[j.name]=f,c.messages&&(d.messages[j.name]=a.extend(d.messages[j.name],c.messages));break;case"remove":return c?(i={},a.each(c.split(/\s/),function(a,b){i[b]=f[b],delete f[b]}),i):(delete e[j.name],f)}return g=a.validator.normalizeRules(a.extend({},a.validator.classRules(j),a.validator.attributeRules(j),a.validator.dataRules(j),a.validator.staticRules(j)),j),g.required&&(h=g.required,delete g.required,g=a.extend({required:h},g)),g.remote&&(h=g.remote,delete g.remote,g=a.extend(g,{remote:h})),g}}});var b=function(a){return a.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,"")};a.extend(a.expr.pseudos||a.expr[":"],{blank:function(c){return!b(""+a(c).val())},filled:function(c){var d=a(c).val();return null!==d&&!!b(""+d)},unchecked:function(b){return!a(b).prop("checked")}}),a.validator=function(b,c){this.settings=a.extend(!0,{},a.validator.defaults,b),this.currentForm=c,this.init()},a.validator.format=function(b,c){return 1===arguments.length?function(){var c=a.makeArray(arguments);return c.unshift(b),a.validator.format.apply(this,c)}:void 0===c?b:(arguments.length>2&&c.constructor!==Array&&(c=a.makeArray(arguments).slice(1)),c.constructor!==Array&&(c=[c]),a.each(c,function(a,c){b=b.replace(new RegExp("\\{"+a+"\\}","g"),function(){return c})}),b)},a.extend(a.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",pendingClass:"pending",validClass:"valid",errorElement:"label",focusCleanup:!1,focusInvalid:!0,errorContainer:a([]),errorLabelContainer:a([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(a){this.lastActive=a,this.settings.focusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,a,this.settings.errorClass,this.settings.validClass),this.hideThese(this.errorsFor(a)))},onfocusout:function(a){this.checkable(a)||!(a.name in this.submitted)&&this.optional(a)||this.element(a)},onkeyup:function(b,c){var d=[16,17,18,20,35,36,37,38,39,40,45,144,225];9===c.which&&""===this.elementValue(b)||a.inArray(c.keyCode,d)!==-1||(b.name in this.submitted||b.name in this.invalid)&&this.element(b)},onclick:function(a){a.name in this.submitted?this.element(a):a.parentNode.name in this.submitted&&this.element(a.parentNode)},highlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).addClass(c).removeClass(d):a(b).addClass(c).removeClass(d)},unhighlight:function(b,c,d){"radio"===b.type?this.findByName(b.name).removeClass(c).addClass(d):a(b).removeClass(c).addClass(d)}},setDefaults:function(b){a.extend(a.validator.defaults,b)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",equalTo:"Please enter the same value again.",maxlength:a.validator.format("Please enter no more than {0} characters."),minlength:a.validator.format("Please enter at least {0} characters."),rangelength:a.validator.format("Please enter a value between {0} and {1} characters long."),range:a.validator.format("Please enter a value between {0} and {1}."),max:a.validator.format("Please enter a value less than or equal to {0}."),min:a.validator.format("Please enter a value greater than or equal to {0}."),step:a.validator.format("Please enter a multiple of {0}.")},autoCreateRanges:!1,prototype:{init:function(){function b(b){var c="undefined"!=typeof a(this).attr("contenteditable")&&"false"!==a(this).attr("contenteditable");if(!this.form&&c&&(this.form=a(this).closest("form")[0],this.name=a(this).attr("name")),d===this.form){var e=a.data(this.form,"validator"),f="on"+b.type.replace(/^validate/,""),g=e.settings;g[f]&&!a(this).is(g.ignore)&&g[f].call(e,this,b)}}this.labelContainer=a(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||a(this.currentForm),this.containers=a(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var c,d=this.currentForm,e=this.groups={};a.each(this.settings.groups,function(b,c){"string"==typeof c&&(c=c.split(/\s/)),a.each(c,function(a,c){e[c]=b})}),c=this.settings.rules,a.each(c,function(b,d){c[b]=a.validator.normalizeRule(d)}),a(this.currentForm).on("focusin.validate focusout.validate keyup.validate",":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'], [type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'], [type='radio'], [type='checkbox'], [contenteditable], [type='button']",b).on("click.validate","select, option, [type='radio'], [type='checkbox']",b),this.settings.invalidHandler&&a(this.currentForm).on("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),a.extend(this.submitted,this.errorMap),this.invalid=a.extend({},this.errorMap),this.valid()||a(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var a=0,b=this.currentElements=this.elements();b[a];a++)this.check(b[a]);return this.valid()},element:function(b){var c,d,e=this.clean(b),f=this.validationTargetFor(e),g=this,h=!0;return void 0===f?delete this.invalid[e.name]:(this.prepareElement(f),this.currentElements=a(f),d=this.groups[f.name],d&&a.each(this.groups,function(a,b){b===d&&a!==f.name&&(e=g.validationTargetFor(g.clean(g.findByName(a))),e&&e.name in g.invalid&&(g.currentElements.push(e),h=g.check(e)&&h))}),c=this.check(f)!==!1,h=h&&c,c?this.invalid[f.name]=!1:this.invalid[f.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),a(b).attr("aria-invalid",!c)),h},showErrors:function(b){if(b){var c=this;a.extend(this.errorMap,b),this.errorList=a.map(this.errorMap,function(a,b){return{message:a,element:c.findByName(b)[0]}}),this.successList=a.grep(this.successList,function(a){return!(a.name in b)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){a.fn.resetForm&&a(this.currentForm).resetForm(),this.invalid={},this.submitted={},this.prepareForm(),this.hideErrors();var b=this.elements().removeData("previousValue").removeAttr("aria-invalid");this.resetElements(b)},resetElements:function(a){var b;if(this.settings.unhighlight)for(b=0;a[b];b++)this.settings.unhighlight.call(this,a[b],this.settings.errorClass,""),this.findByName(a[b].name).removeClass(this.settings.validClass);else a.removeClass(this.settings.errorClass).removeClass(this.settings.validClass)},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(a){var b,c=0;for(b in a)void 0!==a[b]&&null!==a[b]&&a[b]!==!1&&c++;return c},hideErrors:function(){this.hideThese(this.toHide)},hideThese:function(a){a.not(this.containers).text(""),this.addWrapper(a).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{a(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").trigger("focus").trigger("focusin")}catch(b){}},findLastActive:function(){var b=this.lastActive;return b&&1===a.grep(this.errorList,function(a){return a.element.name===b.name}).length&&b},elements:function(){var b=this,c={};return a(this.currentForm).find("input, select, textarea, [contenteditable]").not(":submit, :reset, :image, :disabled").not(this.settings.ignore).filter(function(){var d=this.name||a(this).attr("name"),e="undefined"!=typeof a(this).attr("contenteditable")&&"false"!==a(this).attr("contenteditable");return!d&&b.settings.debug&&window.console&&console.error("%o has no name assigned",this),e&&(this.form=a(this).closest("form")[0],this.name=d),this.form===b.currentForm&&(!(d in c||!b.objectLength(a(this).rules()))&&(c[d]=!0,!0))})},clean:function(b){return a(b)[0]},errors:function(){var b=this.settings.errorClass.split(" ").join(".");return a(this.settings.errorElement+"."+b,this.errorContext)},resetInternals:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=a([]),this.toHide=a([])},reset:function(){this.resetInternals(),this.currentElements=a([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(a){this.reset(),this.toHide=this.errorsFor(a)},elementValue:function(b){var c,d,e=a(b),f=b.type,g="undefined"!=typeof e.attr("contenteditable")&&"false"!==e.attr("contenteditable");return"radio"===f||"checkbox"===f?this.findByName(b.name).filter(":checked").val():"number"===f&&"undefined"!=typeof b.validity?b.validity.badInput?"NaN":e.val():(c=g?e.text():e.val(),"file"===f?"C:\\fakepath\\"===c.substr(0,12)?c.substr(12):(d=c.lastIndexOf("/"),d>=0?c.substr(d+1):(d=c.lastIndexOf("\\"),d>=0?c.substr(d+1):c)):"string"==typeof c?c.replace(/\r/g,""):c)},check:function(b){b=this.validationTargetFor(this.clean(b));var c,d,e,f,g=a(b).rules(),h=a.map(g,function(a,b){return b}).length,i=!1,j=this.elementValue(b);"function"==typeof g.normalizer?f=g.normalizer:"function"==typeof this.settings.normalizer&&(f=this.settings.normalizer),f&&(j=f.call(b,j),delete g.normalizer);for(d in g){e={method:d,parameters:g[d]};try{if(c=a.validator.methods[d].call(this,j,b,e.parameters),"dependency-mismatch"===c&&1===h){i=!0;continue}if(i=!1,"pending"===c)return void(this.toHide=this.toHide.not(this.errorsFor(b)));if(!c)return this.formatAndAdd(b,e),!1}catch(k){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+b.id+", check the '"+e.method+"' method.",k),k instanceof TypeError&&(k.message+=". Exception occurred when checking element "+b.id+", check the '"+e.method+"' method."),k}}if(!i)return this.objectLength(g)&&this.successList.push(b),!0},customDataMessage:function(b,c){return a(b).data("msg"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase())||a(b).data("msg")},customMessage:function(a,b){var c=this.settings.messages[a];return c&&(c.constructor===String?c:c[b])},findDefined:function(){for(var a=0;a<arguments.length;a++)if(void 0!==arguments[a])return arguments[a]},defaultMessage:function(b,c){"string"==typeof c&&(c={method:c});var d=this.findDefined(this.customMessage(b.name,c.method),this.customDataMessage(b,c.method),!this.settings.ignoreTitle&&b.title||void 0,a.validator.messages[c.method],"<strong>Warning: No message defined for "+b.name+"</strong>"),e=/\$?\{(\d+)\}/g;return"function"==typeof d?d=d.call(this,c.parameters,b):e.test(d)&&(d=a.validator.format(d.replace(e,"{$1}"),c.parameters)),d},formatAndAdd:function(a,b){var c=this.defaultMessage(a,b);this.errorList.push({message:c,element:a,method:b.method}),this.errorMap[a.name]=c,this.submitted[a.name]=c},addWrapper:function(a){return this.settings.wrapper&&(a=a.add(a.parent(this.settings.wrapper))),a},defaultShowErrors:function(){var a,b,c;for(a=0;this.errorList[a];a++)c=this.errorList[a],this.settings.highlight&&this.settings.highlight.call(this,c.element,this.settings.errorClass,this.settings.validClass),this.showLabel(c.element,c.message);if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(a=0;this.successList[a];a++)this.showLabel(this.successList[a]);if(this.settings.unhighlight)for(a=0,b=this.validElements();b[a];a++)this.settings.unhighlight.call(this,b[a],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return a(this.errorList).map(function(){return this.element})},showLabel:function(b,c){var d,e,f,g,h=this.errorsFor(b),i=this.idOrName(b),j=a(b).attr("aria-describedby");h.length?(h.removeClass(this.settings.validClass).addClass(this.settings.errorClass),h.html(c)):(h=a("<"+this.settings.errorElement+">").attr("id",i+"-error").addClass(this.settings.errorClass).html(c||""),d=h,this.settings.wrapper&&(d=h.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.length?this.labelContainer.append(d):this.settings.errorPlacement?this.settings.errorPlacement.call(this,d,a(b)):d.insertAfter(b),h.is("label")?h.attr("for",i):0===h.parents("label[for='"+this.escapeCssMeta(i)+"']").length&&(f=h.attr("id"),j?j.match(new RegExp("\\b"+this.escapeCssMeta(f)+"\\b"))||(j+=" "+f):j=f,a(b).attr("aria-describedby",j),e=this.groups[b.name],e&&(g=this,a.each(g.groups,function(b,c){c===e&&a("[name='"+g.escapeCssMeta(b)+"']",g.currentForm).attr("aria-describedby",h.attr("id"))})))),!c&&this.settings.success&&(h.text(""),"string"==typeof this.settings.success?h.addClass(this.settings.success):this.settings.success(h,b)),this.toShow=this.toShow.add(h)},errorsFor:function(b){var c=this.escapeCssMeta(this.idOrName(b)),d=a(b).attr("aria-describedby"),e="label[for='"+c+"'], label[for='"+c+"'] *";return d&&(e=e+", #"+this.escapeCssMeta(d).replace(/\s+/g,", #")),this.errors().filter(e)},escapeCssMeta:function(a){return a.replace(/([\\!"#$%&'()*+,.\/:;<=>?@\[\]^`{|}~])/g,"\\$1")},idOrName:function(a){return this.groups[a.name]||(this.checkable(a)?a.name:a.id||a.name)},validationTargetFor:function(b){return this.checkable(b)&&(b=this.findByName(b.name)),a(b).not(this.settings.ignore)[0]},checkable:function(a){return/radio|checkbox/i.test(a.type)},findByName:function(b){return a(this.currentForm).find("[name='"+this.escapeCssMeta(b)+"']")},getLength:function(b,c){switch(c.nodeName.toLowerCase()){case"select":return a("option:selected",c).length;case"input":if(this.checkable(c))return this.findByName(c.name).filter(":checked").length}return b.length},depend:function(a,b){return!this.dependTypes[typeof a]||this.dependTypes[typeof a](a,b)},dependTypes:{"boolean":function(a){return a},string:function(b,c){return!!a(b,c.form).length},"function":function(a,b){return a(b)}},optional:function(b){var c=this.elementValue(b);return!a.validator.methods.required.call(this,c,b)&&"dependency-mismatch"},startRequest:function(b){this.pending[b.name]||(this.pendingRequest++,a(b).addClass(this.settings.pendingClass),this.pending[b.name]=!0)},stopRequest:function(b,c){this.pendingRequest--,this.pendingRequest<0&&(this.pendingRequest=0),delete this.pending[b.name],a(b).removeClass(this.settings.pendingClass),c&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(a(this.currentForm).submit(),this.submitButton&&a("input:hidden[name='"+this.submitButton.name+"']",this.currentForm).remove(),this.formSubmitted=!1):!c&&0===this.pendingRequest&&this.formSubmitted&&(a(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(b,c){return c="string"==typeof c&&c||"remote",a.data(b,"previousValue")||a.data(b,"previousValue",{old:null,valid:!0,message:this.defaultMessage(b,{method:c})})},destroy:function(){this.resetForm(),a(this.currentForm).off(".validate").removeData("validator").find(".validate-equalTo-blur").off(".validate-equalTo").removeClass("validate-equalTo-blur").find(".validate-lessThan-blur").off(".validate-lessThan").removeClass("validate-lessThan-blur").find(".validate-lessThanEqual-blur").off(".validate-lessThanEqual").removeClass("validate-lessThanEqual-blur").find(".validate-greaterThanEqual-blur").off(".validate-greaterThanEqual").removeClass("validate-greaterThanEqual-blur").find(".validate-greaterThan-blur").off(".validate-greaterThan").removeClass("validate-greaterThan-blur")}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(b,c){b.constructor===String?this.classRuleSettings[b]=c:a.extend(this.classRuleSettings,b)},classRules:function(b){var c={},d=a(b).attr("class");return d&&a.each(d.split(" "),function(){this in a.validator.classRuleSettings&&a.extend(c,a.validator.classRuleSettings[this])}),c},normalizeAttributeRule:function(a,b,c,d){/min|max|step/.test(c)&&(null===b||/number|range|text/.test(b))&&(d=Number(d),isNaN(d)&&(d=void 0)),d||0===d?a[c]=d:b===c&&"range"!==b&&(a[c]=!0)},attributeRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)"required"===c?(d=b.getAttribute(c),""===d&&(d=!0),d=!!d):d=f.attr(c),this.normalizeAttributeRule(e,g,c,d);return e.maxlength&&/-1|2147483647|524288/.test(e.maxlength)&&delete e.maxlength,e},dataRules:function(b){var c,d,e={},f=a(b),g=b.getAttribute("type");for(c in a.validator.methods)d=f.data("rule"+c.charAt(0).toUpperCase()+c.substring(1).toLowerCase()),""===d&&(d=!0),this.normalizeAttributeRule(e,g,c,d);return e},staticRules:function(b){var c={},d=a.data(b.form,"validator");return d.settings.rules&&(c=a.validator.normalizeRule(d.settings.rules[b.name])||{}),c},normalizeRules:function(b,c){return a.each(b,function(d,e){if(e===!1)return void delete b[d];if(e.param||e.depends){var f=!0;switch(typeof e.depends){case"string":f=!!a(e.depends,c.form).length;break;case"function":f=e.depends.call(c,c)}f?b[d]=void 0===e.param||e.param:(a.data(c.form,"validator").resetElements(a(c)),delete b[d])}}),a.each(b,function(a,d){b[a]="function"==typeof d&&"normalizer"!==a?d(c):d}),a.each(["minlength","maxlength"],function(){b[this]&&(b[this]=Number(b[this]))}),a.each(["rangelength","range"],function(){var a;b[this]&&(Array.isArray(b[this])?b[this]=[Number(b[this][0]),Number(b[this][1])]:"string"==typeof b[this]&&(a=b[this].replace(/[\[\]]/g,"").split(/[\s,]+/),b[this]=[Number(a[0]),Number(a[1])]))}),a.validator.autoCreateRanges&&(null!=b.min&&null!=b.max&&(b.range=[b.min,b.max],delete b.min,delete b.max),null!=b.minlength&&null!=b.maxlength&&(b.rangelength=[b.minlength,b.maxlength],delete b.minlength,delete b.maxlength)),b},normalizeRule:function(b){if("string"==typeof b){var c={};a.each(b.split(/\s/),function(){c[this]=!0}),b=c}return b},addMethod:function(b,c,d){a.validator.methods[b]=c,a.validator.messages[b]=void 0!==d?d:a.validator.messages[b],c.length<3&&a.validator.addClassRules(b,a.validator.normalizeRule(b))},methods:{required:function(b,c,d){if(!this.depend(d,c))return"dependency-mismatch";if("select"===c.nodeName.toLowerCase()){var e=a(c).val();return e&&e.length>0}return this.checkable(c)?this.getLength(b,c)>0:void 0!==b&&null!==b&&b.length>0},email:function(a,b){return this.optional(b)||/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test(a)},url:function(a,b){return this.optional(b)||/^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z0-9\u00a1-\uffff][a-z0-9\u00a1-\uffff_-]{0,62})?[a-z0-9\u00a1-\uffff]\.)+(?:[a-z\u00a1-\uffff]{2,}\.?))(?::\d{2,5})?(?:[\/?#]\S*)?$/i.test(a)},date:function(){var a=!1;return function(b,c){return a||(a=!0,this.settings.debug&&window.console&&console.warn("The `date` method is deprecated and will be removed in version '2.0.0'.\nPlease don't use it, since it relies on the Date constructor, which\nbehaves very differently across browsers and locales. Use `dateISO`\ninstead or one of the locale specific methods in `localizations/`\nand `additional-methods.js`.")),this.optional(c)||!/Invalid|NaN/.test(new Date(b).toString())}}(),dateISO:function(a,b){return this.optional(b)||/^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(a)},number:function(a,b){return this.optional(b)||/^(?:-?\d+|-?\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(a)},digits:function(a,b){return this.optional(b)||/^\d+$/.test(a)},minlength:function(a,b,c){var d=Array.isArray(a)?a.length:this.getLength(a,b);return this.optional(b)||d>=c},maxlength:function(a,b,c){var d=Array.isArray(a)?a.length:this.getLength(a,b);return this.optional(b)||d<=c},rangelength:function(a,b,c){var d=Array.isArray(a)?a.length:this.getLength(a,b);return this.optional(b)||d>=c[0]&&d<=c[1]},min:function(a,b,c){return this.optional(b)||a>=c},max:function(a,b,c){return this.optional(b)||a<=c},range:function(a,b,c){return this.optional(b)||a>=c[0]&&a<=c[1]},step:function(b,c,d){var e,f=a(c).attr("type"),g="Step attribute on input type "+f+" is not supported.",h=["text","number","range"],i=new RegExp("\\b"+f+"\\b"),j=f&&!i.test(h.join()),k=function(a){var b=(""+a).match(/(?:\.(\d+))?$/);return b&&b[1]?b[1].length:0},l=function(a){return Math.round(a*Math.pow(10,e))},m=!0;if(j)throw new Error(g);return e=k(d),(k(b)>e||l(b)%l(d)!==0)&&(m=!1),this.optional(c)||m},equalTo:function(b,c,d){var e=a(d);return this.settings.onfocusout&&e.not(".validate-equalTo-blur").length&&e.addClass("validate-equalTo-blur").on("blur.validate-equalTo",function(){a(c).valid()}),b===e.val()},remote:function(b,c,d,e){if(this.optional(c))return"dependency-mismatch";e="string"==typeof e&&e||"remote";var f,g,h,i=this.previousValue(c,e);return this.settings.messages[c.name]||(this.settings.messages[c.name]={}),i.originalMessage=i.originalMessage||this.settings.messages[c.name][e],this.settings.messages[c.name][e]=i.message,d="string"==typeof d&&{url:d}||d,h=a.param(a.extend({data:b},d.data)),i.old===h?i.valid:(i.old=h,f=this,this.startRequest(c),g={},g[c.name]=b,a.ajax(a.extend(!0,{mode:"abort",port:"validate"+c.name,dataType:"json",data:g,context:f.currentForm,success:function(a){var d,g,h,j=a===!0||"true"===a;f.settings.messages[c.name][e]=i.originalMessage,j?(h=f.formSubmitted,f.resetInternals(),f.toHide=f.errorsFor(c),f.formSubmitted=h,f.successList.push(c),f.invalid[c.name]=!1,f.showErrors()):(d={},g=a||f.defaultMessage(c,{method:e,parameters:b}),d[c.name]=i.message=g,f.invalid[c.name]=!0,f.showErrors(d)),i.valid=j,f.stopRequest(c,j)}},d)),"pending")}}});var c,d={};return a.ajaxPrefilter?a.ajaxPrefilter(function(a,b,c){var e=a.port;"abort"===a.mode&&(d[e]&&d[e].abort(),d[e]=c)}):(c=a.ajax,a.ajax=function(b){var e=("mode"in b?b:a.ajaxSettings).mode,f=("port"in b?b:a.ajaxSettings).port;return"abort"===e?(d[f]&&d[f].abort(),d[f]=c.apply(this,arguments),d[f]):c.apply(this,arguments)}),a});
languages/clean-and-simple-contact-form-by-meg-nicholas_pl_PL.mo DELETED
Binary file
readme.txt CHANGED
@@ -1,431 +1,427 @@
1
- === Contact Form Clean and Simple ===
2
- Contributors: megnicholas
3
- Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=AKQM4KSBQ4H66
4
- License: GPLv2 or later
5
- License URI: http://www.gnu.org/licenses/gpl.html
6
- Tags: simple, contact, form, contact button, contact form, contact form plugin, akismet, contacts, contacts form plugin, contact me, feedback form, bootstrap, twitter, google, reCAPTCHA, ajax, secure
7
- Requires at least: 3.3
8
- Tested up to: 5.3
9
- Stable tag: 4.7.0
10
-
11
- A clean and simple AJAX contact form with Google reCAPTCHA, Twitter Bootstrap markup and Akismet spam filtering.
12
-
13
- == Description ==
14
- A clean and simple AJAX contact form with Google reCAPTCHA, Twitter Bootstrap markup and Akismet spam filtering.
15
-
16
- * **Clean**: all user inputs are stripped in order to avoid cross-site scripting (XSS) vulnerabilities.
17
-
18
- * **Simple**: AJAX enabled validation and submission for immediate response and guidance for your users (can be switched off).
19
-
20
- * **Stylish**: Use the included stylesheet or switch it off and use your own for seamless integration with your website.
21
- Uses **Twitter Bootstrap** classes.
22
-
23
- * **Safe**: All incoming data is scanned for spam with **Akismet**.
24
-
25
- This is a straightforward contact form for your WordPress site. There is very minimal set-up
26
- required. Simply install, activate, and then place the short code **[cscf-contact-form]** on your web page.
27
-
28
- A standard set of input boxes are provided, these include Email Address, Name, Message and a nice big ‘Send Message’ button.
29
-
30
- When your user has completed the form an email will be sent to you containing your user’s message.
31
- To reply simply click the ‘reply’ button on your email client.
32
- The email address used is the one you have set up in WordPress under Settings-> ‘General’, so do check this is correct.
33
-
34
- To help prevent spam all data is scanned via Akismet.
35
- For this to work you must have the [Akismet Plugin](http://wordpress.org/plugins/akismet/ "Akismet Plugin") installed and activated.
36
- All spam will be placed in your 'comments' list which you can then review if you want to
37
- [learn more](http://www.megnicholas.co.uk/articles/contact-form-plugin-can-detect-spam/ "Learn More").
38
-
39
- For added piece of mind this plugin also allows you to add a ‘**reCAPTCHA**’.
40
- This adds a picture of a couple of words to the bottom of the contact form.
41
- Your user must correctly type the words before the form can be submitted, and in so doing, prove that they are human.
42
-
43
- = Why Choose This Plugin? =
44
- Granted there are many plugins of this type in existence already. Why use this one in-particular?
45
-
46
- Here’s why:
47
-
48
- * Minimal setup. Simply activate the plugin and place the shortcode [cscf-contact-form] on any post or page.
49
-
50
- * **Safe**. All input entered by your user is stripped back to minimise as far as possible the likelihood of any
51
- malicious user attempting to inject a script into your website.
52
- If the Akismet plugin is activated all form data will be scanned for spam.
53
- You can turn on reCAPTCHA to avoid your form being abused by bots.
54
-
55
- * **Ajax enabled**. You have the option to turn on AJAX (client-side) validation and submission which gives your users an immediate response when completing the form without having to wait for the page to refresh.
56
-
57
- * The form can **integrate seamlessly into your website**. Turn off the plugin’s default css style sheet so that your theme’s style sheet can be used instead.
58
-
59
- * If your theme is based on **twitter bootstrap** then this plugin will fit right in because it already has all the right div’s and CSS classes for bootstrap.
60
-
61
- * This plugin will only link in its jQuery file where it’s needed, it **will not impose** itself on every page of your whole site!
62
-
63
- * Works with the **latest version of WordPress**.
64
-
65
- * Written by an **experienced PHP programmer**, the code is rock solid, safe, and rigorously tested as standard practice.
66
-
67
- Hopefully this plugin will fulfil all your needs, if not [get in-touch](http://www.megnicholas.co.uk/contact-me "Get In Touch") and I will customise to your exact requirements.
68
-
69
-
70
- == Installation ==
71
- There are two ways to install:
72
-
73
- 1. Click the ‘Install Now’ link from the plugin library listing to automatically download and install.
74
-
75
- 2. Download the plugin as a zip file. To install the zip file simply double click to extract it and place the whole folder in your wordpress plugins folder, e.g. [wordpress]/wp-content/plugins where [wordpress] is the directory that you installed WordPress in.
76
-
77
- Then visit the plugin page on your wordpress site and click ‘Activate’ against the ‘Clean and Simple Contact Form’ plugin listing.
78
-
79
- To place the contact form on your page use the shortcode [cscf-contact-form]
80
-
81
- [More information on how to use the plugin.](http://www.megnicholas.co.uk/wordpress-plugins/clean-and-simple-contact-form/ "More Information")
82
-
83
- == How to Use ==
84
- Unless you want to change messages or add reCAPTCHA to your contact form then this plugin will work out of the box without any additional setup.
85
-
86
- Important: Check that you have an email address set-up in your WordPress ‘Settings’->’General’ page. This is the address that the plugin will use to send the contents of the contact form.
87
-
88
- To add the contact form to your WordPress website simply place the shortcode [cscf-contact-form] on the post or page that you wish the form to appear on.
89
-
90
- **If you have Jetpack plugin installed disable the contact form otherwise the wrong form might display.**
91
-
92
- [More information on how to use the plugin.](http://www.megnicholas.co.uk/wordpress-plugins/clean-and-simple-contact-form/ "More Information")
93
-
94
- == Additional Settings ==
95
- This plugin will work out of the box without any additional setup. You have the option to change the default messages that are displayed to your user and to add reCAPTCHA capabilities.
96
-
97
- Go to the settings screen for the contact form plugin.
98
-
99
- You will find a link to the setting screen against the entry of this plugin on the ‘Installed Plugins’ page.
100
-
101
- Here is a list of things that you can change
102
-
103
- * **Message**: The message displayed to the user at the top of the contact form.
104
-
105
- * **Message Sent Heading**: The message heading or title displayed to the user after the message has been sent.
106
-
107
- * **Message Sent Content**: The message content or body displayed to the user after the message has been sent.
108
-
109
- * **Use this plugin’s default stylesheet**: The plugin comes with a default style sheet to make the form look nice for your user. Untick this if you want to use your theme’s stylesheet instead. The default stylesheet will simply not be linked in.
110
-
111
- * **Use client side validation (Ajax)**: When ticked the contact form will be validated and submitted on the client giving your user instant feedback if they have filled the form in incorrectly. If you wish the form to be validated and submitted only to the server then untick this option.
112
-
113
- * **Use reCAPTCHA**: Tick this option if you wish your form to have a reCAPTCHA box. ReCAPTCHA helps to avoid spam bots using your form by checking that the form filler is actually a real person. To use reCAPTCHA you will need to get a some special keys from google https://www.google.com/recaptcha/admin/create. Once you have your keys enter them into the Public key and Private key boxes
114
-
115
- * **reCAPTCHA Public Key**: Enter the public key that you obtained from here.
116
-
117
- * **reCAPTCHA Private Key**: Enter the private key that you obtained from here.
118
-
119
- * **reCAPTCHA Theme**: Here you can change the reCAPTCHA box theme so that it fits with the style of your website.
120
-
121
- * **Recipient Emails**: The email address where you would like all messages to be sent.
122
- This will default to the email address you have specified under 'E-Mail Address' in your WordPress General Settings.
123
- If you want your mail sent to a different address then enter it here.
124
- You may enter multiple email addresses by clicking the '+' button.
125
-
126
- * **Confirm Email Address**: Email confirmation is now optional. To force your user to re-type their email address tick 'Confirm Email Address'.
127
- It is recommended that you leave this option on. If you turn this option off your user will only have to enter their email address once,
128
- but if they enter it incorrectly you will have no way of getting back to them!
129
-
130
- * **Email Subject**: This is the email subject that will appear on all messages. If you would like to set it to something different then enter it here.
131
-
132
- * **Override 'From' Address**: If you tick this and then fill in the 'From Address:' box then all email will be sent from the given address NOT from the email address given by the form filler.
133
-
134
- * **Option to allow enquiry to email themselves a copy of the message.
135
-
136
- * **!NEW! Contact consent**: This option allows you to be GDPR compliant by adding a 'Consent to contact' check box at the bottom of the form.
137
-
138
-
139
- == Screenshots ==
140
- 1. Contact Form With reCAPTCHA
141
- 2. Contact Form Without reCAPTCHA
142
- 3. Message Sent
143
- 4. Contact Form Options Screen
144
- 5. Place this shortcode on your post or page to deploy
145
-
146
- == Demo ==
147
- This is a demonstration of this plugin working on the default Twenty Twelve theme ->
148
- [Clean and Simple Contact Form Demonstration](http://demo.megnicholas.co.uk/wordpress-clean-and-simple-contact-form "Plugin Demonstration")
149
-
150
- ==About Meg Nicholas ==
151
- I am a freelance WordPress Developer.
152
- [Hire me for all your Wordpress needs](http://www.megnicholas.co.uk "Hire Me").
153
-
154
- == Frequently Asked Questions ==
155
- = I get a message to say that the message could not be sent =
156
-
157
- If you get this message then you have a general problem with email on your server. This plugin uses Wordpress's send mail function.
158
- So a problem sending mail from this plugin indicates that Wordpress as a whole cannot send email.
159
- Contact your web host provider for help, or use an SMTP plugin to use a third party email service.
160
-
161
- = I don't receive the email =
162
-
163
- * Check the recipient email on your settings screen, is it correct?
164
- * Check in your spam or junk mail folder
165
- * For Gmail check in 'All Mail', the email might have gone straight to archive
166
- * Try overriding the 'From' email address in the settings screen. Use an email address you own or is from your own domain
167
-
168
- = Why is a different contact form displayed? =
169
-
170
- You may have a conflict with another plugin. Either deactivate the other contact form plugin, if you don't need it, or use
171
- this alternative short code on your webpage - `[cscf-contact-form]`.
172
- This problem often occurs when Jetpack plugin is installed.
173
-
174
- = How do I display the contact form on my page/post? =
175
-
176
- To put the contact form on your page, add the text:
177
- `[cscf-contact-form]`
178
-
179
- The contact form will appear when you view the page.
180
-
181
- = When I use the style sheet that comes with the plugin my theme is affected =
182
-
183
- It is impossible to test this plugin with all themes. Styling incompatibilities can occur. In this case, switch off the default stylesheet on the settings
184
- screen so you can add your own styles to your theme's stylesheet.
185
-
186
- = Can I have this plugin in my own language? =
187
-
188
- Yes, I am currently building up translation files for this plugin. If your language is not yet available you are very welcome to translate it.
189
- If you are not sure how to go about doing this [get in touch](http://www.megnicholas.co.uk/contact-me/ "Contact Me").
190
-
191
- = How do I change the text box sizes? =
192
-
193
- The plugin now uses Bootstrap 3. The text box widths now use up 100% of the available width.
194
- This makes the form responsive to all types of media. If you want to have a fixed width for the form you can put some styling around the shortcode:
195
- `<div style="width:600px;">[cscf-contact-form]</div>`
196
-
197
- = Can I have multiple forms? =
198
-
199
- Currently you may only have one contact form per page. You CAN however put the contact form on more than one page using the same shortcode.
200
- Note that making changes to the settings will affect all implementations of the plugin across your site.
201
-
202
- = Will this work with other plugins that use Google reCAPTCHA? =
203
- Yes it will. HOWEVER, you cannot have more than one reCAPTCHA on a page. This is a constraint created by Google.
204
- So for example, if your 'Contact Me' page has comments below it,
205
- the reCAPTCHA for the contact form will be displayed correctly but not in the comments form below.
206
- The comments form will never validate due to no supplied reCAPTCHA code.
207
-
208
- == Changelog ==
209
- = 4.7.1 =
210
- * Tested with Wordpress version 5.3
211
- Fixed XSS vulnerability in GDPR consent message
212
- = 4.7.0 =
213
- * Tested with Wordpress version 4.9.6
214
- * Added consent to contact checkbox for GDPR compliance
215
- = 4.6.2 =
216
- * Turkish translation update. Thanks to Abdullah Manaz! Tested up to WordPress 4.6.1.
217
- = 4.6.1 =
218
- * Fixed untranslated strings. Thanks to Abdullah Manaz!
219
- = 4.6.0 =
220
- * Prevent multiple 'send message' clicks.
221
- * Changed text domain to plugin slug to allow for WP translation system import
222
- * Removed advertising from settings screen
223
- * Added Korean translation thanks to Lee Dae-yeop
224
- * Added Romanian translation. Thanks to Marius Pruna.
225
- * Update French translation thanks to Steph
226
- * Added Hungarian translation. Thanks to János Sánta.
227
- = 4.5.1 =
228
- * Updated Polish translations thanks to Kacper
229
- * Updated French translation
230
- = 4.5.0 =
231
- * Added support for google recaptcha2. Replaces recaptcha version 1
232
- * Update to Italian translation thanks to Silvano
233
- * Added back the DIV to the contact form view as this introduced a display issue
234
- * Updated German translation thanks to schasoli
235
- * Polish translation update thanks to Kacper Rucinski
236
- = 4.4.4 =
237
- * Added Serbian translation thanks to [Borisa Djuraskovic](http://www.webhostinghub.com "Borisa Djuraskovic")
238
- * Added Slovenian translation thanks to Bekim Lutolli
239
- * Fixed some 'notice' errors
240
- * Recaptcha styling workaround for twenty fifteen theme
241
- * Remove empty divs from view
242
- = 4.4.3 =
243
- * Remove branding
244
- = 4.4.2 =
245
- * Akismet tweak only log as spam if akismet_result = 'true'
246
- * Updated Turkish translations thanks again to [Abdullah Manaz](http://manaz.net "Abdullah Manaz")
247
- * Added Indonesian translations thanks to Beny Hirmansyah
248
- = 4.4.0 =
249
- * Fixed XSS issue
250
- = 4.4.1 =
251
- * Add option for enquiry to email themselves a copy of the message
252
- * Update to Polish translation thanks to Radosław “Robaczek” Rak
253
- = 4.3.4 =
254
- * Added the wordpress page of contact form to the email
255
- * Removed link in main contact form view
256
- = 4.3.3 =
257
- * Before overriding the from address, check that another plugin has not done it first.
258
- Any plugin that overrides 'from email address' and 'from name' such as wp-mail-smtp plugin will take precedence over the settings in this plugin.
259
- * Added 'reply-to' to the email header
260
- * Moved the Name field before Email field
261
- * Added Hebrew translation thanks to Shay Cohen
262
- = 4.3.2 =
263
- * Added Norwegian Bokmål translation thanks to Jann Vestby
264
- * Added Brazilian Portugese translation originally a Portugese translation by Ricardo Santos aka BogasoBogolha
265
- = 4.3.1 =
266
- * Polish translation has been updated thanks to Arkadiusz Baron
267
- * Updated Turkish translations thanks again to [Abdullah Manaz](http://manaz.net "Abdullah Manaz")
268
- * New installations now have default stylesheet, ajax, and confirm-email options turned on
269
- * Compatibility with WordPress 3.8
270
- * Tested with twentyfourteen theme
271
- = 4.3.0 =
272
- * Contact form is now filtered for spam when the Akisturkishturkishturkmet plugin is present.
273
- [Learn more](http://www.megnicholas.co.uk/articles/contact-form-plugin-can-detect-spam/ "Learn More").
274
- = 4.2.5 =
275
- * Fixed bug that caused a PHP notice to be generated when 'Confirm Email Message' option is switched off.
276
- Thanks to MarrsAttax
277
- = 4.2.4 =
278
- * The requirement for users to confirm their email address is now optional.
279
- When turned off users only need to enter their email address once.
280
- * Added Arabic translation thanks to [Omar AlQabandi](http://www.PlusOmar.com "Omar AlQabandi")
281
- = 4.2.3 =
282
- * Added ability to specify multiple recipient email addresses
283
- * Fix settings gui - there was a problem enabling 'From' Address option when javascript is not enabled.
284
- = 4.2.2 =
285
- * Recaptcha library has now been namespaced to 'cscf' to remove ALL possibility of conflicts with other plugins that also include this library.
286
- = 4.2.1 =
287
- * Fixed potential conflict with other themes or plugins that use Google reCAPTCHA. reCAPTCHA library is not loaded if it already loaded by another plugin or theme.
288
- * Recaptcha library function is now used to generate the sign up url on the settings page. The site domain is passed into the url for convenience.
289
- * Options subject, message, heading, and body text are now translated when they are retrieved from the the database. Previously only the default messages were translated when no values were found in the database.
290
- * Improved housekeeping: generic name for settings array has been changed from 'array_key' to 'cscf-options'
291
- = 4.2.0 =
292
- * Updated Turkish translations thanks again to [Abdullah Manaz](http://manaz.net "Abdullah Manaz")
293
- * Fixed a problem where certain texts on the settings screen were not being translated
294
- thanks to [Abdullah Manaz](http://manaz.net "Abdullah Manaz") again for finding this
295
- * Updates to FAQ section
296
- * The settings link on the plugin page may now be translated
297
- * The text 'Contact Form' on the admin screen menu may now be translated
298
- * Added Greek translations thanks to Georgios Diamantopoulos
299
- = 4.1.9 =
300
- * Added support for Bootstrap 3.0.0. Plugin is still compatible with Bootstrap 2.3.2, but if your theme uses this version
301
- please do not use the plugin's default style sheet (uncheck the box in the settings screen)
302
- [more information here](http://www.megnicholas.co.uk/articles/version-4-1-9-supports-bootstrap-3/ "more information").
303
- = 4.1.8 =
304
- * Added Russian Translation thanks to Oleg
305
- * Correct character encoding in Estonian translation thanks to [Marko Punnar](http://aretaja.org "Marko Punnar")
306
- * Correct some Spanish translation errors thanks to rowanda
307
- = 4.1.7 =
308
- * Added a note about the short code to use on the settings screen.
309
- * Added Estonian Translation thanks to [Marko Punnar](http://aretaja.org "Marko Punnar")
310
- * Added Japanese language thanks to Nikhil Khullar
311
- * Updated Turkish translation thanks again to Abdullah Manaz http://manaz.net
312
- = 4.1.6 =
313
- * Added ability to specify a 'from' address. When supplied the email will come from that address instead of the form filler's email address.
314
- * Changed type of email input boxes to "email"
315
- * Added Turkish translation thanks to Abdullah Manaz http://manaz.net
316
- = 4.1.5 =
317
- * Removed all carriage returns from views to avoid problems with wptexturize
318
- * Fixed typo in Dutch translation.
319
- = 4.1.4 =
320
- * Added Slovak translation file - thanks to Peter Gašparík
321
- * Added Catalan translation file - thanks to Llorenç
322
- = 4.1.3 =
323
- * Fixed escaped characters.
324
- * Added more translation files
325
- * Forms now submit via ajax.
326
- * Upgraded jquery-validate.js to 1.11. Removed jquery metadata plugin, form validation is now built with data attributes instead of json in classes.
327
- * Improved view html.
328
- * Added translations: Dutch thanks to Daniel Tetteroo, Armenian thanks to [Artak Kolyan](http://ablog.gratun.am "Artak Kolyan"),
329
- Polish thanks to Patryk Peas
330
- = 4.1.2 =
331
- * Added some FAQs
332
- * Added alternative shortcode [cscf-contact-form] for use when conflicts could occur.
333
- * Updated the documentation.
334
- * Recaptcha form now responds to language changes
335
- * Updated pot file to reflect new name space
336
- * Changed name space from cff to cscf
337
- * Settings screen: recaptcha theme and key inputs are immediately enabled/disabled as the 'Use reCAPTCHA' box is clicked.
338
- * Corrected some html seen as invalid by http://validator.w3.org/
339
- * removed '<?=' and replaced with '<?php echo' in cscf_settings, thanks go to andrewbacon
340
- * Added notice to setting screen when JetPack's contact form is active
341
- * Fixed problem where 'Please enter a valid email address' was not translating in the 'confirm email address' input
342
- = 4.1.1 =
343
- * Fixed potential conflicts with themes that use bootstrap
344
- * Enabled internationalisation, this plugin will now work with multiple languages
345
- * Added German translation file for my German friends, thanks to faktorzweinet for the translation
346
- = 4.1.0 =
347
- * Fixed a bug in class.cff_settings.php where php opening tag had got missed off. This problem caused the settings screen not to display correctly but only occurred with some versions of php. Please upgrade if you have this problem.
348
- = 4.0.9 =
349
- * Switched header argument of wp_mail over to a filter to remove any potential conflicts with other emailing plugins or themes
350
- * The ability to set a different recipient email address. Previously all email was sent to the WordPress administrator email address.
351
- * Allow the email subject to be customised.
352
- = 4.0.8 =
353
- * Fixed a bug: When using reCAPTCHA ajax did not work.
354
- * Fixed a bug: Ajax validation was not checking email address were equal (server side was doing it instead)
355
- * Improvement: Ajax now works better.
356
- * Documentation update: nicer links (worked how to do them in markdown!), changelog and upgrade notice sections now correctly formatted.
357
- = 4.0.7 =
358
- * Fixed a bug: Plugin name is actually clean-and-simple-contact-form-by-meg-nicholas now (not contact-form) but this new name needed to be updated in the plugin settings definitions. I also needed to rename contact-form.php to clean-and-simple-contact-form-by-meg-nicholas.php. My thanks to Jakub for finding this bug.
359
- * If your webpage is ssl then reCAPTCHA will now also use ssl mode.
360
-
361
-
362
- == Upgrade Notice ==
363
- = 4.7.0 =
364
- Tested with Wordpress version 4.9.6. Added 'consent to contact' GDPR compliance message
365
- = 4.6.2 =
366
- Updated translations. Tested up to WordPress 4.6.1.
367
- = 4.6.0 =
368
- Updated translations. Correct textdomain. Prevent multiple clicks.
369
- = 4.5.1 =
370
- Translation updates
371
- = 4.5.0 =
372
- Added support for Google Recaptcha2. Updated translation. Fixed layout bug.
373
- = 4.4.4 =
374
- Added languages, css fix for twenty fifteen theme, remove 'notice' errors, remove empty divs
375
- = 4.4.3 =
376
- Tested up to 4.1
377
- = 4.4.2 =
378
- Akismet tweak and translation updates
379
- = 4.4.1 =
380
- Fixed XSS issue
381
- = 4.4.0 =
382
- Added option for enquiry to email themselves a copy of the message plus Polish translation updated
383
- = 4.3.4 =
384
- Email now includes page url of contact form, removed link in main contact form view
385
- = 4.3.3 =
386
- Hebrew Language added, name field moved to top of form, added 'reply-to'
387
- = 4.3.2 =
388
- Added Norwegian and Brazilian Portugese Translations
389
- = 4.3.1 =
390
- Checked compatibility with WP 3.8 and TwentyFourteen theme, translation updates, defaults for new installations
391
- = 4.3.0 =
392
- Contact form is now filtered for spam when the Akismet plugin is present.
393
- [Learn more](http://www.megnicholas.co.uk/articles/contact-form-plugin-can-detect-spam/ "Learn More").
394
- = 4.2.5 =
395
- Small bug fix
396
- = 4.2.4 =
397
- 'Confirm Email' can now be turned off. Arabic translation added.
398
- = 4.2.3 =
399
- Multiple recipients are now possible
400
- = 4.2.2 =
401
- Remove ALL possibility of conflicts with other plugins that also include Google reCAPTCHA library
402
- = 4.2.1 =
403
- Translation and housekeeping updates
404
- = 4.2.0 =
405
- Translation and documentation updates
406
- = 4.1.9 =
407
- Support for [Bootstrap 3](http://www.megnicholas.co.uk/articles/version-4-1-9-supports-bootstrap-3/ "More information on 4.1.9")
408
- = 4.1.8 =
409
- Added Russian translation and some modifications to Estonian and Spanish translations
410
- = 4.1.7
411
- More translations. A helpful note about the short code to use has been put on the settings screen
412
- = 4.1.6 =
413
- Ability to specify a 'From' address. This email will be used to send the mail instead of the form filler's email address.
414
- = 4.1.5 =
415
- Works with themes that pre-process the html.
416
- = 4.1.4 =
417
- New translations - Slovak and Catalan
418
- = 4.1.3 =
419
- Form now submits via ajax!
420
- = 4.1.2 =
421
- Alternative shortcode, recaptcha internationalisation, Jetpack conflict warning notice
422
- = 4.1.1 =
423
- Internationalisation, fixed conflict with some bootstrapped themes.
424
- = 4.1.0 =
425
- Please upgrade if your settings screen is not displaying.
426
- = 4.0.9 =
427
- More customisation: recipient email address, and email subject.
428
- = 4.0.8 =
429
- Ajax now works when your form has reCAPTCHA on it. Ajax validation is now cleaner.
430
- = 4.0.7 =
431
- Fixed a bug which occurred when plugin name was changed. reCAPTCHA will now use ssl if your webpage is ssl.
1
+ === Contact Form Clean and Simple ===
2
+ Contributors: fullworks
3
+ License: GPLv2 or later
4
+ License URI: http://www.gnu.org/licenses/gpl.html
5
+ Tags: simple, contact, form, contact button, contact form, contact form plugin, akismet, contacts, contacts form plugin, contact me, feedback form, bootstrap, twitter, google, reCAPTCHA, ajax, secure
6
+ Requires at least: 4.6
7
+ Tested up to: 5.7
8
+ Requires PHP: 5.6
9
+ Stable tag: 4.7.2
10
+
11
+ A clean and simple AJAX contact form with Google reCAPTCHA, Twitter Bootstrap markup and Akismet spam filtering.
12
+
13
+
14
+ == Description ==
15
+ A clean and simple AJAX contact form with Google reCAPTCHA, Twitter Bootstrap markup and Akismet spam filtering.
16
+
17
+ * **Clean**: all user inputs are stripped in order to avoid cross-site scripting (XSS) vulnerabilities.
18
+
19
+ * **Simple**: AJAX enabled validation and submission for immediate response and guidance for your users (can be switched off).
20
+
21
+ * **Stylish**: Use the included stylesheet or switch it off and use your own for seamless integration with your website.
22
+ Uses **Twitter Bootstrap** classes.
23
+
24
+ * **Safe**: All incoming data is scanned for spam with **Akismet**.
25
+
26
+ This is a straightforward contact form for your WordPress site. There is very minimal set-up
27
+ required. Simply install, activate, and then place the short code **[cscf-contact-form]** on your web page.
28
+
29
+ A standard set of input boxes are provided, these include Email Address, Name, Message and a nice big ‘Send Message’ button.
30
+
31
+ When your user has completed the form an email will be sent to you containing your user’s message.
32
+ To reply simply click the ‘replybutton on your email client.
33
+ The email address used is the one you have set up in WordPress under ‘Settings’ -> ‘General’, so do check this is correct.
34
+
35
+ To help prevent spam all data is scanned via Akismet.
36
+ For this to work you must have the [Akismet Plugin](http://wordpress.org/plugins/akismet/ "Akismet Plugin") installed and activated.
37
+ All spam will be placed in your 'comments' list which you can then review if you want to,
38
+
39
+ For added piece of mind this plugin also allows you to add a ‘**reCAPTCHA**’.
40
+ This adds a picture of a couple of words to the bottom of the contact form.
41
+ Your user must correctly type the words before the form can be submitted, and in so doing, prove that they are human.
42
+
43
+ = Why Choose This Plugin? =
44
+ Granted there are many plugins of this type in existence already. Why use this one in-particular?
45
+
46
+ Here’s why:
47
+
48
+ * Minimal setup. Simply activate the plugin and place the shortcode [cscf-contact-form] on any post or page.
49
+
50
+ * **Safe**. All input entered by your user is stripped back to minimise as far as possible the likelihood of any
51
+ malicious user attempting to inject a script into your website.
52
+ If the Akismet plugin is activated all form data will be scanned for spam.
53
+ You can turn on reCAPTCHA to avoid your form being abused by bots.
54
+
55
+ * **Ajax enabled**. You have the option to turn on AJAX (client-side) validation and submission which gives your users an immediate response when completing the form without having to wait for the page to refresh.
56
+
57
+ * The form can **integrate seamlessly into your website**. Turn off the plugin’s default css style sheet so that your theme’s style sheet can be used instead.
58
+
59
+ * If your theme is based on **twitter bootstrap** then this plugin will fit right in because it already has all the right div’s and CSS classes for bootstrap.
60
+
61
+ * This plugin will only link in its jQuery file where it’s needed, it **will not impose** itself on every page of your whole site!
62
+
63
+ * Works with the **latest version of WordPress**.
64
+
65
+ * Original plugin written by an **experienced PHP programmer**, Megan Nicholas, the code is rock solid, safe, and rigorously tested as standard practice.
66
+
67
+ Hopefully this plugin will fulfil all your needs.
68
+
69
+
70
+ == Installation ==
71
+ There are two ways to install:
72
+
73
+ 1. Click the ‘Install Now’ link from the plugin library listing to automatically download and install.
74
+
75
+ 2. Download the plugin as a zip file. To install the zip file simply double click to extract it and place the whole folder in your wordpress plugins folder, e.g. [wordpress]/wp-content/plugins where [wordpress] is the directory that you installed WordPress in.
76
+
77
+ Then visit the plugin page on your wordpress site and click ‘Activate’ against the ‘Clean and Simple Contact Form’ plugin listing.
78
+
79
+ To place the contact form on your page use the shortcode [cscf-contact-form]
80
+
81
+ == How to Use ==
82
+ Unless you want to change messages or add reCAPTCHA to your contact form then this plugin will work out of the box without any additional setup.
83
+
84
+ Important: Check that you have an email address set-up in your WordPress ‘Settings’->’General’ page. This is the address that the plugin will use to send the contents of the contact form.
85
+
86
+ To add the contact form to your WordPress website simply place the shortcode [cscf-contact-form] on the post or page that you wish the form to appear on.
87
+
88
+ **If you have Jetpack plugin installed disable the contact form otherwise the wrong form might display.**
89
+
90
+ == Additional Settings ==
91
+ This plugin will work out of the box without any additional setup. You have the option to change the default messages that are displayed to your user and to add reCAPTCHA capabilities.
92
+
93
+ Go to the settings screen for the contact form plugin.
94
+
95
+ You will find a link to the setting screen against the entry of this plugin on the ‘Installed Plugins’ page.
96
+
97
+ Here is a list of things that you can change
98
+
99
+ * **Message**: The message displayed to the user at the top of the contact form.
100
+
101
+ * **Message Sent Heading**: The message heading or title displayed to the user after the message has been sent.
102
+
103
+ * **Message Sent Content**: The message content or body displayed to the user after the message has been sent.
104
+
105
+ * **Use this plugin’s default stylesheet**: The plugin comes with a default style sheet to make the form look nice for your user. Untick this if you want to use your theme’s stylesheet instead. The default stylesheet will simply not be linked in.
106
+
107
+ * **Use client side validation (Ajax)**: When ticked the contact form will be validated and submitted on the client giving your user instant feedback if they have filled the form in incorrectly. If you wish the form to be validated and submitted only to the server then untick this option.
108
+
109
+ * **Use reCAPTCHA**: Tick this option if you wish your form to have a reCAPTCHA box. ReCAPTCHA helps to avoid spam bots using your form by checking that the form filler is actually a real person. To use reCAPTCHA you will need to get a some special keys from google https://www.google.com/recaptcha/admin/create. Once you have your keys enter them into the Public key and Private key boxes
110
+
111
+ * **reCAPTCHA Public Key**: Enter the public key that you obtained from here.
112
+
113
+ * **reCAPTCHA Private Key**: Enter the private key that you obtained from here.
114
+
115
+ * **reCAPTCHA Theme**: Here you can change the reCAPTCHA box theme so that it fits with the style of your website.
116
+
117
+ * **Recipient Emails**: The email address where you would like all messages to be sent.
118
+ This will default to the email address you have specified under 'E-Mail Address' in your WordPress General Settings.
119
+ If you want your mail sent to a different address then enter it here.
120
+ You may enter multiple email addresses by clicking the '+' button.
121
+
122
+ * **Confirm Email Address**: Email confirmation is now optional. To force your user to re-type their email address tick 'Confirm Email Address'.
123
+ It is recommended that you leave this option on. If you turn this option off your user will only have to enter their email address once,
124
+ but if they enter it incorrectly you will have no way of getting back to them!
125
+
126
+ * **Email Subject**: This is the email subject that will appear on all messages. If you would like to set it to something different then enter it here.
127
+
128
+ * **Override 'From' Address**: If you tick this and then fill in the 'From Address:' box then all email will be sent from the given address NOT from the email address given by the form filler.
129
+
130
+ * **Option to allow enquiry to email themselves a copy of the message.
131
+
132
+ * **Contact consent**: This option allows you to be GDPR compliant by adding a 'Consent to contact' check box at the bottom of the form.
133
+
134
+
135
+ == Screenshots ==
136
+ 1. Contact Form With reCAPTCHA
137
+ 2. Contact Form Without reCAPTCHA
138
+ 3. Message Sent
139
+ 4. Contact Form Options Screen
140
+ 5. Place this shortcode on your post or page to deploy
141
+
142
+ == Demo ==
143
+ Demo site coming soon.
144
+
145
+ == Frequently Asked Questions ==
146
+ = I get a message to say that the message could not be sent =
147
+
148
+ If you get this message then you have a general problem with email on your server. This plugin uses Wordpress's send mail function.
149
+ So a problem sending mail from this plugin indicates that Wordpress as a whole cannot send email.
150
+ Contact your web host provider for help, or use an SMTP plugin to use a third party email service.
151
+
152
+ = I don't receive the email =
153
+
154
+ * Check the recipient email on your settings screen, is it correct?
155
+ * Check in your spam or junk mail folder
156
+ * For Gmail check in 'All Mail', the email might have gone straight to archive
157
+ * Try overriding the 'From' email address in the settings screen. Use an email address you own or is from your own domain
158
+
159
+ = Why is a different contact form displayed? =
160
+
161
+ You may have a conflict with another plugin. Either deactivate the other contact form plugin, if you don't need it, or use
162
+ this alternative short code on your webpage - `[cscf-contact-form]`.
163
+ This problem often occurs when Jetpack plugin is installed.
164
+
165
+ = How do I display the contact form on my page/post? =
166
+
167
+ To put the contact form on your page, add the text:
168
+ `[cscf-contact-form]`
169
+
170
+ The contact form will appear when you view the page.
171
+
172
+ = When I use the style sheet that comes with the plugin my theme is affected =
173
+
174
+ It is impossible to test this plugin with all themes. Styling incompatibilities can occur. In this case, switch off the default stylesheet on the settings
175
+ screen so you can add your own styles to your theme's stylesheet.
176
+
177
+ = Can I have this plugin in my own language? =
178
+
179
+ Yes, I am currently building up translation files for this plugin.
180
+ If your language is not yet available you are very welcome to translate it.
181
+
182
+ = How do I change the text box sizes? =
183
+
184
+ The plugin now uses Bootstrap 3. The text box widths now use up 100% of the available width.
185
+ This makes the form responsive to all types of media. If you want to have a fixed width for the form you can put some styling around the shortcode:
186
+ `<div style="width:600px;">[cscf-contact-form]</div>`
187
+
188
+ = Can I have multiple forms? =
189
+
190
+ Currently you may only have one contact form per page. You CAN however put the contact form on more than one page using the same shortcode.
191
+ Note that making changes to the settings will affect all implementations of the plugin across your site.
192
+
193
+ = Will this work with other plugins that use Google reCAPTCHA? =
194
+ Yes it will. HOWEVER, you cannot have more than one reCAPTCHA on a page. This is a constraint created by Google.
195
+ So for example, if your 'Contact Me' page has comments below it,
196
+ the reCAPTCHA for the contact form will be displayed correctly but not in the comments form below.
197
+ The comments form will never validate due to no supplied reCAPTCHA code.
198
+
199
+ == Changelog ==
200
+ = 4.7.2 =
201
+ * Updated santization and escaping to current plugin directory recommendations
202
+ * add email header to specify text to improve formatting
203
+ * tested up to 5.8 beta 2 and PHP 8.0
204
+
205
+ = 4.7.1 =
206
+ * Tested with Wordpress version 5.3
207
+ Fixed XSS vulnerability in GDPR consent message
208
+ = 4.7.0 =
209
+ * Tested with Wordpress version 4.9.6
210
+ * Added consent to contact checkbox for GDPR compliance
211
+ = 4.6.2 =
212
+ * Turkish translation update. Thanks to Abdullah Manaz! Tested up to WordPress 4.6.1.
213
+ = 4.6.1 =
214
+ * Fixed untranslated strings. Thanks to Abdullah Manaz!
215
+ = 4.6.0 =
216
+ * Prevent multiple 'send message' clicks.
217
+ * Changed text domain to plugin slug to allow for WP translation system import
218
+ * Removed advertising from settings screen
219
+ * Added Korean translation thanks to Lee Dae-yeop
220
+ * Added Romanian translation. Thanks to Marius Pruna.
221
+ * Update French translation thanks to Steph
222
+ * Added Hungarian translation. Thanks to János Sánta.
223
+ = 4.5.1 =
224
+ * Updated Polish translations thanks to Kacper
225
+ * Updated French translation
226
+ = 4.5.0 =
227
+ * Added support for google recaptcha2. Replaces recaptcha version 1
228
+ * Update to Italian translation thanks to Silvano
229
+ * Added back the DIV to the contact form view as this introduced a display issue
230
+ * Updated German translation thanks to schasoli
231
+ * Polish translation update thanks to Kacper Rucinski
232
+ = 4.4.4 =
233
+ * Added Serbian translation thanks to [Borisa Djuraskovic](http://www.webhostinghub.com "Borisa Djuraskovic")
234
+ * Added Slovenian translation thanks to Bekim Lutolli
235
+ * Fixed some 'notice' errors
236
+ * Recaptcha styling workaround for twenty fifteen theme
237
+ * Remove empty divs from view
238
+ = 4.4.3 =
239
+ * Remove branding
240
+ = 4.4.2 =
241
+ * Akismet tweak only log as spam if akismet_result = 'true'
242
+ * Updated Turkish translations thanks again to [Abdullah Manaz](http://manaz.net "Abdullah Manaz")
243
+ * Added Indonesian translations thanks to Beny Hirmansyah
244
+ = 4.4.0 =
245
+ * Fixed XSS issue
246
+ = 4.4.1 =
247
+ * Add option for enquiry to email themselves a copy of the message
248
+ * Update to Polish translation thanks to Radosław “Robaczek” Rak
249
+ = 4.3.4 =
250
+ * Added the wordpress page of contact form to the email
251
+ * Removed link in main contact form view
252
+ = 4.3.3 =
253
+ * Before overriding the from address, check that another plugin has not done it first.
254
+ Any plugin that overrides 'from email address' and 'from name' such as wp-mail-smtp plugin will take precedence over the settings in this plugin.
255
+ * Added 'reply-to' to the email header
256
+ * Moved the Name field before Email field
257
+ * Added Hebrew translation thanks to Shay Cohen
258
+ = 4.3.2 =
259
+ * Added Norwegian Bokmål translation thanks to Jann Vestby
260
+ * Added Brazilian Portugese translation originally a Portugese translation by Ricardo Santos aka BogasoBogolha
261
+ = 4.3.1 =
262
+ * Polish translation has been updated thanks to Arkadiusz Baron
263
+ * Updated Turkish translations thanks again to [Abdullah Manaz](http://manaz.net "Abdullah Manaz")
264
+ * New installations now have default stylesheet, ajax, and confirm-email options turned on
265
+ * Compatibility with WordPress 3.8
266
+ * Tested with twentyfourteen theme
267
+ = 4.3.0 =
268
+ * Contact form is now filtered for spam when the Akisturkishturkishturkmet plugin is present.
269
+ [Learn more](http://www.megnicholas.co.uk/articles/contact-form-plugin-can-detect-spam/ "Learn More").
270
+ = 4.2.5 =
271
+ * Fixed bug that caused a PHP notice to be generated when 'Confirm Email Message' option is switched off.
272
+ Thanks to MarrsAttax
273
+ = 4.2.4 =
274
+ * The requirement for users to confirm their email address is now optional.
275
+ When turned off users only need to enter their email address once.
276
+ * Added Arabic translation thanks to [Omar AlQabandi](http://www.PlusOmar.com "Omar AlQabandi")
277
+ = 4.2.3 =
278
+ * Added ability to specify multiple recipient email addresses
279
+ * Fix settings gui - there was a problem enabling 'From' Address option when javascript is not enabled.
280
+ = 4.2.2 =
281
+ * Recaptcha library has now been namespaced to 'cscf' to remove ALL possibility of conflicts with other plugins that also include this library.
282
+ = 4.2.1 =
283
+ * Fixed potential conflict with other themes or plugins that use Google reCAPTCHA. reCAPTCHA library is not loaded if it already loaded by another plugin or theme.
284
+ * Recaptcha library function is now used to generate the sign up url on the settings page. The site domain is passed into the url for convenience.
285
+ * Options subject, message, heading, and body text are now translated when they are retrieved from the the database. Previously only the default messages were translated when no values were found in the database.
286
+ * Improved housekeeping: generic name for settings array has been changed from 'array_key' to 'cscf-options'
287
+ = 4.2.0 =
288
+ * Updated Turkish translations thanks again to [Abdullah Manaz](http://manaz.net "Abdullah Manaz")
289
+ * Fixed a problem where certain texts on the settings screen were not being translated
290
+ thanks to [Abdullah Manaz](http://manaz.net "Abdullah Manaz") again for finding this
291
+ * Updates to FAQ section
292
+ * The settings link on the plugin page may now be translated
293
+ * The text 'Contact Form' on the admin screen menu may now be translated
294
+ * Added Greek translations thanks to Georgios Diamantopoulos
295
+ = 4.1.9 =
296
+ * Added support for Bootstrap 3.0.0. Plugin is still compatible with Bootstrap 2.3.2, but if your theme uses this version
297
+ please do not use the plugin's default style sheet (uncheck the box in the settings screen)
298
+ [more information here](http://www.megnicholas.co.uk/articles/version-4-1-9-supports-bootstrap-3/ "more information").
299
+ = 4.1.8 =
300
+ * Added Russian Translation thanks to Oleg
301
+ * Correct character encoding in Estonian translation thanks to [Marko Punnar](http://aretaja.org "Marko Punnar")
302
+ * Correct some Spanish translation errors thanks to rowanda
303
+ = 4.1.7 =
304
+ * Added a note about the short code to use on the settings screen.
305
+ * Added Estonian Translation thanks to [Marko Punnar](http://aretaja.org "Marko Punnar")
306
+ * Added Japanese language thanks to Nikhil Khullar
307
+ * Updated Turkish translation thanks again to Abdullah Manaz http://manaz.net
308
+ = 4.1.6 =
309
+ * Added ability to specify a 'from' address. When supplied the email will come from that address instead of the form filler's email address.
310
+ * Changed type of email input boxes to "email"
311
+ * Added Turkish translation thanks to Abdullah Manaz http://manaz.net
312
+ = 4.1.5 =
313
+ * Removed all carriage returns from views to avoid problems with wptexturize
314
+ * Fixed typo in Dutch translation.
315
+ = 4.1.4 =
316
+ * Added Slovak translation file - thanks to Peter Gašparík
317
+ * Added Catalan translation file - thanks to Llorenç
318
+ = 4.1.3 =
319
+ * Fixed escaped characters.
320
+ * Added more translation files
321
+ * Forms now submit via ajax.
322
+ * Upgraded jquery-validate.js to 1.11. Removed jquery metadata plugin, form validation is now built with data attributes instead of json in classes.
323
+ * Improved view html.
324
+ * Added translations: Dutch thanks to Daniel Tetteroo, Armenian thanks to [Artak Kolyan](http://ablog.gratun.am "Artak Kolyan"),
325
+ Polish thanks to Patryk Peas
326
+ = 4.1.2 =
327
+ * Added some FAQs
328
+ * Added alternative shortcode [cscf-contact-form] for use when conflicts could occur.
329
+ * Updated the documentation.
330
+ * Recaptcha form now responds to language changes
331
+ * Updated pot file to reflect new name space
332
+ * Changed name space from cff to cscf
333
+ * Settings screen: recaptcha theme and key inputs are immediately enabled/disabled as the 'Use reCAPTCHA' box is clicked.
334
+ * Corrected some html seen as invalid by http://validator.w3.org/
335
+ * removed '<?=' and replaced with '<?php echo' in cscf_settings, thanks go to andrewbacon
336
+ * Added notice to setting screen when JetPack's contact form is active
337
+ * Fixed problem where 'Please enter a valid email address' was not translating in the 'confirm email address' input
338
+ = 4.1.1 =
339
+ * Fixed potential conflicts with themes that use bootstrap
340
+ * Enabled internationalisation, this plugin will now work with multiple languages
341
+ * Added German translation file for my German friends, thanks to faktorzweinet for the translation
342
+ = 4.1.0 =
343
+ * Fixed a bug in class.cff_settings.php where php opening tag had got missed off. This problem caused the settings screen not to display correctly but only occurred with some versions of php. Please upgrade if you have this problem.
344
+ = 4.0.9 =
345
+ * Switched header argument of wp_mail over to a filter to remove any potential conflicts with other emailing plugins or themes
346
+ * The ability to set a different recipient email address. Previously all email was sent to the WordPress administrator email address.
347
+ * Allow the email subject to be customised.
348
+ = 4.0.8 =
349
+ * Fixed a bug: When using reCAPTCHA ajax did not work.
350
+ * Fixed a bug: Ajax validation was not checking email address were equal (server side was doing it instead)
351
+ * Improvement: Ajax now works better.
352
+ * Documentation update: nicer links (worked how to do them in markdown!), changelog and upgrade notice sections now correctly formatted.
353
+ = 4.0.7 =
354
+ * Fixed a bug: Plugin name is actually clean-and-simple-contact-form now (not contact-form) but this new name needed to be updated in the plugin settings definitions. I also needed to rename contact-form.php to clean-and-simple-contact-form.php. My thanks to Jakub for finding this bug.
355
+ * If your webpage is ssl then reCAPTCHA will now also use ssl mode.
356
+
357
+
358
+ == Upgrade Notice ==
359
+ = 4.7.0 =
360
+ Tested with Wordpress version 4.9.6. Added 'consent to contact' GDPR compliance message
361
+ = 4.6.2 =
362
+ Updated translations. Tested up to WordPress 4.6.1.
363
+ = 4.6.0 =
364
+ Updated translations. Correct textdomain. Prevent multiple clicks.
365
+ = 4.5.1 =
366
+ Translation updates
367
+ = 4.5.0 =
368
+ Added support for Google Recaptcha2. Updated translation. Fixed layout bug.
369
+ = 4.4.4 =
370
+ Added languages, css fix for twenty fifteen theme, remove 'notice' errors, remove empty divs
371
+ = 4.4.3 =
372
+ Tested up to 4.1
373
+ = 4.4.2 =
374
+ Akismet tweak and translation updates
375
+ = 4.4.1 =
376
+ Fixed XSS issue
377
+ = 4.4.0 =
378
+ Added option for enquiry to email themselves a copy of the message plus Polish translation updated
379
+ = 4.3.4 =
380
+ Email now includes page url of contact form, removed link in main contact form view
381
+ = 4.3.3 =
382
+ Hebrew Language added, name field moved to top of form, added 'reply-to'
383
+ = 4.3.2 =
384
+ Added Norwegian and Brazilian Portugese Translations
385
+ = 4.3.1 =
386
+ Checked compatibility with WP 3.8 and TwentyFourteen theme, translation updates, defaults for new installations
387
+ = 4.3.0 =
388
+ Contact form is now filtered for spam when the Akismet plugin is present.
389
+ [Learn more](http://www.megnicholas.co.uk/articles/contact-form-plugin-can-detect-spam/ "Learn More").
390
+ = 4.2.5 =
391
+ Small bug fix
392
+ = 4.2.4 =
393
+ 'Confirm Email' can now be turned off. Arabic translation added.
394
+ = 4.2.3 =
395
+ Multiple recipients are now possible
396
+ = 4.2.2 =
397
+ Remove ALL possibility of conflicts with other plugins that also include Google reCAPTCHA library
398
+ = 4.2.1 =
399
+ Translation and housekeeping updates
400
+ = 4.2.0 =
401
+ Translation and documentation updates
402
+ = 4.1.9 =
403
+ Support for [Bootstrap 3](http://www.megnicholas.co.uk/articles/version-4-1-9-supports-bootstrap-3/ "More information on 4.1.9")
404
+ = 4.1.8 =
405
+ Added Russian translation and some modifications to Estonian and Spanish translations
406
+ = 4.1.7
407
+ More translations. A helpful note about the short code to use has been put on the settings screen
408
+ = 4.1.6 =
409
+ Ability to specify a 'From' address. This email will be used to send the mail instead of the form filler's email address.
410
+ = 4.1.5 =
411
+ Works with themes that pre-process the html.
412
+ = 4.1.4 =
413
+ New translations - Slovak and Catalan
414
+ = 4.1.3 =
415
+ Form now submits via ajax!
416
+ = 4.1.2 =
417
+ Alternative shortcode, recaptcha internationalisation, Jetpack conflict warning notice
418
+ = 4.1.1 =
419
+ Internationalisation, fixed conflict with some bootstrapped themes.
420
+ = 4.1.0 =
421
+ Please upgrade if your settings screen is not displaying.
422
+ = 4.0.9 =
423
+ More customisation: recipient email address, and email subject.
424
+ = 4.0.8 =
425
+ Ajax now works when your form has reCAPTCHA on it. Ajax validation is now cleaner.
426
+ = 4.0.7 =
427
+ Fixed a bug which occurred when plugin name was changed. reCAPTCHA will now use ssl if your webpage is ssl.
 
 
 
 
shortcodes/contact-form.php CHANGED
@@ -1,60 +1,55 @@
1
  <?php
2
- add_shortcode('contact-form', 'cscf_ContactForm');
3
- add_shortcode('cscf-contact-form', 'cscf_ContactForm');
4
-
5
- function cscf_ContactForm()
6
- {
7
-
8
- $contact = new cscf_Contact;
9
-
10
- if ($contact->IsValid())
11
- {
12
- if ( $contact->SendMail() )
13
-
14
- {
15
- $view = new CSCF_View('message-sent');
16
- $view->Set('heading',cscf_PluginSettings::SentMessageHeading());
17
- $view->Set('message',cscf_PluginSettings::SentMessageBody());
18
- }
19
- else
20
- {
21
- $view = new CSCF_View('message-not-sent');
22
- }
23
-
24
- return $view->Render();
25
- }
26
 
27
  //load google recaptcha script if required
28
  if ( $contact->RecaptchaPublicKey <> '' && $contact->RecaptchaPrivateKey <> '' ) {
29
- wp_enqueue_script('csf-recaptcha2');
 
 
 
 
 
 
30
  }
31
-
32
- //here we need some jquery scripts and styles, so load them here
33
- if ( cscf_PluginSettings::UseClientValidation() == true) {
34
- wp_enqueue_script('jquery-validate');
35
- wp_enqueue_script('cscf-validate');
36
- }
37
-
38
- //only load the stylesheet if required
39
- if ( cscf_PluginSettings::LoadStyleSheet() == true)
40
- wp_enqueue_style('cscf-bootstrap');
41
-
42
- $messageSentView = new CSCF_View('message-sent');
43
- $messageSentView->Set('heading',cscf_PluginSettings::SentMessageHeading());
44
- $messageSentView->Set('message',cscf_PluginSettings::SentMessageBody());
45
-
46
- $view = new CSCF_View('contact-form');
47
- $view->Set('contact',$contact);
48
- $view->Set('message',cscf_PluginSettings::Message());
49
- $view->Set('version', CSCF_VERSION_NUM);
50
- $view->Set('confirmEmail', cscf_PluginSettings::ConfirmEmail());
51
- $view->Set('postID', get_the_ID());
52
-
53
-
54
- $view->Set('messageSentView',$messageSentView);
55
- $view->Set('messageNotSentView',new CSCF_View('message-not-sent'));
56
-
57
- return $view->Render();
58
 
59
  }
60
 
1
  <?php
2
+ add_shortcode( 'contact-form', 'cscf_ContactForm' );
3
+ add_shortcode( 'cscf-contact-form', 'cscf_ContactForm' );
4
+
5
+ function cscf_ContactForm() {
6
+
7
+ $contact = new cscf_Contact;
8
+
9
+ if ( $contact->IsValid() ) {
10
+ if ( $contact->SendMail() ) {
11
+ $view = new CSCF_View( 'message-sent' );
12
+ $view->Set( 'heading', cscf_PluginSettings::SentMessageHeading() );
13
+ $view->Set( 'message', cscf_PluginSettings::SentMessageBody() );
14
+ } else {
15
+ $view = new CSCF_View( 'message-not-sent' );
16
+ }
17
+
18
+ return $view->Render();
19
+ }
 
 
 
 
 
 
20
 
21
  //load google recaptcha script if required
22
  if ( $contact->RecaptchaPublicKey <> '' && $contact->RecaptchaPrivateKey <> '' ) {
23
+ wp_enqueue_script( 'csf-recaptcha2' );
24
+ }
25
+
26
+ //here we need some jquery scripts and styles, so load them here
27
+ if ( cscf_PluginSettings::UseClientValidation() == true ) {
28
+ wp_enqueue_script( 'jquery-validate' );
29
+ wp_enqueue_script( 'cscf-validate' );
30
  }
31
+
32
+ //only load the stylesheet if required
33
+ if ( cscf_PluginSettings::LoadStyleSheet() == true ) {
34
+ wp_enqueue_style( 'cscf-bootstrap' );
35
+ }
36
+
37
+ $messageSentView = new CSCF_View( 'message-sent' );
38
+ $messageSentView->Set( 'heading', cscf_PluginSettings::SentMessageHeading() );
39
+ $messageSentView->Set( 'message', cscf_PluginSettings::SentMessageBody() );
40
+
41
+ $view = new CSCF_View( 'contact-form' );
42
+ $view->Set( 'contact', $contact );
43
+ $view->Set( 'message', cscf_PluginSettings::Message() );
44
+ $view->Set( 'version', CSCF_VERSION_NUM );
45
+ $view->Set( 'confirmEmail', cscf_PluginSettings::ConfirmEmail() );
46
+ $view->Set( 'postID', get_the_ID() );
47
+
48
+
49
+ $view->Set( 'messageSentView', $messageSentView );
50
+ $view->Set( 'messageNotSentView', new CSCF_View( 'message-not-sent' ) );
51
+
52
+ return $view->Render();
 
 
 
 
 
53
 
54
  }
55
 
views/contact-form.view.php CHANGED
@@ -1,215 +1,216 @@
1
  <div id="cscf" class="cscfBlock">
2
- <div class="cscfMessageSent" style="display:none;">
3
- <?php echo $messageSentView->Render(); ?>
4
- </div>
5
- <div class="cscfMessageNotSent" style="display:none;">
6
- <?php echo $messageNotSentView->Render(); ?>
7
- </div>
8
- <div class="cscfForm">
9
- <p><?php echo $message; ?></p>
10
-
11
- <form role="form" id="frmCSCF" name="frmCSCF" method="post">
12
  <?php wp_nonce_field( 'cscf_contact', 'cscf_nonce' ); ?>
13
- <input type="hidden" name="post-id" value="<?php echo $postID; ?>">
14
 
15
  <?php if ( isset( $contact->Errors['recaptcha'] ) ) { ?>
16
- <div class="control-group form-group">
17
- <p class="text-error"><?php echo $contact->Errors['recaptcha']; ?></p>
18
- </div>
19
  <?php } ?>
20
 
21
- <!-- name -->
22
- <div class="control-group form-group<?php if ( isset( $contact->Errors['name'] ) ) {
23
  echo ' error has-error';
24
  } ?>">
25
- <label for="cscf_name"><?php _e( 'Name:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
26
 
27
 
28
- <div class="<?php echo cscf_PluginSettings::InputIcons() ? "input-group" : ""; ?>">
29
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
30
- <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
31
  <?php } ?>
32
- <input class="form-control input-xlarge"
33
- data-rule-required="true"
34
- data-msg-required="<?php _e( 'Please give your name.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
35
- type="text" id="cscf_name" name="cscf[name]"
36
- value="<?php echo esc_attr( $contact->Name ); ?>"
37
- placeholder="<?php _e( 'Your Name', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
38
- />
39
- </div>
40
  <span for="cscf_name" class="help-inline help-block error"
41
  style="display:<?php echo isset( $contact->Errors['name'] ) ? 'block' : 'none'; ?>;">
42
 
43
  <?php if ( isset( $contact->Errors['name'] ) ) {
44
- echo $contact->Errors['name'];
45
  } ?>
46
  </span>
47
- </div>
48
 
49
 
50
- <!--email address-->
51
- <div class="control-group form-group<?php if ( isset( $contact->Errors['email'] ) ) {
52
  echo ' error has-error';
53
  } ?>">
54
- <label for="cscf_email"><?php _e( 'Email Address:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
55
 
56
- <div class="<?php echo cscf_PluginSettings::InputIcons() ? "input-group" : ""; ?>">
57
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
58
- <span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span></span>
59
  <?php } ?>
60
- <input class="form-control input-xlarge"
61
- data-rule-required="true"
62
- data-rule-email="true"
63
- data-msg-required="<?php _e( 'Please give your email address.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
64
- data-msg-email="<?php _e( 'Please enter a valid email address.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
65
- type="email" id="cscf_email" name="cscf[email]"
66
- value="<?php echo esc_attr( $contact->Email ); ?>"
67
- placeholder="<?php _e( 'Your Email Address', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
68
- />
69
- </div>
70
  <span for="cscf_email" class="help-inline help-block error"
71
  style="display:<?php echo isset( $contact->Errors['email'] ) ? 'block' : 'none'; ?>;">
72
  <?php if ( isset( $contact->Errors['email'] ) ) {
73
- echo $contact->Errors['email'];
74
  } ?>
75
  </span>
76
- </div>
77
 
78
  <?php if ( $confirmEmail ) { ?>
79
- <!--confirm email address -->
80
- <div class="control-group form-group<?php if ( isset( $contact->Errors['confirm-email'] ) ) {
81
  echo ' error has-error';
82
  } ?>">
83
- <label for="cscf_confirm-email"><?php _e( 'Confirm Email Address:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
84
- <div class="<?php echo cscf_PluginSettings::InputIcons() ? "input-group" : ""; ?>">
85
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
86
- <span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span></span>
87
  <?php } ?>
88
- <input class="form-control input-xlarge"
89
- data-rule-required="true"
90
- data-rule-email="true"
91
- data-rule-equalTo="#cscf_email"
92
- data-msg-required="<?php _e( 'Please enter the same email address again.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
93
- data-msg-email="<?php _e( 'Please enter a valid email address.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
94
- data-msg-equalTo="<?php _e( 'Please enter the same email address again.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
95
- type="email" id="cscf_confirm-email" name="cscf[confirm-email]"
96
- value="<?php echo esc_attr( $contact->ConfirmEmail ); ?>"
97
- placeholder="<?php _e( 'Confirm Your Email Address', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
98
- />
99
- </div>
100
- <span for="cscf_confirm-email" class="help-inline help-block error"
101
- style="display:<?php echo isset( $contact->Errors['confirm-email'] ) ? 'block' : 'none'; ?>;">
102
  <?php if ( isset( $contact->Errors['confirm-email'] ) ) {
103
- echo $contact->Errors['confirm-email'];
104
  } ?>
105
  </span>
106
- </div>
107
  <?php } ?>
108
 
109
 
110
- <!-- message -->
111
- <div class="control-group form-group<?php if ( isset( $contact->Errors['message'] ) ) {
112
  echo ' error has-error';
113
  } ?>">
114
- <label for="cscf_message"><?php _e( 'Message:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
115
- <div class="<?php echo cscf_PluginSettings::InputIcons() ? "input-group" : ""; ?>">
116
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
117
- <span class="input-group-addon"><span class="glyphicon glyphicon-comment"></span></span>
118
  <?php } ?>
119
- <textarea class="form-control input-xlarge"
120
- data-rule-required="true"
121
- data-msg-required="<?php _e( 'Please give a message.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
122
- id="cscf_message" name="cscf[message]" rows="10"
123
- placeholder="<?php _e( 'Your Message', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"><?php echo esc_textarea( $contact->Message ); ?></textarea>
124
- </div>
125
-
126
- <span for="cscf_message" class="help-inline help-block error"
127
- style="display:<?php echo isset( $contact->Errors['message'] ) ? 'block' : 'none'; ?>;">
128
  <?php if ( isset( $contact->Errors['message'] ) ) {
129
- echo $contact->Errors['message'];
130
  } ?>
131
  </span>
132
- </div>
133
 
134
  <?php if ( cscf_PluginSettings::EmailToSender() ) { ?>
135
- <!-- email to sender -->
136
- <div class="control-group form-group<?php if ( isset( $contact->Errors['email-sender'] ) ) {
137
  echo ' error has-error';
138
  } ?>">
139
- <label for="cscf_email-sender"><?php _e( 'Send me a copy:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
140
- <div class="<?php echo cscf_PluginSettings::InputIcons() ? "input-group" : ""; ?>">
141
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
142
- <span class="input-group-addon"><span class="glyphicon glyphicon-comment"></span></span>
143
  <?php } ?>
144
- <input <?php echo $contact->EmailToSender == true ? 'checked' : ''; ?> type="checkbox"
145
- id="cscf_email-sender"
146
- name="cscf[email-sender]">
147
- </div>
148
- <span for="cscf_email-sender" class="help-inline help-block error"
149
- style="display:<?php echo isset( $contact->Errors['email-sender'] ) ? 'block' : 'none'; ?>;">
150
  <?php if ( isset( $contact->Errors['email-sender'] ) ) {
151
- echo $contact->Errors['email-sender'];
152
  } ?>
153
  </span>
154
- </div>
155
  <?php } ?>
156
 
157
 
158
 
159
  <?php if ( cscf_PluginSettings::ContactConsent() ) { ?>
160
- <!-- contact consent -->
161
- <div class="control-group form-group<?php if ( isset( $contact->Errors['contact-consent'] ) ) {
162
  echo ' error has-error';
163
  } ?>">
164
- <label for="cscf_contact-consent"><?php echo cscf_PluginSettings::ContactConsentMsg(); ?>:</label>
165
- <div class="<?php echo cscf_PluginSettings::InputIcons() ? "input-group" : ""; ?>">
 
166
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
167
- <span class="input-group-addon"><span class="glyphicon glyphicon-comment"></span></span>
168
  <?php } ?>
169
- <input data-rule-required="true"
170
- data-msg-required="<?php _e( 'Please give your consent.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
171
- <?php echo $contact->ContactConsent == true ? 'checked' : ''; ?> type="checkbox"
172
- id="cscf_contact-consent"
173
- name="cscf[contact-consent]">
174
- </div>
175
- <span for="cscf[contact-consent]" class="help-inline help-block error"
176
- style="display:<?php echo isset( $contact->Errors['contact-consent'] ) ? 'block' : 'none'; ?>;">
177
  <?php if ( isset( $contact->Errors['contact-consent'] ) ) {
178
- echo $contact->Errors['contact-consent'];
179
  } ?>
180
  </span>
181
- </div>
182
  <?php } ?>
183
 
184
- <!-- recaptcha -->
185
  <?php if ( $contact->RecaptchaPublicKey <> '' && $contact->RecaptchaPrivateKey <> '' ) { ?>
186
 
187
- <div class="control-group form-group<?php
188
  if ( isset( $contact->Errors['recaptcha'] ) ) {
189
  echo ' error has-error';
190
  } ?>">
191
- <div id="recaptcha_div">
192
- <div class="g-recaptcha" data-theme="<?php echo cscf_PluginSettings::Theme(); ?>"
193
- data-sitekey="<?php echo $contact->RecaptchaPublicKey; ?>"></div>
194
 
195
 
196
- <div for="cscf_recaptcha"
197
- class="help-block has-error error"><?php if ( isset( $contact->Errors['recaptcha'] ) ) {
198
- echo $contact->Errors['recaptcha'];
199
  } ?></div>
200
 
201
 
202
- <noscript>
203
- <div style="width: 302px; height: 422px;">
204
- <div style="width: 302px; height: 422px; position: relative;">
205
- <div style="width: 302px; height: 422px; position: absolute;">
206
- <iframe
207
- src="https://www.google.com/recaptcha/api/fallback?k=<?php echo $contact->RecaptchaPublicKey; ?>"
208
- frameborder="0" scrolling="no"
209
- style="width: 302px; height:422px; border-style: none;">
210
- </iframe>
211
- </div>
212
- <div style="width: 300px; height: 60px; border-style: none;
213
  bottom: 12px; left: 25px; margin: 0px; padding: 0px; right: 25px;
214
  background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;">
215
  <textarea id="g-recaptcha-response" name="g-recaptcha-response"
@@ -217,15 +218,16 @@
217
  style="width: 250px; height: 40px; border: 1px solid #c1c1c1;
218
  margin: 10px 25px; padding: 0px; resize: none;">
219
  </textarea>
220
- </div>
221
- </div>
222
- </div>
223
- </noscript>
224
 
225
- </div>
226
- </div>
227
  <?php } ?>
228
- <input type="submit" id="cscf_SubmitButton" class="btn btn-default" value="<?php _e( 'Send Message', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"/>
229
- </form>
230
- </div>
231
- </div>
 
1
  <div id="cscf" class="cscfBlock">
2
+ <div class="cscfMessageSent" style="display:none;">
3
+ <?php echo wp_kses_post( $messageSentView->Render() ); ?>
4
+ </div>
5
+ <div class="cscfMessageNotSent" style="display:none;">
6
+ <?php echo wp_kses_post( $messageNotSentView->Render() ); ?>
7
+ </div>
8
+ <div class="cscfForm">
9
+ <p><?php echo wp_kses_post( $message ); ?></p>
10
+
11
+ <form role="form" id="frmCSCF" name="frmCSCF" method="post">
12
  <?php wp_nonce_field( 'cscf_contact', 'cscf_nonce' ); ?>
13
+ <input type="hidden" name="post-id" value="<?php echo esc_attr( $postID ); ?>">
14
 
15
  <?php if ( isset( $contact->Errors['recaptcha'] ) ) { ?>
16
+ <div class="control-group form-group">
17
+ <p class="text-error"><?php echo esc_html( $contact->Errors['recaptcha'] ); ?></p>
18
+ </div>
19
  <?php } ?>
20
 
21
+ <!-- name -->
22
+ <div class="control-group form-group<?php if ( isset( $contact->Errors['name'] ) ) {
23
  echo ' error has-error';
24
  } ?>">
25
+ <label for="cscf_name"><?php esc_html_e( 'Name:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
26
 
27
 
28
+ <div class="<?php echo ( true === cscf_PluginSettings::InputIcons() ) ? 'input-group' : ''; ?>">
29
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
30
+ <span class="input-group-addon"><span class="glyphicon glyphicon-user"></span></span>
31
  <?php } ?>
32
+ <input class="form-control input-xlarge"
33
+ data-rule-required="true"
34
+ data-msg-required="<?php esc_html_e( 'Please give your name.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
35
+ type="text" id="cscf_name" name="cscf[name]"
36
+ value="<?php echo esc_attr( $contact->Name ); ?>"
37
+ placeholder="<?php esc_html_e( 'Your Name', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
38
+ />
39
+ </div>
40
  <span for="cscf_name" class="help-inline help-block error"
41
  style="display:<?php echo isset( $contact->Errors['name'] ) ? 'block' : 'none'; ?>;">
42
 
43
  <?php if ( isset( $contact->Errors['name'] ) ) {
44
+ echo esc_html( $contact->Errors['name'] );
45
  } ?>
46
  </span>
47
+ </div>
48
 
49
 
50
+ <!--email address-->
51
+ <div class="control-group form-group<?php if ( isset( $contact->Errors['email'] ) ) {
52
  echo ' error has-error';
53
  } ?>">
54
+ <label for="cscf_email"><?php esc_html_e( 'Email Address:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
55
 
56
+ <div class="<?php echo ( true === cscf_PluginSettings::InputIcons() ) ? 'input-group' : ''; ?>">
57
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
58
+ <span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span></span>
59
  <?php } ?>
60
+ <input class="form-control input-xlarge"
61
+ data-rule-required="true"
62
+ data-rule-email="true"
63
+ data-msg-required="<?php esc_html_e( 'Please give your email address.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
64
+ data-msg-email="<?php esc_html_e( 'Please enter a valid email address.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
65
+ type="email" id="cscf_email" name="cscf[email]"
66
+ value="<?php echo esc_attr( $contact->Email ); ?>"
67
+ placeholder="<?php esc_html_e( 'Your Email Address', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
68
+ />
69
+ </div>
70
  <span for="cscf_email" class="help-inline help-block error"
71
  style="display:<?php echo isset( $contact->Errors['email'] ) ? 'block' : 'none'; ?>;">
72
  <?php if ( isset( $contact->Errors['email'] ) ) {
73
+ echo esc_html( $contact->Errors['email'] );
74
  } ?>
75
  </span>
76
+ </div>
77
 
78
  <?php if ( $confirmEmail ) { ?>
79
+ <!--confirm email address -->
80
+ <div class="control-group form-group<?php if ( isset( $contact->Errors['confirm-email'] ) ) {
81
  echo ' error has-error';
82
  } ?>">
83
+ <label for="cscf_confirm-email"><?php esc_html_e( 'Confirm Email Address:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
84
+ <div class="<?php echo ( true === cscf_PluginSettings::InputIcons() ) ? 'input-group' : ''; ?>">
85
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
86
+ <span class="input-group-addon"><span class="glyphicon glyphicon-envelope"></span></span>
87
  <?php } ?>
88
+ <input class="form-control input-xlarge"
89
+ data-rule-required="true"
90
+ data-rule-email="true"
91
+ data-rule-equalTo="#cscf_email"
92
+ data-msg-required="<?php esc_html_e( 'Please enter the same email address again.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
93
+ data-msg-email="<?php esc_html_e( 'Please enter a valid email address.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
94
+ data-msg-equalTo="<?php esc_html_e( 'Please enter the same email address again.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
95
+ type="email" id="cscf_confirm-email" name="cscf[confirm-email]"
96
+ value="<?php echo esc_attr( $contact->ConfirmEmail ); ?>"
97
+ placeholder="<?php esc_html_e( 'Confirm Your Email Address', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
98
+ />
99
+ </div>
100
+ <span for="cscf_confirm-email" class="help-inline help-block error"
101
+ style="display:<?php echo isset( $contact->Errors['confirm-email'] ) ? 'block' : 'none'; ?>;">
102
  <?php if ( isset( $contact->Errors['confirm-email'] ) ) {
103
+ echo esc_attr( $contact->Errors['confirm-email'] );
104
  } ?>
105
  </span>
106
+ </div>
107
  <?php } ?>
108
 
109
 
110
+ <!-- message -->
111
+ <div class="control-group form-group<?php if ( isset( $contact->Errors['message'] ) ) {
112
  echo ' error has-error';
113
  } ?>">
114
+ <label for="cscf_message"><?php esc_html_e( 'Message:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
115
+ <div class="<?php echo ( true === cscf_PluginSettings::InputIcons() ) ? 'input-group' : ''; ?>">
116
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
117
+ <span class="input-group-addon"><span class="glyphicon glyphicon-comment"></span></span>
118
  <?php } ?>
119
+ <textarea class="form-control input-xlarge"
120
+ data-rule-required="true"
121
+ data-msg-required="<?php esc_html_e( 'Please give a message.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
122
+ id="cscf_message" name="cscf[message]" rows="10"
123
+ placeholder="<?php esc_html_e( 'Your Message', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"><?php echo esc_textarea( $contact->Message ); ?></textarea>
124
+ </div>
125
+
126
+ <span for="cscf_message" class="help-inline help-block error"
127
+ style="display:<?php echo isset( $contact->Errors['message'] ) ? 'block' : 'none'; ?>;">
128
  <?php if ( isset( $contact->Errors['message'] ) ) {
129
+ echo esc_attr( $contact->Errors['message'] );
130
  } ?>
131
  </span>
132
+ </div>
133
 
134
  <?php if ( cscf_PluginSettings::EmailToSender() ) { ?>
135
+ <!-- email to sender -->
136
+ <div class="control-group form-group<?php if ( isset( $contact->Errors['email-sender'] ) ) {
137
  echo ' error has-error';
138
  } ?>">
139
+ <label for="cscf_email-sender"><?php esc_html_e( 'Send me a copy:', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?></label>
140
+ <div class="<?php echo ( true === cscf_PluginSettings::InputIcons() ) ? "input-group" : ""; ?>">
141
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
142
+ <span class="input-group-addon"><span class="glyphicon glyphicon-comment"></span></span>
143
  <?php } ?>
144
+ <input <?php echo ( true == $contact->EmailToSender ) ? 'checked' : ''; ?> type="checkbox"
145
+ id="cscf_email-sender"
146
+ name="cscf[email-sender]">
147
+ </div>
148
+ <span for="cscf_email-sender" class="help-inline help-block error"
149
+ style="display:<?php echo isset( $contact->Errors['email-sender'] ) ? 'block' : 'none'; ?>;">
150
  <?php if ( isset( $contact->Errors['email-sender'] ) ) {
151
+ echo esc_attr( $contact->Errors['email-sender'] );
152
  } ?>
153
  </span>
154
+ </div>
155
  <?php } ?>
156
 
157
 
158
 
159
  <?php if ( cscf_PluginSettings::ContactConsent() ) { ?>
160
+ <!-- contact consent -->
161
+ <div class="control-group form-group<?php if ( isset( $contact->Errors['contact-consent'] ) ) {
162
  echo ' error has-error';
163
  } ?>">
164
+ <label for="cscf_contact-consent"><?php echo esc_html( cscf_PluginSettings::ContactConsentMsg() ); ?>
165
+ :</label>
166
+ <div class="<?php echo ( cscf_PluginSettings::InputIcons() ) ? "input-group" : ""; ?>">
167
  <?php if ( cscf_PluginSettings::InputIcons() == true ) { ?>
168
+ <span class="input-group-addon"><span class="glyphicon glyphicon-comment"></span></span>
169
  <?php } ?>
170
+ <input data-rule-required="true"
171
+ data-msg-required="<?php esc_html_e( 'Please give your consent.', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"
172
+ <?php echo ( true === $contact->ContactConsent ) ? 'checked' : ''; ?> type="checkbox"
173
+ id="cscf_contact-consent"
174
+ name="cscf[contact-consent]">
175
+ </div>
176
+ <span for="cscf[contact-consent]" class="help-inline help-block error"
177
+ style="display:<?php echo isset( $contact->Errors['contact-consent'] ) ? 'block' : 'none'; ?>;">
178
  <?php if ( isset( $contact->Errors['contact-consent'] ) ) {
179
+ echo esc_html( $contact->Errors['contact-consent'] );
180
  } ?>
181
  </span>
182
+ </div>
183
  <?php } ?>
184
 
185
+ <!-- recaptcha -->
186
  <?php if ( $contact->RecaptchaPublicKey <> '' && $contact->RecaptchaPrivateKey <> '' ) { ?>
187
 
188
+ <div class="control-group form-group<?php
189
  if ( isset( $contact->Errors['recaptcha'] ) ) {
190
  echo ' error has-error';
191
  } ?>">
192
+ <div id="recaptcha_div">
193
+ <div class="g-recaptcha" data-theme="<?php echo esc_attr( cscf_PluginSettings::Theme() ); ?>"
194
+ data-sitekey="<?php echo esc_attr( $contact->RecaptchaPublicKey ); ?>"></div>
195
 
196
 
197
+ <div for="cscf_recaptcha"
198
+ class="help-block has-error error"><?php if ( isset( $contact->Errors['recaptcha'] ) ) {
199
+ echo esc_html( $contact->Errors['recaptcha'] );
200
  } ?></div>
201
 
202
 
203
+ <noscript>
204
+ <div style="width: 302px; height: 422px;">
205
+ <div style="width: 302px; height: 422px; position: relative;">
206
+ <div style="width: 302px; height: 422px; position: absolute;">
207
+ <iframe
208
+ src="https://www.google.com/recaptcha/api/fallback?k=<?php echo esc_attr( $contact->RecaptchaPublicKey ); ?>"
209
+ frameborder="0" scrolling="no"
210
+ style="width: 302px; height:422px; border-style: none;">
211
+ </iframe>
212
+ </div>
213
+ <div style="width: 300px; height: 60px; border-style: none;
214
  bottom: 12px; left: 25px; margin: 0px; padding: 0px; right: 25px;
215
  background: #f9f9f9; border: 1px solid #c1c1c1; border-radius: 3px;">
216
  <textarea id="g-recaptcha-response" name="g-recaptcha-response"
218
  style="width: 250px; height: 40px; border: 1px solid #c1c1c1;
219
  margin: 10px 25px; padding: 0px; resize: none;">
220
  </textarea>
221
+ </div>
222
+ </div>
223
+ </div>
224
+ </noscript>
225
 
226
+ </div>
227
+ </div>
228
  <?php } ?>
229
+ <input type="submit" id="cscf_SubmitButton" class="btn btn-default"
230
+ value="<?php esc_html_e( 'Send Message', 'clean-and-simple-contact-form-by-meg-nicholas' ); ?>"/>
231
+ </form>
232
+ </div>
233
+ </div>
views/message-not-sent.view.php CHANGED
@@ -1 +1 @@
1
- <p><?php _e('Sorry, there has been a problem and your message was not sent.','clean-and-simple-contact-form-by-meg-nicholas') ?></p>
1
+ <p><?php esc_html_e('Sorry, there has been a problem and your message was not sent.','clean-and-simple-contact-form-by-meg-nicholas') ?></p>
views/message-sent.view.php CHANGED
@@ -1,2 +1,2 @@
1
- <h3><?php echo $heading; ?></h3>
2
- <p><?php echo $message; ?> </p>
1
+ <h3><?php echo esc_html($heading); ?></h3>
2
+ <p><?php echo esc_html($message); ?> </p>