Spam protection, AntiSpam, FireWall by CleanTalk - Version 5.185.1

Version Description

Sep 28 2022 =

Fixed a security issues.

  • Fix. Fixed a security issues.
Download this release

Release Info

Developer artemacleantalk
Plugin Icon 128x128 Spam protection, AntiSpam, FireWall by CleanTalk
Version 5.185.1
Comparing to
See all releases

Code changes from version 5.185 to 5.185.1

cleantalk.php CHANGED
@@ -4,7 +4,7 @@
4
  Plugin Name: Anti-Spam by CleanTalk
5
  Plugin URI: https://cleantalk.org
6
  Description: Max power, all-in-one, no Captcha, premium anti-spam plugin. No comment spam, no registration spam, no contact spam, protects any WordPress forms.
7
- Version: 5.185
8
  Author: СleanTalk <welcome@cleantalk.org>
9
  Author URI: https://cleantalk.org
10
  Text Domain: cleantalk-spam-protect
4
  Plugin Name: Anti-Spam by CleanTalk
5
  Plugin URI: https://cleantalk.org
6
  Description: Max power, all-in-one, no Captcha, premium anti-spam plugin. No comment spam, no registration spam, no contact spam, protects any WordPress forms.
7
+ Version: 5.185.1
8
  Author: СleanTalk <welcome@cleantalk.org>
9
  Author URI: https://cleantalk.org
10
  Text Domain: cleantalk-spam-protect
css/src/cleantalk-admin-settings-page.css ADDED
@@ -0,0 +1,279 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .apbct_settings-field_content,
2
+ .cleantalk_link-auto,
3
+ .cleantalk_link-manual,
4
+ .ct-warning-test-failed,
5
+ .ct_rate_block,
6
+ .ct_settings_banner,
7
+ i.animate-spin {
8
+ display: inline-block
9
+ }
10
+
11
+ #apbctTopWarning {margin-bottom: 5px;}
12
+ #apbctTopWarning h3{margin: 10px 0 5px 0;}
13
+ #apbctTopWarning h4{margin: 10px;}
14
+ #apbctTopWarning h4 span{margin-top: 5px;}
15
+
16
+ /* Main title */
17
+ /*.apbct_settings-title{ display: inline-block; }*/
18
+ .apbct_settings-subtitle{
19
+ position: relative;
20
+ top: -15px;
21
+ margin: 0;
22
+ }
23
+
24
+ /* Setting fields */
25
+ .apbct_settings-field_wrapper{ margin: 15px 0; }
26
+ .apbct_settings-field_wrapper--sub{ margin-left: 30px !important; }
27
+
28
+ .apbct_settings-field_title{ }
29
+ .apbct_settings__label{
30
+ margin-right: 10px;
31
+ font-size: 17px;
32
+ vertical-align: text-bottom;
33
+ }
34
+
35
+ .apbct_settings-field_content{ display: inline-block; }
36
+ .apbct_settings-field_content--checkbox{ }
37
+ .apbct_settings-field_content--radio,
38
+ .apbct_settings-field_wrapper > .apbct_settings-field_description {
39
+ width: 70%;
40
+ }
41
+ .apbct_settings-field_content--text{ }
42
+
43
+ .apbct_settings-field_title{}
44
+ .apbct_settings-field_title--checkbox{ }
45
+ .apbct_settings-field_title--radio{
46
+ display: inline-block;
47
+ margin: 0;
48
+ width: 210px;
49
+ padding-right: 10px;
50
+ font-size: 14px;
51
+ vertical-align: top;
52
+ }
53
+ .apbct_input_text{min-width: 255px; width: 400px;}
54
+
55
+ .apbct_settings-field--api_key{font-size: 14pt;}
56
+
57
+ .apbct_settings-long_description---show:hover{
58
+ color: #aaaaaa;
59
+ cursor: pointer;
60
+ }
61
+
62
+ .apbct_setting_textarea {
63
+ min-width: 300px;
64
+ }
65
+
66
+ .cleantalk_link {
67
+ text-decoration: none;
68
+ font-size: 13px;
69
+ line-height: 26px;
70
+ margin: 10px 0 0 0;
71
+ padding: 0 10px 1px;
72
+ cursor: pointer;
73
+ border-width: 1px;
74
+ border-style: solid;
75
+ -webkit-appearance: none;
76
+ white-space: nowrap;
77
+ -webkit-box-sizing: border-box;
78
+ -moz-box-sizing: border-box;
79
+ box-sizing: border-box;
80
+ }
81
+ .cleantalk_link-auto{
82
+ background: #ccc;
83
+ border-color: #999;
84
+ -webkit-box-shadow: inset 0 1px 0 rgba(200,200,200,.5),0 1px 0 rgba(0,0,0,.15);
85
+ box-shadow: inset 0 1px 0 rgba(200,200,200,.5),0 1px 0 rgba(0,0,0,.15);
86
+ color: #000;
87
+ display: inline-block;
88
+ height: 28px;
89
+ -webkit-border-radius: 2px;
90
+ border-radius: 2px;
91
+ }
92
+ .cleantalk_link-auto:hover {color: #fff;}
93
+ .cleantalk_link-manual {
94
+ background: #2ea2cc;
95
+ border-color: #0074a2;
96
+ -webkit-box-shadow: inset 0 1px 0 rgba(120, 200, 230, .5), 0 1px 0 rgba(0, 0, 0, .15);
97
+ box-shadow: inset 0 1px 0 rgba(120, 200, 230, .5), 0 1px 0 rgba(0, 0, 0, .15);
98
+ color: #fff;
99
+ display: inline-block;
100
+ -webkit-border-radius: 3px;
101
+ border-radius: 3px;
102
+ text-align: center;
103
+ }
104
+ .cleantalk_link-manual:hover {color:black;}
105
+ .cleantalk_link[disabled=disabled]{
106
+ background: #5d9db5; color: #000;
107
+ }
108
+
109
+ .apbct_status_icon{
110
+ vertical-align: text-bottom;
111
+ margin: 0 5px 0 8px;
112
+ }
113
+
114
+ a.ct_support_link{
115
+ color: #666;
116
+ margin-right: 0.5em;
117
+ font-size: 10pt;
118
+ font-weight: normal;
119
+ }
120
+
121
+ .ct-warning-test-failed {
122
+ display: inline-block;
123
+ position: relative;
124
+ padding: 5px;
125
+ margin: 4px;
126
+ border: 3px solid rgba(240,50,50,1);
127
+ border-radius: 5px;
128
+ background-color: rgba(255,200,200,1);
129
+ }
130
+
131
+ /* Settings banners */
132
+ .ct_settings_banner{
133
+ text-align: right;
134
+ display:inline-block;
135
+ width: 100%;
136
+ margin: 1em 0;
137
+ vertical-align: top;
138
+ }
139
+
140
+ #ct_translate_plugin {margin-left: 0;}
141
+ .ct_rate_block {
142
+ display: inline-block;
143
+ width: 370px;
144
+ margin-right: 3em;
145
+ padding: 0.8em 0.8em 15px 0.8em;
146
+ text-align: center;
147
+ border: 1px dashed #666;
148
+ }
149
+ #ct_translate_plugin .apbct_button_rate{margin-bottom: 10px;}
150
+
151
+ .apbct_long_desc{
152
+ position: absolute;
153
+ background: #5a5a5a;
154
+ min-width: 80px; min-height: 80px;
155
+ max-width: 500px;
156
+ padding: 10px;
157
+ color: white;
158
+ z-index: 10;
159
+ }
160
+ .apbct_long_desc a {
161
+ color: rgba(120,200,230,1);
162
+ }
163
+ i.animate-spin{
164
+ -moz-animation: spin 2s infinite linear;
165
+ -o-animation: spin 2s infinite linear;
166
+ -webkit-animation: spin 2s infinite linear;
167
+ animation: spin 2s infinite linear;
168
+ display: inline-block;
169
+ margin: 0 auto;
170
+ font-size: 25px;
171
+ line-height: 20px;
172
+ color: rgba(120,200,230,1);
173
+ margin: 25px;
174
+ }
175
+ @keyframes spin {
176
+ to{transform: rotate(359deg);}
177
+ }
178
+ .apbct_long_desc__cancel{
179
+ position: absolute;
180
+ top: 5px; right: 5px;
181
+ color: rgba(255,255,255,0.5);
182
+ }
183
+ .apbct_long_desc__cancel:hover{
184
+ color: white;
185
+ }
186
+ .apbct_long_desc__angle{
187
+ position: absolute;
188
+ top: 5px; left: -17px;
189
+ width: 10px; height: 10px;
190
+ background: #5a5a5a;
191
+ -webkit-transform: rotate(135deg);
192
+ -ms-transform: rotate(135deg);
193
+ transform: rotate(135deg);
194
+ -webkit-transform-origin: 100% 100%;
195
+ -ms-transform-origin: 100% 100%;
196
+ transform-origin: 100% 100%;
197
+ }
198
+ .apbct_long_desc__title{
199
+ color: rgba(120,200,230,1);
200
+ margin: 0;
201
+ }
202
+
203
+ .--hide{ display: none; }
204
+ .apbct_preloader_button{ height: 15px; margin-left: 5px; vertical-align: text-top; display: none; }
205
+
206
+ /* Modal Window Stiles */
207
+ #cleantalk-modal-content {
208
+ text-align: center;
209
+ }
210
+ #cleantalk-modal-content > * {
211
+ display: block;
212
+ width: 100%;
213
+ }
214
+
215
+ button.ct_support_link{
216
+ border: none;
217
+ background: transparent;
218
+ color: #666;
219
+ text-decoration: underline;
220
+ cursor: pointer;
221
+ }
222
+ .apbct-btn-as-link {
223
+ padding: 0;
224
+ margin: 0;
225
+ vertical-align: baseline;
226
+ color: gray;
227
+ border: 0 none;
228
+ border-bottom: 1px solid;
229
+ cursor: pointer;
230
+ }
231
+ #apbct-account-email[contenteditable="true"] {
232
+ padding: 6px;
233
+ background-color: #fff;
234
+ border: 1px solid #ccc;
235
+ }
236
+ button[value="save_changes"]:disabled {
237
+ color: #2271b1;
238
+ border-color: #2271b1;
239
+ background: #f6f7f7;
240
+ }
241
+ #apbct_settings__advanced_settings {
242
+ position: relative;
243
+ }
244
+ #apbct_settings__advanced_settings_inner {
245
+ width: 70%;
246
+ }
247
+ #apbct_hidden_section_nav {
248
+ position: absolute;
249
+ top: 0;
250
+ right: 20px;
251
+ }
252
+ #apbct_settings__after_advanced_settings{
253
+ margin-bottom: 20px;
254
+ }
255
+ #apbct_settings__button_section {
256
+ position: fixed;
257
+ z-index: 9999;
258
+ width: 100%;
259
+ padding-bottom: 40px;
260
+ }
261
+ #cleantalk_notice_review .caption {
262
+ margin: 0 0 15px;
263
+ color: gray;
264
+ }
265
+ #cleantalk_notice_review .button {
266
+ margin-bottom: 20px;
267
+ }
268
+
269
+ .apbct_highlighted{
270
+ outline-offset: 5px;
271
+ outline-color: red;
272
+ outline-width: 3px !important;
273
+ outline-style: solid !important;
274
+ }
275
+
276
+ .apbct_notice_inner{
277
+ display: flex;
278
+ margin-top: 10px !important;
279
+ }
css/src/cleantalk-admin.css ADDED
@@ -0,0 +1,86 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Common styles for admin pages */
2
+ :disabled{cursor: not-allowed !important;}
3
+ .apbct_color--gray{color: gray;}
4
+ .apbct_display--none{display: none;}
5
+
6
+ /* Additional styles for admin pages */
7
+ .ct_meta_links{
8
+
9
+ }
10
+ .ct_translate_links{color: rgba(150, 150, 20, 1);}
11
+ .ct_support_links {color: rgba(150, 20, 20, 1);}
12
+ .ct_faq_links {color: rgba(20, 150, 20, 1);}
13
+ .ct_setting_links {color: rgba(20, 20, 150, 1);}
14
+
15
+ .ct_translate_links:hover{color: rgba(210, 210, 20, 1) !important;}
16
+ .ct_support_links:hover {color: rgba(250, 20, 20, 1) !important;}
17
+ .ct_faq_links:hover {color: rgba(20, 250, 20, 1) !important;}
18
+ .ct_setting_links:hover {color: rgba(20, 20, 250, 1) !important;}
19
+
20
+ .ct_link_new_tab img{
21
+ float: none !important;
22
+ margin: 0 2px;
23
+ border: 0;
24
+ }
25
+
26
+ #negative_reports_table tr td{
27
+ padding: 7px 5px !important;
28
+ }
29
+
30
+ #wp-admin-bar-cleantalk_admin_bar__parent_node{
31
+ margin-right: 5px;
32
+ }
33
+
34
+ #wp-admin-bar-cleantalk_admin_bar__parent_node span {
35
+ display: inline-block;
36
+ }
37
+
38
+ #wp-admin-bar-cleantalk_admin_bar__parent_node .apbct-icon-attention-alt {
39
+ background: #d63638;
40
+ color: #fff;
41
+ border-radius: 50%;
42
+ font-size: 12px;
43
+ }
44
+
45
+ #wp-admin-bar-cleantalk_admin_bar__parent_node img.cleantalk_admin_bar__spbc_icon{
46
+ width: 14px;
47
+ height: 17px;
48
+ margin-top: 7px;
49
+ }
50
+
51
+ #wp-admin-bar-cleantalk_admin_bar__parent_node img.cleantalk_admin_bar__apbct_icon{
52
+ width: 18px;
53
+ height: 18px;
54
+ margin-top: 7px;
55
+ }
56
+
57
+ #wp-admin-bar-cleantalk_admin_bar__parent_node div.cleantalk_admin_bar__sum_counter{
58
+ color: #999;
59
+ display: inline;
60
+ padding: 2px 5px !important;
61
+ }
62
+
63
+ .cleantalk_admin_bar__blocked div{
64
+ cursor: not-allowed !important;
65
+ }
66
+
67
+ .cleantalk_admin_bar__blocked div a{
68
+ color: #777 !important;
69
+ }
70
+
71
+ .cleantalk_admin_bar__title{
72
+ vertical-align: top;
73
+ }
74
+
75
+ .cleantalk_admin_bar__separator{
76
+ height: 0px !important;
77
+ }
78
+
79
+ .cleantalk-admin_bar--list_wrapper .ab-sub-wrapper ul:last-child{
80
+ margin-bottom: 5px !important;
81
+ }
82
+
83
+ .apbct-plugin-errors {
84
+ margin-left: 0;
85
+ margin-bottom: 20px;
86
+ }
css/src/cleantalk-dashboard-widget.css ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ct_widget_wrapper {
2
+ position: relative;
3
+ width: 100%;
4
+ height: 100%;
5
+ }
6
+ .ct_widget_top_links {
7
+ text-align: right;
8
+ padding: 0 12px;
9
+ height: 32px;
10
+ }
11
+ .ct_widget_settings_link{margin: 0 0 0 10px;}
12
+ .ct_widget_refresh_link{}
13
+
14
+ .ct_preloader{
15
+ display: none;
16
+ float: left;
17
+ width: 20px; height: 20px;
18
+ margin: 0 10px;
19
+ }
20
+
21
+ .ct_widget_hr{
22
+ width: 100%;
23
+ }
24
+
25
+ .ct_widget_block_header{
26
+ font-size: 18px !important;
27
+ margin-left: 12px !important;
28
+ }
29
+
30
+ .ct_widget_block{
31
+ display: block; position: relative;
32
+ padding: 12px;
33
+ }
34
+ .ct_widget_chart_wrapper{
35
+ height: 300px;
36
+ margin-right: 10px;
37
+ }
38
+ #ct_widget_chart{}
39
+
40
+ .bar {fill: steelblue;}
41
+ .bar:nth-child(odd){fill: rgba(50,50,250,0.9);}
42
+ .bar:hover {fill: brown;}
43
+
44
+ .axis--x path {
45
+ display: none;
46
+ }
47
+
48
+ .ct_widget_block table{
49
+ width: 100%;
50
+ text-align: left;
51
+ }
52
+ .ct_widget_block table tr{margin-bottom: 10px;}
53
+ .ct_widget_block table th{
54
+ text-align: left;
55
+ padding: 10px 0 5px 10px;;
56
+ border-bottom: 2px solid gray;
57
+
58
+ }
59
+ .ct_widget_block table td{
60
+ text-align: left;
61
+ padding: 10px 0 5px 10px;;
62
+ border-bottom: 1px solid gray;
63
+ }
64
+ #ct_widget_wrapper .ct_widget_block table td.ct_widget_block__country_cell img {
65
+ width: 16px !important;
66
+ height: auto;
67
+ }
68
+
69
+ .ct_widget_button{
70
+ display: block;
71
+ margin: 10px auto;
72
+ }
73
+ .ct_widget_activate_button{
74
+ display: block;
75
+ margin: 10px auto; padding: 7px 15px;
76
+ font-weight: 600;
77
+ border-radius: 3px;
78
+ border: 2px solid #aaa;
79
+ background: rgba(250,50,50,0.9);
80
+ }
81
+ .ct_widget_resolve_button{
82
+ background: rgba(50,250,50,0.9);
83
+ }
84
+ .ct_widget_activate_header{
85
+ display: inline-block;
86
+ width: 100%;
87
+ text-align: center;
88
+ font-size: 18px !important;
89
+ }
90
+ .ct_widget_wprapper_total_blocked{
91
+ padding: 10px 0 10px 10px;
92
+ background: #f1f1f1;
93
+ }
94
+ .ct_widget_wprapper_total_blocked span{
95
+ position: relative;
96
+ top: 2px;
97
+ }
98
+ .ct_widget_small_logo{
99
+ margin-right: 1em;
100
+ vertical-align: middle;
101
+ }
102
+ #ct_widget_wrapper .ct_widget_wprapper_total_blocked img.ct_widget_small_logo {
103
+ width: 24px !important;
104
+ height: 24px !important;
105
+ }
106
+ #ct_widget_button_view_all{
107
+ cursor: pointer;
108
+ border: 1px solid #0074a2;
109
+ -webkit-appearance: none;
110
+ -webkit-border-radius: 2px;
111
+ border-radius: 2px;
112
+ white-space: nowrap;
113
+ -webkit-box-sizing: border-box;
114
+ -moz-box-sizing: border-box;
115
+ box-sizing: border-box;
116
+ background: #0085ba;
117
+ -webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,.5), 0 1px 0 rgba(0,0,0,.15);
118
+ box-shadow: inset 0 1px 0 rgba(120,200,230,.5), 0 1px 0 rgba(0,0,0,.15);
119
+ color: #fff;
120
+ }
121
+ #ct_widget_button_view_all:hover{color: #000 !important;}
122
+
css/src/cleantalk-icons.css ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @font-face {
2
+ font-family: 'fontello';
3
+ src: url('./fonts/icons/icons.eot');
4
+ src: url('./fonts/icons/icons.eot') format('embedded-opentype'),
5
+ url('./fonts/icons/icons.woff2') format('woff2'),
6
+ url('./fonts/icons/icons.woff') format('woff'),
7
+ url('./fonts/icons/icons.ttf') format('truetype'),
8
+ url('./fonts/icons/icons.svg') format('svg');
9
+ font-weight: normal;
10
+ font-style: normal;
11
+ }
12
+ /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
13
+ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
14
+ /*
15
+ @media screen and (-webkit-min-device-pixel-ratio:0) {
16
+ @font-face {
17
+ font-family: 'fontello';
18
+ src: url('./fonts/icons/icons.svg') format('svg');
19
+ }
20
+ }
21
+ */
22
+
23
+ [class^="apbct-icon-"]:before, [class*=" apbct-icon-"]:before {
24
+ font-family: "fontello";
25
+ font-style: normal;
26
+ font-weight: normal;
27
+ speak: none;
28
+
29
+ display: inline-block;
30
+ text-decoration: inherit;
31
+ width: 1em;
32
+ margin-right: .2em;
33
+ text-align: center;
34
+ /* opacity: .8; */
35
+
36
+ /* For safety - reset parent styles, that can break glyph codes*/
37
+ font-variant: normal;
38
+ text-transform: none;
39
+
40
+ /* fix buttons height, for twitter bootstrap */
41
+ line-height: 1em;
42
+
43
+ /* Animation center compensation - margins should be symmetric */
44
+ /* remove if not needed */
45
+ margin-left: .2em;
46
+
47
+ /* you can be more comfortable with increased icons size */
48
+ /* font-size: 120%; */
49
+
50
+ /* Font smoothing. That was taken from TWBS */
51
+ -webkit-font-smoothing: antialiased;
52
+ -moz-osx-font-smoothing: grayscale;
53
+
54
+ /* Uncomment for 3D effect */
55
+ /* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
56
+ }
57
+
58
+ .apbct-icon-download:before { content: '\e800'; } /* '' */
59
+ .apbct-icon-glass:before { content: '\e801'; } /* '' */
60
+ .apbct-icon-emo-happy:before { content: '\e802'; } /* '' */
61
+ .apbct-icon-search:before { content: '\e803'; } /* '' */
62
+ .apbct-icon-emo-unhappy:before { content: '\e804'; } /* '' */
63
+ .apbct-icon-mail:before { content: '\e805'; } /* '' */
64
+ .apbct-icon-info-circled:before { content: '\e806'; } /* '' */
65
+ .apbct-icon-help-circled:before { content: '\e807'; } /* '' */
66
+ .apbct-icon-heart:before { content: '\e808'; } /* '' */
67
+ .apbct-icon-heart-empty:before { content: '\e809'; } /* '' */
68
+ .apbct-icon-star:before { content: '\e80a'; } /* '' */
69
+ .apbct-icon-star-empty:before { content: '\e80b'; } /* '' */
70
+ .apbct-icon-user:before { content: '\e80c'; } /* '' */
71
+ .apbct-icon-users:before { content: '\e80d'; } /* '' */
72
+ .apbct-icon-th-large:before { content: '\e80e'; } /* '' */
73
+ .apbct-icon-th:before { content: '\e80f'; } /* '' */
74
+ .apbct-icon-th-list:before { content: '\e810'; } /* '' */
75
+ .apbct-icon-to-end:before { content: '\e811'; } /* '' */
76
+ .apbct-icon-to-start:before { content: '\e812'; } /* '' */
77
+ .apbct-icon-fast-fw:before { content: '\e813'; } /* '' */
78
+ .apbct-icon-fast-bw:before { content: '\e814'; } /* '' */
79
+ .apbct-icon-off:before { content: '\e815'; } /* '' */
80
+ .apbct-icon-chart-bar:before { content: '\e816'; } /* '' */
81
+ .apbct-icon-home:before { content: '\e817'; } /* '' */
82
+ .apbct-icon-link-1:before { content: '\e818'; } /* '' */
83
+ .apbct-icon-lock-open:before { content: '\e819'; } /* '' */
84
+ .apbct-icon-eye:before { content: '\e81a'; } /* '' */
85
+ .apbct-icon-eye-off:before { content: '\e81b'; } /* '' */
86
+ .apbct-icon-download-1:before { content: '\e81c'; } /* '' */
87
+ .apbct-icon-chat:before { content: '\e81d'; } /* '' */
88
+ .apbct-icon-comment:before { content: '\e81e'; } /* '' */
89
+ .apbct-icon-doc:before { content: '\e81f'; } /* '' */
90
+ .apbct-icon-lock:before { content: '\e820'; } /* '' */
91
+ .apbct-icon-emo-wink2:before { content: '\e821'; } /* '' */
92
+ .apbct-icon-plus:before { content: '\e822'; } /* '' */
93
+ .apbct-icon-upload:before { content: '\e823'; } /* '' */
94
+ .apbct-icon-picture:before { content: '\e824'; } /* '' */
95
+ .apbct-icon-ok:before { content: '\e825'; } /* '' */
96
+ .apbct-icon-cancel:before { content: '\e826'; } /* '' */
97
+ .apbct-icon-pencil:before { content: '\e827'; } /* '' */
98
+ .apbct-icon-edit:before { content: '\e828'; } /* '' */
99
+ .apbct-icon-forward:before { content: '\e829'; } /* '' */
100
+ .apbct-icon-export:before { content: '\e82a'; } /* '' */
101
+ .apbct-icon-trash-empty:before { content: '\e82b'; } /* '' */
102
+ .apbct-icon-down-dir:before { content: '\e82c'; } /* '' */
103
+ .apbct-icon-up-dir:before { content: '\e82d'; } /* '' */
104
+ .apbct-icon-left-dir:before { content: '\e82e'; } /* '' */
105
+ .apbct-icon-right-dir:before { content: '\e82f'; } /* '' */
106
+ .apbct-icon-spin1:before { content: '\e830'; } /* '' */
107
+ .apbct-icon-spin2:before { content: '\e831'; } /* '' */
108
+ .apbct-icon-mobile:before { content: '\e832'; } /* '' */
109
+ .apbct-icon-bell:before { content: '\e833'; } /* '' */
110
+ .apbct-icon-ccw:before { content: '\e834'; } /* '' */
111
+ .apbct-icon-wrench:before { content: '\e835'; } /* '' */
112
+ .apbct-icon-stop-1:before { content: '\e837'; } /* '' */
113
+ .apbct-icon-spin5:before { content: '\e838'; } /* '' */
114
+ .apbct-icon-pause-1:before { content: '\e839'; } /* '' */
115
+ .apbct-icon-play-1:before { content: '\e83a'; } /* '' */
116
+ .apbct-icon-link-ext:before { content: '\f08e'; } /* '' */
117
+ .apbct-icon-menu:before { content: '\f0c9'; } /* '' */
118
+ .apbct-icon-sort:before { content: '\f0dc'; } /* '' */
119
+ .apbct-icon-mail-alt:before { content: '\f0e0'; } /* '' */
120
+ .apbct-icon-lightbulb:before { content: '\f0eb'; } /* '' */
121
+ .apbct-icon-exchange:before { content: '\f0ec'; } /* '' */
122
+ .apbct-icon-upload-cloud:before { content: '\f0ee'; } /* '' */
123
+ .apbct-icon-bell-alt:before { content: '\f0f3'; } /* '' */
124
+ .apbct-icon-doc-text:before { content: '\f0f6'; } /* '' */
125
+ .apbct-icon-angle-double-left:before { content: '\f100'; } /* '' */
126
+ .apbct-icon-angle-double-right:before { content: '\f101'; } /* '' */
127
+ .apbct-icon-angle-double-up:before { content: '\f102'; } /* '' */
128
+ .apbct-icon-angle-double-down:before { content: '\f103'; } /* '' */
129
+ .apbct-icon-desktop:before { content: '\f108'; } /* '' */
130
+ .apbct-icon-laptop:before { content: '\f109'; } /* '' */
131
+ .apbct-icon-tablet:before { content: '\f10a'; } /* '' */
132
+ .apbct-icon-circle-empty:before { content: '\f10c'; } /* '' */
133
+ .apbct-icon-circle:before { content: '\f111'; } /* '' */
134
+ .apbct-icon-unlink:before { content: '\f127'; } /* '' */
135
+ .apbct-icon-help:before { content: '\f128'; } /* '' */
136
+ .apbct-icon-info:before { content: '\f129'; } /* '' */
137
+ .apbct-icon-attention-alt:before { content: '\f12a'; } /* '' */
138
+ .apbct-icon-ellipsis:before { content: '\f141'; } /* '' */
139
+ .apbct-icon-ellipsis-vert:before { content: '\f142'; } /* '' */
140
+ .apbct-icon-euro:before { content: '\f153'; } /* '' */
141
+ .apbct-icon-pound:before { content: '\f154'; } /* '' */
142
+ .apbct-icon-dollar:before { content: '\f155'; } /* '' */
143
+ .apbct-icon-rupee:before { content: '\f156'; } /* '' */
144
+ .apbct-icon-yen:before { content: '\f157'; } /* '' */
145
+ .apbct-icon-rouble:before { content: '\f158'; } /* '' */
146
+ .apbct-icon-won:before { content: '\f159'; } /* '' */
147
+ .apbct-icon-bitcoin:before { content: '\f15a'; } /* '' */
148
+ .apbct-icon-sort-alt-up:before { content: '\f160'; } /* '' */
149
+ .apbct-icon-sort-alt-down:before { content: '\f161'; } /* '' */
150
+ .apbct-icon-bug:before { content: '\f188'; } /* '' */
151
+ .apbct-icon-try:before { content: '\f195'; } /* '' */
152
+ .apbct-icon-wordpress:before { content: '\f19a'; } /* '' */
153
+ .apbct-icon-cubes:before { content: '\f1b3'; } /* '' */
154
+ .apbct-icon-database:before { content: '\f1c0'; } /* '' */
155
+ .apbct-icon-circle-thin:before { content: '\f1db'; } /* '' */
156
+ .apbct-icon-sliders:before { content: '\f1de'; } /* '' */
157
+ .apbct-icon-share:before { content: '\f1e0'; } /* '' */
158
+ .apbct-icon-plug:before { content: '\f1e6'; } /* '' */
159
+ .apbct-icon-trash:before { content: '\f1f8'; } /* '' */
160
+ .apbct-icon-chart-line:before { content: '\f201'; } /* '' */
161
+ .apbct-icon-shekel:before { content: '\f20b'; } /* '' */
162
+ .apbct-icon-user-secret:before { content: '\f21b'; } /* '' */
163
+ .apbct-icon-user-plus:before { content: '\f234'; } /* '' */
164
+ .apbct-icon-user-times:before { content: '\f235'; } /* '' */
165
+ .apbct-icon-viacoin:before { content: '\f237'; } /* '' */
166
+ .apbct-icon-safari:before { content: '\f267'; } /* '' */
167
+ .apbct-icon-chrome:before { content: '\f268'; } /* '' */
168
+ .apbct-icon-firefox:before { content: '\f269'; } /* '' */
169
+ .apbct-icon-opera:before { content: '\f26a'; } /* '' */
170
+ .apbct-icon-internet-explorer:before { content: '\f26b'; } /* '' */
171
+ .apbct-icon-television:before { content: '\f26c'; } /* '' */
172
+ .apbct-icon-percent:before { content: '\f295'; } /* '' */
css/src/cleantalk-public-admin.css ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .ct_hidden{
2
+ display: none;
3
+ }
4
+
5
+ .ct_comment_info{
6
+ position: relative;
7
+ font-size: 11px;
8
+ line-height: 12px;
9
+ margin-bottom: 15px;
10
+ }
11
+ .ct_comment_info img, .ct_comment_info a{
12
+ display: inline-block;
13
+ }
14
+
15
+ .ct_comment_titles
16
+ {
17
+ border-bottom: 1px solid gray !important;
18
+ background: inherit;
19
+ margin-bottom: 15px;
20
+ }
21
+ p.ct_comment_info_title{
22
+ display: inline-block;
23
+ }
24
+ p.ct_comment_logo_title{
25
+ float:right;
26
+ display: inline-block;
27
+ }
28
+ .ct_comment_logo_img{
29
+ height: 12px;
30
+ vertical-align: text-top;
31
+ box-shadow: transparent 0 0 0 !important;
32
+ }
33
+
34
+ .ct_this_is{
35
+ padding: 2px 3px;
36
+ cursor: pointer;
37
+ white-space: nowrap;
38
+ color: black !important;
39
+ background: rgba(230,230,230,1);
40
+ border: 1px solid #777;
41
+ border-radius: 4px;
42
+ }
43
+ .ct_this_is_spam{
44
+
45
+ }
46
+ p.ct_feedback_wrap{
47
+ display: none;
48
+ position: absolute;
49
+ top: 37px; left: 0;
50
+ width: 100%; height: 27px;
51
+ margin: 0;
52
+ padding: 6px 6px;
53
+ border-radius: 3px;
54
+ background: white;
55
+ }
56
+ .ct_feedback_result{display: none; text-decoration: underline;}
57
+ .ct_feedback_result_spam{color: red;}
58
+ .ct_feedback_result_not_spam{color: green;}
59
+
60
+ .ct_feedback_msg a{color: green !important; text-decoration: underline;}
61
+
62
+ .ct_feedback_success{color: green;}
63
+ .ct_feedback_error{color: red;}
64
+ .ct_feedback_no_hash{color: blue;}
css/src/cleantalk-public.css ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*.apbct-email-encoder{*/
2
+ /* position: relative;*/
3
+ /*}*/
4
+ /*.apbct-tooltip{*/
5
+ /* position: relative;*/
6
+ /*}*/
7
+ /* .apbct-tooltip--text{*/
8
+ /* position: absolute;*/
9
+ /* background: lightgray;*/
10
+ /* border-radius: 10px;*/
11
+ /* padding: 5px;*/
12
+ /* color: white;*/
13
+ /* top: 4px;*/
14
+ /* }*/
15
+ /* .apbct-tooltip--arrow{*/
16
+ /* position: absolute;*/
17
+ /* top: 0px;*/
18
+ /* left: 15px;*/
19
+ /* width: 10px;*/
20
+ /* height: 10px;*/
21
+ /* background: #5a5a5a;*/
22
+ /* transform: rotate(135deg);*/
23
+ /* }*/
24
+
25
+ #honeypot-field-url {
26
+ display: none !important;
27
+ }
28
+ .comment-form-cookies-consent {
29
+ width:100%;
30
+ overflow: hidden;
31
+ }
32
+ .wc_apbct_email_id {
33
+ display: none !important;
34
+ }
35
+ .um-form input[type=text].apbct_special_field,
36
+ input[class*='apbct'].apbct_special_field{
37
+ display: none !important;
38
+ }
39
+
40
+ .apbct-email-encoder{
41
+ position: relative;
42
+ }
43
+ .apbct-tooltip{
44
+ display: none;
45
+ position: absolute;
46
+ top: 35px;
47
+ left: 15px;
48
+ background: lightgray;
49
+ border-radius: 5px;
50
+ opacity: .9;
51
+ }
52
+ .apbct-tooltip--text{
53
+ position: absolute;
54
+ background: lightgray;
55
+ padding: 10px;
56
+ border-radius: 5px;
57
+ width: max-content;
58
+ }
59
+ .apbct-tooltip--arrow{
60
+ position: absolute;
61
+ background: lightgray;
62
+ width: 10px;
63
+ height: 10px;
64
+ top: -5px;
65
+ left: 10px;
66
+ transform: rotate(135deg);
67
+ }
css/src/cleantalk-spam-check.css ADDED
@@ -0,0 +1,94 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #ct_checking_status, #ct_cooling_notice, #ct_error_message h3, #ct_checking_count, #ct_error_message h4{
2
+ text-align: center;
3
+ width:90%;
4
+ }
5
+
6
+ #ct_preloader{
7
+ display:none;
8
+ width:100%;
9
+ text-align:center;
10
+ }
11
+ #ct_preloader img {
12
+ border: none !important;
13
+ }
14
+ #ct_working_message{
15
+ display:none;
16
+ margin: 1em auto auto auto;
17
+ padding:3px;
18
+ width:70%;
19
+ border:2px dotted gray;
20
+ background:#ffff99;
21
+ }
22
+
23
+ #ct_pause{
24
+ display:none;
25
+ }
26
+
27
+ div.ct_check_params_wrapper{}
28
+ .ct_check_params_elem{}
29
+ .ct_check_params_elem_sub{
30
+ margin: 15px 0 0 25px;
31
+ width: 150px;
32
+ display: inline-block;
33
+ }
34
+ .ct_check_params_elem_sub_sub{ margin: 15px 0 0 50px; }
35
+ button#ct_check_spam_button{
36
+ background: #2ea2cc;
37
+ border-color: #0074a2;
38
+ color: #fff;
39
+ -webkit-box-shadow: inset 0 1px 0 rgba(120,200,230,.5), 0 1px 0 rgba(0,0,0,.15);
40
+ box-shadow: inset 0 1px 0 rgba(120,200,230,.5), 0 1px 0 rgba(0,0,0,.15);
41
+ }
42
+ button#ct_check_spam_button:hover{ color: black; }
43
+ .ct_date{
44
+ display: inline;
45
+ width: 150px;
46
+ }
47
+ .ct_check_params_desc{
48
+ display: inline-block;
49
+ margin: 5px 10px 10px 15px;
50
+ }
51
+ #ct_check_tabs {
52
+ border: 1px solid #c5c5c5;
53
+ border-radius: 3px;
54
+ padding: .2em;
55
+ background: #ffffff;
56
+ }
57
+ #ct_check_tabs ul {
58
+ margin: 0;
59
+ padding: .2em .2em 0;
60
+ border: 1px solid #c5c5c5;
61
+ border-radius: 3px;
62
+ background: #e9e9e9;
63
+ color: #333333;
64
+ font-weight: bold;
65
+ display: flex;
66
+ }
67
+ #ct_check_tabs ul li {
68
+ list-style: none;
69
+ position: relative;
70
+ margin: 1px .2em -1px 0;
71
+ padding: 0;
72
+ white-space: nowrap;
73
+ border: 1px solid #c5c5c5;
74
+ border-radius: 3px 3px 0 0;
75
+ background: #fff;
76
+ font-weight: normal;
77
+ }
78
+ #ct_check_tabs ul li.active {
79
+ border-bottom: 1px solid transparent;
80
+ }
81
+ #ct_check_tabs ul li a {
82
+ display: block;
83
+ padding: .5em 1em;
84
+ text-decoration: none;
85
+ }
86
+ #ct_check_tabs ul li.active a {
87
+ font-weight: bold;
88
+ }
89
+ #ct_check_content {
90
+ display: block;
91
+ border-width: 0;
92
+ padding: 1em 1.4em;
93
+ background: none;
94
+ }
js/src/apbct-disable-comments.js ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ "use strict";
2
+ wp.domReady(function () {
3
+ if (wp.blocks) {
4
+ wp.blocks.getBlockTypes().forEach(function (block) {
5
+ if (apbctDisableComments.disabled_blocks.includes(block.name)) {
6
+ wp.blocks.unregisterBlockType(block.name);
7
+ }
8
+ });
9
+ }
10
+ });
js/src/apbct-public--0--LibBundle.js ADDED
@@ -0,0 +1,865 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class ApbctCore{
2
+
3
+ ajax_parameters = {};
4
+ rest_parameters = {};
5
+
6
+ #selector = null;
7
+ elements = [];
8
+
9
+ // Event properties
10
+ #eventCallback;
11
+ #eventSelector;
12
+ #event;
13
+
14
+ /**
15
+ * Default constructor
16
+ */
17
+ constructor(selector){
18
+ this.select(selector);
19
+ }
20
+
21
+ /**
22
+ * Get elements by CSS selector
23
+ *
24
+ * @param selector
25
+ * @returns {*}
26
+ */
27
+ select(selector) {
28
+
29
+ if(selector instanceof HTMLCollection){
30
+ this.#selector = null;
31
+ this.elements = [];
32
+ this.elements = Array.prototype.slice.call(selector);
33
+ }else if( typeof selector === 'object' ){
34
+ this.#selector = null;
35
+ this.elements = [];
36
+ this.elements[0] = selector;
37
+ }else if( typeof selector === 'string' ){
38
+ this.#selector = selector;
39
+ this.elements = Array.prototype.slice.call(document.querySelectorAll(selector));
40
+ // this.elements = document.querySelectorAll(selector)[0];
41
+ }else{
42
+ this.#deselect();
43
+ }
44
+
45
+ return this;
46
+ }
47
+
48
+ #addElement(elemToAdd){
49
+ if( typeof elemToAdd === 'object' ){
50
+ this.elements.push(elemToAdd);
51
+ }else if( typeof elemToAdd === 'string' ){
52
+ this.#selector = elemToAdd;
53
+ this.elements = Array.prototype.slice.call(document.querySelectorAll(elemToAdd));
54
+ }else{
55
+ this.#deselect();
56
+ }
57
+ }
58
+
59
+ #push(elem){
60
+ this.elements.push(elem);
61
+ }
62
+
63
+ #reduce(){
64
+ this.elements = this.elements.slice(0,-1);
65
+ }
66
+
67
+ #deselect(){
68
+ this.elements = [];
69
+ }
70
+
71
+ /**
72
+ * Set or get CSS for/of currently selected element
73
+ *
74
+ * @param style
75
+ * @param getRaw
76
+ *
77
+ * @returns {boolean|*}
78
+ */
79
+ css(style, getRaw){
80
+
81
+ getRaw = getRaw | false;
82
+
83
+ // Set style
84
+ if(typeof style === "object"){
85
+
86
+ const stringToCamelCase = str =>
87
+ str.replace(/([-_][a-z])/g, group =>
88
+ group
89
+ .toUpperCase()
90
+ .replace('-', '')
91
+ .replace('_', '')
92
+ );
93
+
94
+ // Apply multiple styles
95
+ for(let style_name in style){
96
+ let DOM_style_name = stringToCamelCase(style_name);
97
+
98
+ // Apply to multiple elements (currently selected)
99
+ for(let i=0; i<this.elements.length; i++){
100
+ this.elements[i].style[DOM_style_name] = style[style_name];
101
+ }
102
+ }
103
+
104
+ return this;
105
+ }
106
+
107
+ // Get style of first currently selected element
108
+ if(typeof style === 'string'){
109
+
110
+ let computedStyle = getComputedStyle(this.elements[0])[style];
111
+
112
+ console.log(computedStyle);
113
+
114
+ // Process
115
+ if( typeof computedStyle !== 'undefined' && ! getRaw){
116
+ computedStyle = computedStyle.replace(/(\d)(em|pt|%|px){1,2}$/, '$1'); // Cut of units
117
+ computedStyle = Number(computedStyle) == computedStyle ? Number(computedStyle) : computedStyle; // Cast to INT
118
+ return computedStyle;
119
+ }
120
+
121
+ // Return unprocessed
122
+ return computedStyle;
123
+ }
124
+ }
125
+
126
+ hide(){
127
+ this.prop('prev-display', this.css('display'));
128
+ this.css({'display': 'none'});
129
+ }
130
+
131
+ show(){
132
+ this.css({'display': this.prop('prev-display')});
133
+ }
134
+
135
+ addClass(){
136
+ for(let i=0; i<this.elements.length; i++){
137
+ this.elements[i].classList.add(className);
138
+ }
139
+ }
140
+
141
+ removeClass(){
142
+ for(let i=0; i<this.elements.length; i++){
143
+ this.elements[i].classList.remove(className);
144
+ }
145
+ }
146
+
147
+ toggleClass(className){
148
+ for(let i=0; i<this.elements.length; i++){
149
+ this.elements[i].classList.toggle(className);
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Wrapper for apbctAJAX class
155
+ *
156
+ * @param ajax_parameters
157
+ * @returns {ApbctAjax}
158
+ */
159
+ ajax(ajax_parameters){
160
+ this.ajax_parameters = ajax_parameters;
161
+ return new ApbctAjax(ajax_parameters);
162
+ }
163
+
164
+ /**
165
+ * Wrapper for apbctREST class
166
+ *
167
+ * @param rest_parameters
168
+ * @returns {ApbctRest}
169
+ */
170
+ rest(rest_parameters){
171
+ this.rest_parameters = rest_parameters;
172
+ return new ApbctRest(rest_parameters);
173
+ }
174
+
175
+ /************** EVENTS **************/
176
+
177
+ /**
178
+ *
179
+ * Why the mess with arguments?
180
+ *
181
+ * Because we need to support the following function signatures:
182
+ * on('click', function(){ alert('some'); });
183
+ * on('click', 'inner_selector', function(){ alert('some'); });
184
+ *
185
+ * @param args
186
+ */
187
+ on(...args){
188
+
189
+ this.#event = args[0];
190
+ this.#eventCallback = args[2] || args[1];
191
+ this.#eventSelector = typeof args[1] === "string" ? args[1] : null;
192
+
193
+ for(let i=0; i<this.elements.length; i++){
194
+ this.elements[i].addEventListener(
195
+ this.#event,
196
+ this.#eventSelector !== null
197
+ ? this.#onChecker.bind(this)
198
+ : this.#eventCallback
199
+ );
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Check if a selector of an event matches current target
205
+ *
206
+ * @param event
207
+ * @returns {*}
208
+ */
209
+ #onChecker(event){
210
+ if(event.target === document.querySelector(this.#eventSelector)){
211
+ event.stopPropagation();
212
+ return this.#eventCallback(event);
213
+ }
214
+ }
215
+
216
+ ready(callback){
217
+ document.addEventListener('DOMContentLoaded', callback);
218
+ }
219
+
220
+ change(callback){
221
+ this.on('change', callback);
222
+ }
223
+
224
+ /************** ATTRIBUTES **************/
225
+
226
+ /**
227
+ * Get an attribute or property of an element
228
+ *
229
+ * @param attrName
230
+ * @returns {*|*[]}
231
+ */
232
+ attr(attrName){
233
+
234
+ let outputValue = [];
235
+
236
+ for(let i=0; i<this.elements.length; i++){
237
+
238
+ // Use property instead of attribute if possible
239
+ if(typeof this.elements[i][attrName] !== undefined){
240
+ outputValue.push(this.elements[i][attrName]);
241
+ }else{
242
+ outputValue.push(this.elements[i].getAttribute(attrName));
243
+ }
244
+ }
245
+
246
+ // Return a single value instead of array if only one value is present
247
+ return outputValue.length === 1 ? outputValue[0] : outputValue;
248
+ }
249
+
250
+ prop(propName, value){
251
+
252
+ // Setting values
253
+ if(typeof value !== "undefined"){
254
+ for(let i=0; i<this.elements.length; i++){
255
+ this.elements[i][propName] = value;
256
+ }
257
+
258
+ return this;
259
+
260
+ // Getting values
261
+ }else{
262
+
263
+ let outputValue = [];
264
+
265
+ for(let i=0; i<this.elements.length; i++){
266
+ outputValue.push(this.elements[i][propName]);
267
+ }
268
+
269
+ // Return a single value instead of array if only one value is present
270
+ return outputValue.length === 1 ? outputValue[0] : outputValue;
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Set or get inner HTML
276
+ *
277
+ * @param value
278
+ * @returns {*|*[]}
279
+ */
280
+ html(value){
281
+ return typeof value !== 'undefined'
282
+ ? this.prop('innerHTML', value)
283
+ : this.prop('innerHTML');
284
+ }
285
+
286
+ /**
287
+ * Set or get value of input tags
288
+ *
289
+ * @param value
290
+ * @returns {*|*[]|undefined}
291
+ */
292
+ val(value){
293
+ return typeof value !== 'undefined'
294
+ ? this.prop('value', value)
295
+ : this.prop('value');
296
+ }
297
+
298
+ data(name, value){
299
+ return typeof value !== 'undefined'
300
+ ? this.prop('apbct-data', name, value)
301
+ : this.prop('apbct-data');
302
+ }
303
+
304
+ /************** END OF ATTRIBUTES **************/
305
+
306
+ /************** FILTERS **************/
307
+
308
+ /**
309
+ * Check if the current elements are corresponding to filter
310
+ *
311
+ * @param filter
312
+ * @returns {boolean}
313
+ */
314
+ is(filter){
315
+
316
+ let outputValue = false;
317
+
318
+ for(let elem of this.elements){
319
+ outputValue ||= this.#isElem(elem, filter);
320
+ }
321
+
322
+ return outputValue;
323
+ }
324
+
325
+ #isElem(elemToCheck, filter){
326
+
327
+ let is = false;
328
+ let isRegisteredTagName = function(name){
329
+ let newlyCreatedElement = document.createElement(name).constructor;
330
+ return ! Boolean( ~[HTMLElement, HTMLUnknownElement].indexOf(newlyCreatedElement) );
331
+ };
332
+
333
+ // Check for filter function
334
+ if(typeof filter === 'function') {
335
+ is ||= filter.call(this, elemToCheck);
336
+ }
337
+
338
+ // Check for filter function
339
+ if(typeof filter === 'string') {
340
+
341
+ // Filter is tag name
342
+ if( filter.match(/^[a-z]/) && isRegisteredTagName(filter) ){
343
+ is ||= elemToCheck.tagName.toLowerCase() === filter.toLowerCase();
344
+
345
+ // Filter is property
346
+ }else if( filter.match(/^[a-z]/) ){
347
+ is ||= Boolean(elemToCheck[filter]);
348
+
349
+ // Filter is CSS selector
350
+ }else {
351
+ is ||= this.#selector !== null
352
+ ? document.querySelector(this.#selector + filter) !== null // If possible
353
+ : this.#isWithoutSelector(elemToCheck, filter); // Search through all elems with such selector
354
+ }
355
+ }
356
+
357
+ return is;
358
+ }
359
+
360
+ #isWithoutSelector(elemToCheck, filter){
361
+
362
+ let elems = document.querySelectorAll(filter);
363
+ let outputValue = false;
364
+
365
+ for(let elem of elems){
366
+ outputValue ||= elemToCheck === elem;
367
+ }
368
+
369
+ return outputValue;
370
+ }
371
+
372
+ filter(filter){
373
+
374
+ this.#selector = null;
375
+
376
+ for( let i = this.elements.length - 1; i >= 0; i-- ){
377
+ if( ! this.#isElem(this.elements[i], filter) ){
378
+ this.elements.splice(Number(i), 1);
379
+ }
380
+ }
381
+
382
+ return this;
383
+ }
384
+
385
+ /************** NODES **************/
386
+
387
+ parent(filter){
388
+
389
+ this.select(this.elements[0].parentElement);
390
+
391
+ if( typeof filter !== 'undefined' && ! this.is(filter) ){
392
+ this.#deselect();
393
+ }
394
+
395
+ return this;
396
+ }
397
+
398
+ parents(filter){
399
+
400
+ this.select(this.elements[0]);
401
+
402
+ for ( ; this.elements[ this.elements.length - 1].parentElement !== null ; ) {
403
+ this.#push(this.elements[ this.elements.length - 1].parentElement);
404
+ }
405
+
406
+ this.elements.splice(0,1); // Deleting initial element from the set
407
+
408
+ if( typeof filter !== 'undefined' ){
409
+ this.filter(filter);
410
+ }
411
+
412
+ return this;
413
+ }
414
+
415
+ children(filter){
416
+
417
+ this.select(this.elements[0].children);
418
+
419
+ if( typeof filter !== 'undefined' ){
420
+ this.filter(filter);
421
+ }
422
+
423
+ return this;
424
+ }
425
+
426
+ siblings(filter){
427
+
428
+ let current = this.elements[0]; // Remember current to delete it later
429
+
430
+ this.parent();
431
+ this.children(filter);
432
+ this.elements.splice(this.elements.indexOf(current), 1); // Remove current element
433
+
434
+ return this;
435
+ }
436
+
437
+ /************** DOM MANIPULATIONS **************/
438
+ remove(){
439
+ for(let elem of this.elements){
440
+ elem.remove();
441
+ }
442
+ }
443
+
444
+ after(content){
445
+ for(let elem of this.elements){
446
+ elem.after(content);
447
+ }
448
+ }
449
+
450
+ append(content){
451
+ for(let elem of this.elements){
452
+ elem.append(content);
453
+ }
454
+ }
455
+
456
+ /** ANIMATION **/
457
+ fadeIn(time) {
458
+ for(let elem of this.elements){
459
+ elem.style.opacity = 0;
460
+ elem.style.display = 'block';
461
+
462
+ let last = +new Date();
463
+ const tick = function () {
464
+ elem.style.opacity = +elem.style.opacity + (new Date() - last) / time;
465
+ last = +new Date();
466
+
467
+ if (+elem.style.opacity < 1) {
468
+ (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
469
+ }
470
+ };
471
+
472
+ tick();
473
+ }
474
+ }
475
+
476
+ fadeOut(time) {
477
+ for(let elem of this.elements){
478
+ elem.style.opacity = 1;
479
+
480
+ let last = +new Date();
481
+ const tick = function () {
482
+ elem.style.opacity = +elem.style.opacity - (new Date() - last) / time;
483
+ last = +new Date();
484
+
485
+ if (+elem.style.opacity > 0) {
486
+ (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
487
+ } else {
488
+ elem.style.display = 'none';
489
+ }
490
+ };
491
+
492
+ tick();
493
+ }
494
+ }
495
+
496
+ }
497
+
498
+ /**
499
+ * Hack
500
+ *
501
+ * Make a proxy to keep both properties and methods from:
502
+ * - the native object and
503
+ * - the new one from ApbctCore for selected element.
504
+ *
505
+ * For example:
506
+ * apbct('#id).innerHTML = 'some';
507
+ * apbct('#id).css({'backgorund-color': 'black'});
508
+ */
509
+ // apbct = new Proxy(
510
+ // apbct,
511
+ // {
512
+ // get(target, prop) {
513
+ // if (target.elements.length) {
514
+ // return target.elements[0][prop];
515
+ // } else {
516
+ // return null;
517
+ // }
518
+ // },
519
+ // set(target, prop, value){
520
+ // if (target.elements.length) {
521
+ // target.elements[0][prop] = value;
522
+ // return true;
523
+ // } else {
524
+ // return false;
525
+ // }
526
+ // },
527
+ // apply(target, thisArg, argArray) {
528
+ //
529
+ // }
530
+ // }
531
+ // );
532
+
533
+ /**
534
+ * Enter point to ApbctCore class
535
+ *
536
+ * @param params
537
+ * @returns {*}
538
+ */
539
+ function apbct(params){
540
+ return new ApbctCore()
541
+ .select(params);
542
+ }
543
+ class ApbctXhr{
544
+
545
+ #xhr = new XMLHttpRequest();
546
+
547
+ // Base parameters
548
+ method = 'POST'; // HTTP-request type
549
+ url = ''; // URL to send the request
550
+ async = true;
551
+ user = null; // HTTP-authorization username
552
+ password = null; // HTTP-authorization password
553
+ data = {}; // Data to send
554
+
555
+
556
+ // Optional params
557
+ button = null; // Button that should be disabled when request is performing
558
+ spinner = null; // Spinner that should appear when request is in process
559
+ progressbar = null; // Progress bar for the current request
560
+ context = this; // Context
561
+ callback = null;
562
+ onErrorCallback = null;
563
+
564
+ responseType = 'json'; // Expected data type from server
565
+ headers = {};
566
+ timeout = 15000; // Request timeout in milliseconds
567
+
568
+ #methods_to_convert_data_to_URL = [
569
+ 'GET',
570
+ 'HEAD',
571
+ ];
572
+
573
+ #body = null;
574
+ #http_code = 0;
575
+ #status_text = '';
576
+
577
+ constructor(parameters){
578
+
579
+ console.log('%cXHR%c started', 'color: red; font-weight: bold;', 'color: grey; font-weight: normal;');
580
+
581
+ // Set class properties
582
+ for( let key in parameters ){
583
+ if( typeof this[key] !== 'undefined' ){
584
+ this[key] = parameters[key];
585
+ }
586
+ }
587
+
588
+ // Modifying DOM-elements
589
+ this.#prepare();
590
+
591
+ // Modify URL with data for GET and HEAD requests
592
+ if ( Object.keys(this.data).length ) {
593
+ this.deleteDoubleJSONEncoding(this.data);
594
+ this.convertData();
595
+ }
596
+
597
+ if( ! this.url ){
598
+ console.log('%cXHR%c not URL provided', 'color: red; font-weight: bold;', 'color: grey; font-weight: normal;')
599
+ return false;
600
+ }
601
+
602
+ // Configure the request
603
+ this.#xhr.open(this.method, this.url, this.async, this.user, this.password);
604
+ this.setHeaders();
605
+
606
+ this.#xhr.responseType = this.responseType;
607
+ this.#xhr.timeout = this.timeout;
608
+
609
+ /* EVENTS */
610
+ // Monitoring status
611
+ this.#xhr.onreadystatechange = function(){
612
+ this.onReadyStateChange();
613
+ }.bind(this);
614
+
615
+ // Run callback
616
+ this.#xhr.onload = function(){
617
+ this.onLoad();
618
+ }.bind(this);
619
+
620
+ // On progress
621
+ this.#xhr.onprogress = function(event){
622
+ this.onProgress(event);
623
+ }.bind(this);
624
+
625
+ // On error
626
+ this.#xhr.onerror = function(){
627
+ this.onError();
628
+ }.bind(this);
629
+
630
+ this.#xhr.ontimeout = function(){
631
+ this.onTimeout();
632
+ }.bind(this);
633
+
634
+ // Send the request
635
+ this.#xhr.send(this.#body);
636
+ }
637
+
638
+ #prepare(){
639
+
640
+ // Disable button
641
+ if(this.button){
642
+ this.button.setAttribute('disabled', 'disabled');
643
+ this.button.style.cursor = 'not-allowed';
644
+ }
645
+
646
+ // Enable spinner
647
+ if(this.spinner) {
648
+ this.spinner.style.display = 'inline';
649
+ }
650
+ }
651
+
652
+ #complete(){
653
+
654
+ this.#http_code = this.#xhr.status;
655
+ this.#status_text = this.#xhr.statusText;
656
+
657
+ // Disable button
658
+ if(this.button){
659
+ this.button.removeAttribute('disabled');
660
+ this.button.style.cursor = 'auto';
661
+ }
662
+
663
+ // Enable spinner
664
+ if(this.spinner) {
665
+ this.spinner.style.display = 'none';
666
+ }
667
+
668
+ if( this.progressbar ) {
669
+ this.progressbar.fadeOut('slow');
670
+ }
671
+ }
672
+
673
+ onReadyStateChange(){
674
+ if (this.on_ready_state_change !== null && typeof this.on_ready_state_change === 'function'){
675
+ this.on_ready_state_change();
676
+ }
677
+ }
678
+
679
+ onProgress(event) {
680
+ if (this.on_progress !== null && typeof this.on_progress === 'function'){
681
+ this.on_progress();
682
+ }
683
+ }
684
+
685
+ onError(){
686
+
687
+ console.log('error');
688
+
689
+ this.#complete();
690
+ this.#error(
691
+ this.#http_code,
692
+ this.#status_text
693
+ );
694
+
695
+ if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function'){
696
+ this.onErrorCallback(this.#status_text);
697
+ }
698
+ }
699
+
700
+ onTimeout(){
701
+ this.#complete();
702
+ this.#error(
703
+ 0,
704
+ 'timeout'
705
+ );
706
+
707
+ if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function'){
708
+ this.onErrorCallback('Timeout');
709
+ }
710
+ }
711
+
712
+ onLoad(){
713
+
714
+ this.#complete();
715
+
716
+ if (this.responseType === 'json' ){
717
+ if(this.#xhr.response === null){
718
+ this.#error(this.#http_code, this.#status_text, 'No response');
719
+ return false;
720
+ }else if( typeof this.#xhr.response.error !== 'undefined') {
721
+ this.#error(this.#http_code, this.#status_text, this.#xhr.response.error);
722
+ return false;
723
+ }
724
+ }
725
+
726
+ if (this.callback !== null && typeof this.callback === 'function') {
727
+ this.callback.call(this.context, this.#xhr.response, this.data);
728
+ }
729
+ }
730
+
731
+ #error(http_code, status_text, additional_msg){
732
+
733
+ let error_string = '';
734
+
735
+ if( status_text === 'timeout' ){
736
+ error_string += 'Server response timeout'
737
+
738
+ }else if( http_code === 200 ){
739
+
740
+ if( status_text === 'parsererror' ){
741
+ error_string += 'Unexpected response from server. See console for details.';
742
+ }else {
743
+ error_string += 'Unexpected error. Status: ' + status_text + '.';
744
+ if( typeof additional_msg !== 'undefined' )
745
+ error_string += ' Additional error info: ' + additional_msg;
746
+ }
747
+
748
+ }else if(http_code === 500){
749
+ error_string += 'Internal server error.';
750
+
751
+ }else {
752
+ error_string += 'Unexpected response code:' + http_code;
753
+ }
754
+
755
+ this.errorOutput( error_string );
756
+ }
757
+
758
+ errorOutput(error_msg){
759
+ console.log( '%c ctXHR error: %c' + error_msg, 'color: red;', 'color: grey;' );
760
+ }
761
+
762
+ setHeaders(){
763
+ // Set headers if passed
764
+ for( let header_name in this.headers ){
765
+ if( typeof this.headers[header_name] !== 'undefined' ){
766
+ this.#xhr.setRequestHeader(header_name, this.headers[header_name]);
767
+ }
768
+ }
769
+ }
770
+
771
+ convertData()
772
+ {
773
+ // GET, HEAD request-type
774
+ if( ~this.#methods_to_convert_data_to_URL.indexOf( this.method ) ){
775
+ return this.convertDataToURL();
776
+
777
+ // POST request-type
778
+ }else{
779
+ return this.convertDataToBody()
780
+ }
781
+ }
782
+
783
+ convertDataToURL(){
784
+ let params_appendix = new URLSearchParams(this.data).toString();
785
+ let params_prefix = this.url.match(/^(https?:\/{2})?[a-z0-9.]+\?/) ? '&' : '?';
786
+ this.url += params_prefix + params_appendix;
787
+
788
+ return this.url;
789
+ }
790
+
791
+ /**
792
+ *
793
+ * @returns {null}
794
+ */
795
+ convertDataToBody()
796
+ {
797
+ this.#body = new FormData();
798
+
799
+ for (let dataKey in this.data) {
800
+ this.#body.append(
801
+ dataKey,
802
+ typeof this.data[dataKey] === 'object'
803
+ ? JSON.stringify(this.data[dataKey])
804
+ : this.data[dataKey]
805
+ );
806
+ }
807
+
808
+ return this.#body;
809
+ }
810
+
811
+ /**
812
+ * Recursive
813
+ *
814
+ * Recursively decode JSON-encoded properties
815
+ *
816
+ * @param object
817
+ * @returns {*}
818
+ */
819
+ deleteDoubleJSONEncoding(object){
820
+
821
+ if( typeof object === 'object'){
822
+
823
+ for (let objectKey in object) {
824
+
825
+ // Recursion
826
+ if( typeof object[objectKey] === 'object'){
827
+ object[objectKey] = this.deleteDoubleJSONEncoding(object[objectKey]);
828
+ }
829
+
830
+ // Common case (out)
831
+ if(
832
+ typeof object[objectKey] === 'string' &&
833
+ object[objectKey].match(/^[\[{].*?[\]}]$/) !== null // is like JSON
834
+ ){
835
+ let parsedValue = JSON.parse(object[objectKey]);
836
+ if( typeof parsedValue === 'object' ){
837
+ object[objectKey] = parsedValue;
838
+ }
839
+ }
840
+ }
841
+ }
842
+
843
+ return object;
844
+ }
845
+ }
846
+ class ApbctAjax extends ApbctXhr{
847
+
848
+ constructor(...args) {
849
+ super(args[0]);
850
+ }
851
+ }
852
+ class ApbctRest extends ApbctXhr{
853
+
854
+ static default_route = ctPublicFunctions._rest_url + 'cleantalk-antispam/v1/';
855
+ route = '';
856
+
857
+ constructor(...args) {
858
+ args = args[0];
859
+ args.url = ApbctRest.default_route + args.route;
860
+ args.headers = {
861
+ "X-WP-Nonce": ctPublicFunctions._rest_nonce
862
+ };
863
+ super(args);
864
+ }
865
+ }
js/src/apbct-public--1--functions.js ADDED
@@ -0,0 +1,187 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function ctSetCookie( cookies, value, expires ){
2
+
3
+ if( typeof cookies === 'string' && typeof value === 'string' || typeof value === 'number'){
4
+ var skip_alt = cookies === 'ct_pointer_data';
5
+ cookies = [ [ cookies, value, expires ] ];
6
+ }
7
+
8
+ // Cookies disabled
9
+ if( ctPublicFunctions.data__cookies_type === 'none' ){
10
+ cookies.forEach( function (item, i, arr ) {
11
+ apbctLocalStorage.set(item[0], encodeURIComponent(item[1]))
12
+ });
13
+ ctNoCookieAttachHiddenFieldsToForms()
14
+ // Using traditional cookies
15
+ }else if( ctPublicFunctions.data__cookies_type === 'native' ){
16
+ cookies.forEach( function (item, i, arr ) {
17
+ var expires = typeof item[2] !== 'undefined' ? "expires=" + expires + '; ' : '';
18
+ var ctSecure = location.protocol === 'https:' ? '; secure' : '';
19
+ document.cookie = ctPublicFunctions.cookiePrefix + item[0] + "=" + encodeURIComponent(item[1]) + "; " + expires + "path=/; samesite=lax" + ctSecure;
20
+ });
21
+
22
+ // Using alternative cookies
23
+ }else if( ctPublicFunctions.data__cookies_type === 'alternative' && ! skip_alt ){
24
+
25
+ if (typeof (getJavascriptClientData) === "function"){
26
+ //reprocess already gained cookies data
27
+ cookies = getJavascriptClientData(cookies);
28
+ } else {
29
+ console.log('APBCT ERROR: getJavascriptClientData() is not loaded')
30
+ }
31
+
32
+ try {
33
+ JSON.parse(cookies)
34
+ } catch (e){
35
+ console.log('APBCT ERROR: JSON parse error:' + e)
36
+ return
37
+ }
38
+
39
+ // Using REST API handler
40
+ if( ctPublicFunctions.data__ajax_type === 'rest' ){
41
+ apbct_public_sendREST(
42
+ 'alt_sessions',
43
+ {
44
+ method: 'POST',
45
+ data: { cookies: cookies }
46
+ }
47
+ );
48
+
49
+ // Using AJAX request and handler
50
+ } else if( ctPublicFunctions.data__ajax_type === 'admin_ajax' ) {
51
+ apbct_public_sendAJAX(
52
+ {
53
+ action: 'apbct_alt_session__save__AJAX',
54
+ cookies: cookies,
55
+ },
56
+ {
57
+ notJson: 1,
58
+ }
59
+ );
60
+ }
61
+ }
62
+ }
63
+
64
+ /**
65
+ * Get cookie by name
66
+ * @param name
67
+ * @returns {string|undefined}
68
+ */
69
+ function ctGetCookie(name) {
70
+ var matches = document.cookie.match(new RegExp(
71
+ "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
72
+ ));
73
+ return matches ? decodeURIComponent(matches[1]) : undefined;
74
+ }
75
+
76
+ function ctDeleteCookie(cookieName) {
77
+ // Cookies disabled
78
+ if( ctPublicFunctions.data__cookies_type === 'none' ){
79
+ return;
80
+
81
+ // Using traditional cookies
82
+ }else if( ctPublicFunctions.data__cookies_type === 'native' ){
83
+
84
+ var ctSecure = location.protocol === 'https:' ? '; secure' : '';
85
+ document.cookie = cookieName + "=\"\"; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; samesite=lax" + ctSecure;
86
+
87
+ // Using alternative cookies
88
+ }else if( ctPublicFunctions.data__cookies_type === 'alternative' ){
89
+ // @ToDo implement this logic
90
+ }
91
+ }
92
+
93
+ function apbct_public_sendAJAX(data, params, obj){
94
+
95
+ // Default params
96
+ let _params = [];
97
+ _params["callback"] = params.callback || null;
98
+ _params["onErrorCallback"] = params.onErrorCallback || null;
99
+ _params["callback_context"] = params.callback_context || null;
100
+ _params["callback_params"] = params.callback_params || null;
101
+ _params["async"] = params.async || true;
102
+ _params["notJson"] = params.notJson || null;
103
+ _params["timeout"] = params.timeout || 15000;
104
+ _params["obj"] = obj || null;
105
+ _params["button"] = params.button || null;
106
+ _params["progressbar"] = params.progressbar || null;
107
+ _params["silent"] = params.silent || null;
108
+ _params["no_nonce"] = params.no_nonce || null;
109
+ _params["data"] = data;
110
+ _params["url"] = ctPublicFunctions._ajax_url;
111
+
112
+ if(typeof (data) === 'string') {
113
+ if( ! _params["no_nonce"] ) {
114
+ _params["data"] = _params["data"] + '&_ajax_nonce=' + ctPublicFunctions._ajax_nonce;
115
+ }
116
+ _params["data"] = _params["data"] + '&no_cache=' + Math.random()
117
+ } else {
118
+ if( ! _params["no_nonce"] ) {
119
+ _params["data"]._ajax_nonce = ctPublicFunctions._ajax_nonce;
120
+ }
121
+ _params["data"].no_cache = Math.random();
122
+ }
123
+
124
+ new ApbctCore().ajax(_params);
125
+ }
126
+
127
+ function apbct_public_sendREST( route, params ) {
128
+
129
+ let _params = [];
130
+ _params["route"] = route;
131
+ _params["callback"] = params.callback || null;
132
+ _params["onErrorCallback"] = params.onErrorCallback || null;
133
+ _params["data"] = params.data || [];
134
+ _params["method"] = params.method || 'POST';
135
+
136
+ new ApbctCore().rest(_params);
137
+ }
138
+
139
+ apbctLocalStorage = {
140
+ get : function(key, property) {
141
+ if ( typeof property === 'undefined' ) {
142
+ property = 'value';
143
+ }
144
+ const storageValue = localStorage.getItem(key);
145
+ if ( storageValue !== null ) {
146
+ try {
147
+ const json = JSON.parse(storageValue);
148
+ return json.hasOwnProperty(property) ? JSON.parse(json[property]) : json;
149
+ } catch (e) {
150
+ return storageValue;
151
+ }
152
+ }
153
+ return false;
154
+ },
155
+ set : function(key, value, is_json = true) {
156
+ if (is_json){
157
+ let objToSave = {'value': JSON.stringify(value), 'timestamp': Math.floor(new Date().getTime() / 1000)};
158
+ localStorage.setItem(key, JSON.stringify(objToSave));
159
+ } else {
160
+ localStorage.setItem(key, value);
161
+ }
162
+ },
163
+ isAlive : function(key, maxLifetime) {
164
+ if ( typeof maxLifetime === 'undefined' ) {
165
+ maxLifetime = 86400;
166
+ }
167
+ const keyTimestamp = this.get(key, 'timestamp');
168
+ return keyTimestamp + maxLifetime > Math.floor(new Date().getTime() / 1000);
169
+ },
170
+ isSet : function(key) {
171
+ return localStorage.getItem(key) !== null;
172
+ },
173
+ delete : function (key) {
174
+ localStorage.removeItem(key);
175
+ },
176
+ getCleanTalkData : function () {
177
+ let data = {}
178
+ for(let i=0; i<localStorage.length; i++) {
179
+ let key = localStorage.key(i);
180
+ if (key.indexOf('ct_') !==-1 || key.indexOf('apbct_') !==-1){
181
+ data[key.toString()] = apbctLocalStorage.get(key)
182
+ }
183
+ }
184
+ return data
185
+ },
186
+
187
+ }
js/src/apbct-public--2--public.js ADDED
@@ -0,0 +1,789 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ var ct_date = new Date(),
2
+ ctTimeMs = new Date().getTime(),
3
+ ctMouseEventTimerFlag = true, //Reading interval flag
4
+ ctMouseData = [],
5
+ ctMouseDataCounter = 0,
6
+ ctCheckedEmails = {};
7
+
8
+ function apbct_attach_event_handler(elem, event, callback){
9
+ if(typeof window.addEventListener === "function") elem.addEventListener(event, callback);
10
+ else elem.attachEvent(event, callback);
11
+ }
12
+
13
+ function apbct_remove_event_handler(elem, event, callback){
14
+ if(typeof window.removeEventListener === "function") elem.removeEventListener(event, callback);
15
+ else elem.detachEvent(event, callback);
16
+ }
17
+
18
+ //Writing first key press timestamp
19
+ var ctFunctionFirstKey = function output(event){
20
+ var KeyTimestamp = Math.floor(new Date().getTime()/1000);
21
+ ctSetCookie("ct_fkp_timestamp", KeyTimestamp);
22
+ ctKeyStopStopListening();
23
+ };
24
+
25
+ //Reading interval
26
+ var ctMouseReadInterval = setInterval(function(){
27
+ ctMouseEventTimerFlag = true;
28
+ }, 150);
29
+
30
+ //Writting interval
31
+ var ctMouseWriteDataInterval = setInterval(function(){
32
+ ctSetCookie("ct_pointer_data", JSON.stringify(ctMouseData));
33
+ }, 1200);
34
+
35
+ //Logging mouse position each 150 ms
36
+ var ctFunctionMouseMove = function output(event){
37
+ ctSetMouseMoved();
38
+ if(ctMouseEventTimerFlag === true){
39
+
40
+ ctMouseData.push([
41
+ Math.round(event.clientY),
42
+ Math.round(event.clientX),
43
+ Math.round(new Date().getTime() - ctTimeMs)
44
+ ]);
45
+
46
+ ctMouseDataCounter++;
47
+ ctMouseEventTimerFlag = false;
48
+ if(ctMouseDataCounter >= 50){
49
+ ctMouseStopData();
50
+ }
51
+ }
52
+ };
53
+
54
+ //Stop mouse observing function
55
+ function ctMouseStopData(){
56
+ apbct_remove_event_handler(window, "mousemove", ctFunctionMouseMove);
57
+ clearInterval(ctMouseReadInterval);
58
+ clearInterval(ctMouseWriteDataInterval);
59
+ }
60
+
61
+ //Stop key listening function
62
+ function ctKeyStopStopListening(){
63
+ apbct_remove_event_handler(window, "mousedown", ctFunctionFirstKey);
64
+ apbct_remove_event_handler(window, "keydown", ctFunctionFirstKey);
65
+ }
66
+
67
+ function checkEmail(e) {
68
+ var current_email = e.target.value;
69
+ if (current_email && !(current_email in ctCheckedEmails)) {
70
+ // Using REST API handler
71
+ if( ctPublicFunctions.data__ajax_type === 'rest' ){
72
+ apbct_public_sendREST(
73
+ 'check_email_before_post',
74
+ {
75
+ method: 'POST',
76
+ data: {'email' : current_email},
77
+ callback: function (result) {
78
+ if (result.result) {
79
+ ctCheckedEmails[current_email] = {'result' : result.result, 'timestamp': Date.now() / 1000 |0};
80
+ ctSetCookie('ct_checked_emails', JSON.stringify(ctCheckedEmails));
81
+ }
82
+ },
83
+ }
84
+ );
85
+ // Using AJAX request and handler
86
+ } else if( ctPublicFunctions.data__ajax_type === 'admin_ajax' ) {
87
+ apbct_public_sendAJAX(
88
+ {
89
+ action: 'apbct_email_check_before_post',
90
+ email : current_email,
91
+ },
92
+ {
93
+ callback: function (result) {
94
+ if (result.result) {
95
+ ctCheckedEmails[current_email] = {'result' : result.result, 'timestamp': Date.now() / 1000 |0};
96
+ ctSetCookie('ct_checked_emails', JSON.stringify(ctCheckedEmails));
97
+ }
98
+ },
99
+ }
100
+ );
101
+ }
102
+ }
103
+ }
104
+
105
+ function ctSetPixelImg(pixelUrl) {
106
+ ctSetCookie('apbct_pixel_url', pixelUrl);
107
+ if( +ctPublic.pixel__enabled ){
108
+ if( ! document.getElementById('apbct_pixel') ) {
109
+ let insertedImg = document.createElement('img');
110
+ insertedImg.setAttribute('alt', 'CleanTalk Pixel');
111
+ insertedImg.setAttribute('id', 'apbct_pixel');
112
+ insertedImg.setAttribute('style', 'display: none; left: 99999px;');
113
+ insertedImg.setAttribute('src', pixelUrl);
114
+ apbct('body').append(insertedImg);
115
+ }
116
+ }
117
+ }
118
+
119
+ function ctGetPixelUrl() {
120
+ // Check if pixel is already in localstorage and is not outdated
121
+ let local_storage_pixel_url = apbctLocalStorage.get('apbct_pixel_url');
122
+ if ( local_storage_pixel_url !== false ) {
123
+ if ( apbctLocalStorage.isAlive('apbct_pixel_url', 3600 * 3) ) {
124
+ apbctLocalStorage.delete('apbct_pixel_url')
125
+ } else {
126
+ //if so - load pixel from localstorage and draw it skipping AJAX
127
+ ctSetPixelImg(local_storage_pixel_url);
128
+ return;
129
+ }
130
+ }
131
+ // Using REST API handler
132
+ if( ctPublicFunctions.data__ajax_type === 'rest' ){
133
+ apbct_public_sendREST(
134
+ 'apbct_get_pixel_url',
135
+ {
136
+ method: 'POST',
137
+ callback: function (result) {
138
+ if (result) {
139
+ //set pixel url to localstorage
140
+ if ( ! apbctLocalStorage.get('apbct_pixel_url') ){
141
+ //set pixel to the storage
142
+ apbctLocalStorage.set('apbct_pixel_url', result)
143
+ //update pixel data in the hidden fields
144
+ ctNoCookieAttachHiddenFieldsToForms()
145
+ }
146
+ //then run pixel drawing
147
+ ctSetPixelImg(result);
148
+ }
149
+ },
150
+ }
151
+ );
152
+ // Using AJAX request and handler
153
+ }else{
154
+ apbct_public_sendAJAX(
155
+ {
156
+ action: 'apbct_get_pixel_url',
157
+ },
158
+ {
159
+ notJson: true,
160
+ callback: function (result) {
161
+ if (result) {
162
+ //set pixel url to localstorage
163
+ if ( ! apbctLocalStorage.get('apbct_pixel_url') ){
164
+ //set pixel to the storage
165
+ apbctLocalStorage.set('apbct_pixel_url', result)
166
+ //update pixel data in the hidden fields
167
+ ctNoCookieAttachHiddenFieldsToForms()
168
+ }
169
+ //then run pixel drawing
170
+ ctSetPixelImg(result);
171
+ }
172
+ },
173
+ }
174
+ );
175
+ }
176
+ }
177
+
178
+ function ctSetHasScrolled() {
179
+ if( ! apbctLocalStorage.isSet('ct_has_scrolled') || ! apbctLocalStorage.get('ct_has_scrolled') ) {
180
+ ctSetCookie("ct_has_scrolled", 'true');
181
+ apbctLocalStorage.set('ct_has_scrolled', true);
182
+ }
183
+ }
184
+
185
+ function ctSetMouseMoved() {
186
+ if( ! apbctLocalStorage.isSet('ct_mouse_moved') || ! apbctLocalStorage.get('ct_mouse_moved') ) {
187
+ ctSetCookie("ct_mouse_moved", 'true');
188
+ apbctLocalStorage.set('ct_mouse_moved', true);
189
+ }
190
+ }
191
+
192
+ function ctPreloadLocalStorage(){
193
+ if (ctPublic.data__to_local_storage){
194
+ let data = Object.entries(ctPublic.data__to_local_storage)
195
+ data.forEach(([key, value]) => {
196
+ apbctLocalStorage.set(key,value)
197
+ });
198
+ }
199
+ }
200
+
201
+ apbct_attach_event_handler(window, "mousemove", ctFunctionMouseMove);
202
+ apbct_attach_event_handler(window, "mousedown", ctFunctionFirstKey);
203
+ apbct_attach_event_handler(window, "keydown", ctFunctionFirstKey);
204
+ apbct_attach_event_handler(window, "scroll", ctSetHasScrolled);
205
+
206
+ // Ready function
207
+ function apbct_ready(){
208
+
209
+ ctPreloadLocalStorage()
210
+
211
+ let cookiesType = apbctLocalStorage.get('ct_cookies_type');
212
+ if ( ! cookiesType || cookiesType !== ctPublic.data__cookies_type ) {
213
+ apbctLocalStorage.set('ct_cookies_type', ctPublic.data__cookies_type);
214
+ apbctLocalStorage.delete('ct_mouse_moved');
215
+ apbctLocalStorage.delete('ct_has_scrolled');
216
+ }
217
+
218
+ // Collect scrolling info
219
+ var initCookies = [
220
+ ["ct_ps_timestamp", Math.floor(new Date().getTime() / 1000)],
221
+ ["ct_fkp_timestamp", "0"],
222
+ ["ct_pointer_data", "0"],
223
+ ["ct_timezone", ct_date.getTimezoneOffset()/60*(-1) ],
224
+ ["ct_screen_info", apbctGetScreenInfo()],
225
+ ["apbct_headless", navigator.webdriver],
226
+ ];
227
+
228
+ apbctLocalStorage.set('ct_ps_timestamp', Math.floor(new Date().getTime() / 1000));
229
+ apbctLocalStorage.set('ct_fkp_timestamp', "0");
230
+ apbctLocalStorage.set('ct_pointer_data', "0");
231
+ apbctLocalStorage.set('ct_timezone', ct_date.getTimezoneOffset()/60*(-1) );
232
+ apbctLocalStorage.set('ct_screen_info', apbctGetScreenInfo());
233
+ apbctLocalStorage.set('apbct_headless', navigator.webdriver);
234
+
235
+ if( ctPublic.data__cookies_type !== 'native' ) {
236
+ initCookies.push(['apbct_visible_fields', '0']);
237
+ } else {
238
+ // Delete all visible fields cookies on load the page
239
+ var cookiesArray = document.cookie.split(";");
240
+ if( cookiesArray.length !== 0 ) {
241
+ for ( var i = 0; i < cookiesArray.length; i++ ) {
242
+ var currentCookie = cookiesArray[i].trim();
243
+ var cookieName = currentCookie.split("=")[0];
244
+ if( cookieName.indexOf("apbct_visible_fields_") === 0 ) {
245
+ ctDeleteCookie(cookieName);
246
+ }
247
+ }
248
+ }
249
+ }
250
+
251
+ if( +ctPublic.pixel__setting ){
252
+ if( +ctPublic.pixel__enabled ){
253
+ ctGetPixelUrl()
254
+ } else {
255
+ initCookies.push(['apbct_pixel_url', ctPublic.pixel__url]);
256
+ }
257
+ }
258
+
259
+ if ( +ctPublic.data__email_check_before_post) {
260
+ initCookies.push(['ct_checked_emails', '0']);
261
+ apbct("input[type = 'email'], #email").on('blur', checkEmail);
262
+ }
263
+
264
+ if (apbctLocalStorage.isSet('ct_checkjs')) {
265
+ initCookies.push(['ct_checkjs', apbctLocalStorage.get('ct_checkjs')]);
266
+ } else {
267
+ initCookies.push(['ct_checkjs', 0]);
268
+ }
269
+
270
+ ctSetCookie(initCookies);
271
+
272
+ setTimeout(function(){
273
+
274
+ ctNoCookieAttachHiddenFieldsToForms()
275
+
276
+ for(var i = 0; i < document.forms.length; i++){
277
+ var form = document.forms[i];
278
+
279
+ //Exclusion for forms
280
+ if (
281
+ +ctPublic.data__visible_fields_required === 0 ||
282
+ form.method.toString().toLowerCase() === 'get' ||
283
+ form.classList.contains('slp_search_form') || //StoreLocatorPlus form
284
+ form.parentElement.classList.contains('mec-booking') ||
285
+ form.action.toString().indexOf('activehosted.com') !== -1 || // Active Campaign
286
+ (form.id && form.id === 'caspioform') || //Caspio Form
287
+ (form.classList && form.classList.contains('tinkoffPayRow')) || // TinkoffPayForm
288
+ (form.classList && form.classList.contains('give-form')) || // GiveWP
289
+ (form.id && form.id === 'ult-forgot-password-form') || //ult forgot password
290
+ (form.id && form.id.toString().indexOf('calculatedfields') !== -1) || // CalculatedFieldsForm
291
+ (form.id && form.id.toString().indexOf('sac-form') !== -1) || // Simple Ajax Chat
292
+ (form.id && form.id.toString().indexOf('cp_tslotsbooking_pform') !== -1) || // WP Time Slots Booking Form
293
+ (form.name && form.name.toString().indexOf('cp_tslotsbooking_pform') !== -1) || // WP Time Slots Booking Form
294
+ form.action.toString() === 'https://epayment.epymtservice.com/epay.jhtml' || // Custom form
295
+ (form.name && form.name.toString().indexOf('tribe-bar-form') !== -1) // The Events Calendar
296
+ ) {
297
+ continue;
298
+ }
299
+
300
+ var hiddenInput = document.createElement( 'input' );
301
+ hiddenInput.setAttribute( 'type', 'hidden' );
302
+ hiddenInput.setAttribute( 'id', 'apbct_visible_fields_' + i );
303
+ hiddenInput.setAttribute( 'name', 'apbct_visible_fields');
304
+ var visibleFieldsToInput = {};
305
+ visibleFieldsToInput[0] = apbct_collect_visible_fields(form);
306
+ hiddenInput.value = JSON.stringify(visibleFieldsToInput);
307
+ form.append( hiddenInput );
308
+
309
+ form.onsubmit_prev = form.onsubmit;
310
+
311
+ form.ctFormIndex = i;
312
+ form.onsubmit = function (event) {
313
+
314
+ if ( ctPublic.data__cookies_type !== 'native' && typeof event.target.ctFormIndex !== 'undefined' ) {
315
+
316
+ var visible_fields = {};
317
+ visible_fields[0] = apbct_collect_visible_fields(this);
318
+ console.log("visible_fields[0]" + visible_fields[0])
319
+ apbct_visible_fields_set_cookie( visible_fields, event.target.ctFormIndex );
320
+ }
321
+
322
+ // Call previous submit action
323
+ if (event.target.onsubmit_prev instanceof Function) {
324
+ setTimeout(function () {
325
+ event.target.onsubmit_prev.call(event.target, event);
326
+ }, 500);
327
+ }
328
+ };
329
+ }
330
+
331
+ }, 1000);
332
+
333
+ // Listen clicks on encoded emails
334
+ let decodedEmailNodes = document.querySelectorAll("[data-original-string]");
335
+ if (decodedEmailNodes.length) {
336
+ for (let i = 0; i < decodedEmailNodes.length; ++i) {
337
+ if (
338
+ decodedEmailNodes[i].parentElement.href ||
339
+ decodedEmailNodes[i].parentElement.parentElement.href
340
+ ) {
341
+ // Skip listening click on hyperlinks
342
+ continue;
343
+ }
344
+ decodedEmailNodes[i].addEventListener('click', ctFillDecodedEmailHandler);
345
+ }
346
+ }
347
+ }
348
+ apbct_attach_event_handler(window, "DOMContentLoaded", apbct_ready);
349
+
350
+ function ctFillDecodedEmailHandler(event) {
351
+ this.removeEventListener('click', ctFillDecodedEmailHandler);
352
+ apbctAjaxEmailDecode(event, this);
353
+ }
354
+
355
+ function apbctAjaxEmailDecode(event, baseElement){
356
+ const element = event.target;
357
+ const javascriptClientData = getJavascriptClientData();
358
+ let data = {
359
+ event_javascript_data: javascriptClientData,
360
+ post_url: document.location.href,
361
+ referrer: document.referrer,
362
+ };
363
+
364
+ if (typeof baseElement.href !== 'undefined' && baseElement.href.indexOf('mailto:') === 0) {
365
+ event.preventDefault();
366
+ } else {
367
+ element.setAttribute('title', ctPublicFunctions.text__wait_for_decoding);
368
+ element.style.cursor = 'progress';
369
+
370
+ // Adding a tooltip
371
+ let apbctTooltip = document.createElement('div');
372
+ apbctTooltip.setAttribute('class', 'apbct-tooltip');
373
+ let apbctTooltipText = document.createElement('div');
374
+ apbctTooltipText.setAttribute('class', 'apbct-tooltip--text');
375
+ let apbctTooltipArrow = document.createElement('div');
376
+ apbctTooltipArrow.setAttribute('class', 'apbct-tooltip--arrow');
377
+ apbct(element).append(apbctTooltip);
378
+ apbct(apbctTooltip).append(apbctTooltipText);
379
+ apbct(apbctTooltip).append(apbctTooltipArrow);
380
+ ctShowDecodeComment(element, ctPublicFunctions.text__wait_for_decoding);
381
+ }
382
+
383
+ let encodedEmail = event.target.dataset.originalString;
384
+
385
+ if (typeof baseElement.href !== 'undefined' && baseElement.href.indexOf('mailto:') === 0) {
386
+ encodedEmail = baseElement.dataset.originalString;
387
+ }
388
+
389
+ data.encodedEmail = encodedEmail;
390
+
391
+ // Using REST API handler
392
+ if( ctPublicFunctions.data__ajax_type === 'rest' ){
393
+ apbct_public_sendREST(
394
+ 'apbct_decode_email',
395
+ {
396
+ data: data,
397
+ method: 'POST',
398
+ callback: function (result) {
399
+ if (result.success) {
400
+ if (typeof baseElement.href !== 'undefined' && baseElement.href.indexOf('mailto:') === 0) {
401
+ let encodedEmail = baseElement.href.replace('mailto:', '');
402
+ let baseElementContent = baseElement.innerHTML;
403
+ baseElement.innerHTML = baseElementContent.replace(encodedEmail, result.data.decoded_email);
404
+ baseElement.href = 'mailto:' + result.data.decoded_email;
405
+ baseElement.click();
406
+ } else {
407
+ setTimeout(function(){
408
+ ctProcessDecodedDataResult(result.data, event.target);
409
+ }, 3000);
410
+ }
411
+ }
412
+ setTimeout(function () {
413
+ apbct(element.getElementsByClassName('apbct-tooltip')).fadeOut(700);
414
+ }, 4000);
415
+ },
416
+ onErrorCallback: function (res) {
417
+ element.addEventListener('click', ctFillDecodedEmailHandler);
418
+ element.removeAttribute('style');
419
+ ctShowDecodeComment(element, 'Error occurred: ' + res);
420
+ },
421
+ }
422
+ );
423
+
424
+ // Using AJAX request and handler
425
+ }else{
426
+ data.action = 'apbct_decode_email';
427
+ apbct_public_sendAJAX(
428
+ data,
429
+ {
430
+ notJson: true,
431
+ callback: function (result) {
432
+ if (result.success) {
433
+ if (typeof baseElement.href !== 'undefined' && baseElement.href.indexOf('mailto:') === 0) {
434
+ let encodedEmail = baseElement.href.replace('mailto:', '');
435
+ let baseElementContent = baseElement.innerHTML;
436
+ baseElement.innerHTML = baseElementContent.replace(encodedEmail, result.data.decoded_email);
437
+ baseElement.href = 'mailto:' + result.data.decoded_email;
438
+ baseElement.click();
439
+ } else {
440
+ setTimeout(function(){
441
+ ctProcessDecodedDataResult(result.data, event.target);
442
+ }, 3000);
443
+ }
444
+ }
445
+ setTimeout(function () {
446
+ apbct(element.getElementsByClassName('apbct-tooltip')).fadeOut(700);
447
+ }, 4000);
448
+ },
449
+ onErrorCallback: function (res) {
450
+ element.addEventListener('click', ctFillDecodedEmailHandler);
451
+ element.removeAttribute('style');
452
+ ctShowDecodeComment(element, 'Error occurred: ' + res);
453
+ },
454
+ }
455
+ );
456
+ }
457
+ }
458
+
459
+ function getJavascriptClientData(common_cookies = []) {
460
+ let resultDataJson = {};
461
+
462
+ resultDataJson.apbct_headless = ctGetCookie(ctPublicFunctions.cookiePrefix + 'apbct_headless');
463
+ resultDataJson.apbct_pixel_url = ctGetCookie(ctPublicFunctions.cookiePrefix + 'apbct_pixel_url');
464
+ resultDataJson.ct_checked_emails = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_checked_emails');
465
+ resultDataJson.ct_checkjs = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_checkjs');
466
+ resultDataJson.ct_fkp_timestamp = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_fkp_timestamp');
467
+ resultDataJson.ct_pointer_data = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_pointer_data');
468
+ resultDataJson.ct_ps_timestamp = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_ps_timestamp');
469
+ resultDataJson.ct_screen_info = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_screen_info');
470
+ resultDataJson.ct_timezone = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_timezone');
471
+
472
+ // collecting data from localstorage
473
+ const ctMouseMovedLocalStorage = apbctLocalStorage.get(ctPublicFunctions.cookiePrefix + 'ct_mouse_moved');
474
+ const ctHasScrolledLocalStorage = apbctLocalStorage.get(ctPublicFunctions.cookiePrefix + 'ct_has_scrolled');
475
+ const ctCookiesTypeLocalStorage = apbctLocalStorage.get(ctPublicFunctions.cookiePrefix + 'ct_cookies_type');
476
+
477
+ // collecting data from cookies
478
+ const ctMouseMovedCookie = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_mouse_moved');
479
+ const ctHasScrolledCookie = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_has_scrolled');
480
+ const ctCookiesTypeCookie = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_cookies_type');
481
+
482
+ resultDataJson.ct_mouse_moved = ctMouseMovedLocalStorage !== undefined ? ctMouseMovedLocalStorage : ctMouseMovedCookie;
483
+ resultDataJson.ct_has_scrolled = ctHasScrolledLocalStorage !== undefined ? ctHasScrolledLocalStorage : ctHasScrolledCookie;
484
+ resultDataJson.ct_cookies_type = ctCookiesTypeLocalStorage !== undefined ? ctCookiesTypeLocalStorage : ctCookiesTypeCookie;
485
+
486
+ if (
487
+ typeof (common_cookies) === "object"
488
+ && common_cookies !== []
489
+ ){
490
+ for (let i = 0; i < common_cookies.length; ++i){
491
+ if ( typeof (common_cookies[i][1]) === "object" ){
492
+ //this is for handle SFW cookies
493
+ resultDataJson[common_cookies[i][1][0]] = common_cookies[i][1][1]
494
+ } else {
495
+ resultDataJson[common_cookies[i][0]] = common_cookies[i][1]
496
+ }
497
+ }
498
+ } else {
499
+ console.log('APBCT JS ERROR: Collecting data type mismatch')
500
+ }
501
+
502
+ // Parse JSON properties to prevent double JSON encoding
503
+ resultDataJson = removeDoubleJsonEncoding(resultDataJson);
504
+
505
+ return JSON.stringify(resultDataJson);
506
+ }
507
+
508
+ /**
509
+ * Recursive
510
+ *
511
+ * Recursively decode JSON-encoded properties
512
+ *
513
+ * @param object
514
+ * @returns {*}
515
+ */
516
+ function removeDoubleJsonEncoding(object){
517
+
518
+ if( typeof object === 'object'){
519
+
520
+ for (let objectKey in object) {
521
+
522
+ // Recursion
523
+ if( typeof object[objectKey] === 'object'){
524
+ object[objectKey] = removeDoubleJsonEncoding(object[objectKey]);
525
+ }
526
+
527
+ // Common case (out)
528
+ if(
529
+ typeof object[objectKey] === 'string' &&
530
+ object[objectKey].match(/^[\[{].*?[\]}]$/) !== null // is like JSON
531
+ ){
532
+ let parsedValue = JSON.parse(object[objectKey]);
533
+ if( typeof parsedValue === 'object' ){
534
+ object[objectKey] = parsedValue;
535
+ }
536
+ }
537
+ }
538
+ }
539
+
540
+ return object;
541
+ }
542
+
543
+ function ctProcessDecodedDataResult(response, targetElement) {
544
+
545
+ targetElement.setAttribute('title', '');
546
+ targetElement.removeAttribute('style');
547
+
548
+ if( !! response.is_allowed) {
549
+ ctFillDecodedEmail(targetElement, response.decoded_email);
550
+ }
551
+
552
+ if( !! response.show_comment ){
553
+ ctShowDecodeComment(targetElement, response.comment);
554
+ }
555
+ }
556
+
557
+ function ctFillDecodedEmail(target, email){
558
+ apbct(target).html(
559
+ apbct(target)
560
+ .html()
561
+ .replace(/.+?(<div class=["']apbct-tooltip["'].+?<\/div>)/, email + "$1")
562
+ );
563
+ }
564
+
565
+ function ctShowDecodeComment(target, comment){
566
+
567
+ if( ! comment ){
568
+ return;
569
+ }
570
+
571
+ apbct(target.getElementsByClassName('apbct-tooltip')).fadeIn(300);
572
+ apbct(target.getElementsByClassName('apbct-tooltip--text')).html(comment);
573
+ setTimeout(function(){
574
+ apbct(target.getElementsByClassName('apbct-tooltip')).fadeOut(700);
575
+ }, 5000);
576
+ }
577
+
578
+ function apbct_collect_visible_fields( form ) {
579
+
580
+ // Get only fields
581
+ var inputs = [],
582
+ inputs_visible = '',
583
+ inputs_visible_count = 0,
584
+ inputs_invisible = '',
585
+ inputs_invisible_count = 0,
586
+ inputs_with_duplicate_names = [];
587
+
588
+ for(var key in form.elements){
589
+ if(!isNaN(+key))
590
+ inputs[key] = form.elements[key];
591
+ }
592
+
593
+ // Filter fields
594
+ inputs = inputs.filter(function(elem){
595
+
596
+ // Filter already added fields
597
+ if( inputs_with_duplicate_names.indexOf( elem.getAttribute('name') ) !== -1 ){
598
+ return false;
599
+ }
600
+ // Filter inputs with same names for type == radio
601
+ if( -1 !== ['radio', 'checkbox'].indexOf( elem.getAttribute("type") )){
602
+ inputs_with_duplicate_names.push( elem.getAttribute('name') );
603
+ return false;
604
+ }
605
+ return true;
606
+ });
607
+
608
+ // Visible fields
609
+ inputs.forEach(function(elem, i, elements){
610
+ // Unnecessary fields
611
+ if(
612
+ elem.getAttribute("type") === "submit" || // type == submit
613
+ elem.getAttribute('name') === null ||
614
+ elem.getAttribute('name') === 'ct_checkjs'
615
+ ) {
616
+ return;
617
+ }
618
+ // Invisible fields
619
+ if(
620
+ getComputedStyle(elem).display === "none" || // hidden
621
+ getComputedStyle(elem).visibility === "hidden" || // hidden
622
+ getComputedStyle(elem).opacity === "0" || // hidden
623
+ elem.getAttribute("type") === "hidden" // type == hidden
624
+ ) {
625
+ if( elem.classList.contains("wp-editor-area") ) {
626
+ inputs_visible += " " + elem.getAttribute("name");
627
+ inputs_visible_count++;
628
+ } else {
629
+ inputs_invisible += " " + elem.getAttribute("name");
630
+ inputs_invisible_count++;
631
+ }
632
+ }
633
+ // Visible fields
634
+ else {
635
+ inputs_visible += " " + elem.getAttribute("name");
636
+ inputs_visible_count++;
637
+ }
638
+
639
+ });
640
+
641
+ inputs_invisible = inputs_invisible.trim();
642
+ inputs_visible = inputs_visible.trim();
643
+
644
+ return {
645
+ visible_fields : inputs_visible,
646
+ visible_fields_count : inputs_visible_count,
647
+ invisible_fields : inputs_invisible,
648
+ invisible_fields_count : inputs_invisible_count,
649
+ }
650
+
651
+ }
652
+
653
+ function apbct_visible_fields_set_cookie( visible_fields_collection, form_id ) {
654
+
655
+ var collection = typeof visible_fields_collection === 'object' && visible_fields_collection !== null ? visible_fields_collection : {};
656
+
657
+ if( ctPublic.data__cookies_type === 'native' ) {
658
+ for ( var i in collection ) {
659
+ if ( i > 10 ) {
660
+ // Do not generate more than 10 cookies
661
+ return;
662
+ }
663
+ var collectionIndex = form_id !== undefined ? form_id : i;
664
+ ctSetCookie("apbct_visible_fields_" + collectionIndex, JSON.stringify( collection[i] ) );
665
+ }
666
+ } else {
667
+ if (ctPublic.data__cookies_type === 'none'){
668
+ ctSetCookie("apbct_visible_fields", JSON.stringify( collection[0] ) );
669
+ } else {
670
+ ctSetCookie("apbct_visible_fields", JSON.stringify( collection ) );
671
+ }
672
+
673
+ }
674
+ }
675
+
676
+ function apbct_js_keys__set_input_value(result, data, params, obj){
677
+ if( document.querySelectorAll('[name^=ct_checkjs]').length > 0 ) {
678
+ var elements = document.querySelectorAll('[name^=ct_checkjs]');
679
+ for ( var i = 0; i < elements.length; i++ ) {
680
+ elements[i].value = result.js_key;
681
+ }
682
+ }
683
+ }
684
+
685
+ function apbctGetScreenInfo() {
686
+ return JSON.stringify({
687
+ fullWidth : document.documentElement.scrollWidth,
688
+ fullHeight : Math.max(
689
+ document.body.scrollHeight, document.documentElement.scrollHeight,
690
+ document.body.offsetHeight, document.documentElement.offsetHeight,
691
+ document.body.clientHeight, document.documentElement.clientHeight
692
+ ),
693
+ visibleWidth : document.documentElement.clientWidth,
694
+ visibleHeight : document.documentElement.clientHeight,
695
+ });
696
+ }
697
+
698
+ if(typeof jQuery !== 'undefined') {
699
+
700
+ // Capturing responses and output block message for unknown AJAX forms
701
+ jQuery(document).ajaxComplete(function (event, xhr, settings) {
702
+ if (xhr.responseText && xhr.responseText.indexOf('"apbct') !== -1) {
703
+ try {
704
+ var response = JSON.parse(responseText);
705
+ } catch (e) {
706
+ console.log(e.toString());
707
+ return;
708
+ }
709
+ ctParseBlockMessage(response);
710
+ }
711
+ });
712
+ }
713
+
714
+ function ctParseBlockMessage(response) {
715
+
716
+ if (typeof response.apbct !== 'undefined') {
717
+ response = response.apbct;
718
+ if (response.blocked) {
719
+ document.dispatchEvent(
720
+ new CustomEvent( "apbctAjaxBockAlert", {
721
+ bubbles: true,
722
+ detail: { message: response.comment }
723
+ } )
724
+ );
725
+
726
+ // Show the result by modal
727
+ cleantalkModal.loaded = response.comment;
728
+ cleantalkModal.open();
729
+
730
+ if(+response.stop_script == 1)
731
+ window.stop();
732
+ }
733
+ }
734
+ }
735
+
736
+ function ctSetPixelUrlLocalstorage(ajax_pixel_url) {
737
+ //set pixel to the storage
738
+ ctSetCookie('apbct_pixel_url', ajax_pixel_url)
739
+ }
740
+
741
+ function ctNoCookieConstructHiddenField(){
742
+ let field = ''
743
+ let no_cookie_data = apbctLocalStorage.getCleanTalkData()
744
+ no_cookie_data = JSON.stringify(no_cookie_data)
745
+ no_cookie_data = btoa(no_cookie_data)
746
+ field = document.createElement('input')
747
+ field.setAttribute('id','ct_no_cookie_hidden_field')
748
+ field.setAttribute('name','ct_no_cookie_hidden_field')
749
+ field.setAttribute('value', no_cookie_data)
750
+ field.setAttribute('type', 'hidden')
751
+ return field
752
+ }
753
+
754
+ function ctNoCookieGetForms(){
755
+ let forms = document.forms
756
+ if (forms) {
757
+ return forms
758
+ }
759
+ return false
760
+ }
761
+
762
+ function ctNoCookieAttachHiddenFieldsToForms(){
763
+
764
+ if (ctPublic.data__cookies_type !== 'none'){
765
+ return
766
+ }
767
+
768
+ let forms = ctNoCookieGetForms()
769
+
770
+ if (forms){
771
+ for ( let i = 0; i < forms.length; i++ ){
772
+ //ignore forms with get method @todo We need to think about this
773
+ if (document.forms[i].getAttribute('method') === null ||
774
+ document.forms[i].getAttribute('method').toLowerCase() === 'post'){
775
+
776
+ let elements = document.getElementsByName('ct_no_cookie_hidden_field')
777
+ //clear previous hidden set
778
+ if (elements){
779
+ for (let j = 0; j < elements.length; j++) {
780
+ elements[j].parentNode.removeChild(elements[j])
781
+ }
782
+ }
783
+ // add new set
784
+ document.forms[i].append(ctNoCookieConstructHiddenField())
785
+ }
786
+ }
787
+ }
788
+
789
+ }
js/src/apbct-public--3--cleantalk-modal.js ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* Cleantalk Modal object */
2
+ cleantalkModal = {
3
+
4
+ // Flags
5
+ loaded: false,
6
+ loading: false,
7
+ opened: false,
8
+ opening: false,
9
+
10
+ // Methods
11
+ load: function( action ) {
12
+ if( ! this.loaded ) {
13
+ this.loading = true;
14
+ callback = function( result, data, params, obj ) {
15
+ cleantalkModal.loading = false;
16
+ cleantalkModal.loaded = result;
17
+ document.dispatchEvent(
18
+ new CustomEvent( "cleantalkModalContentLoaded", {
19
+ bubbles: true,
20
+ } )
21
+ );
22
+ };
23
+ if( typeof apbct_admin_sendAJAX === "function" ) {
24
+ apbct_admin_sendAJAX( { 'action' : action }, { 'callback': callback, 'notJson': true } );
25
+ } else {
26
+ apbct_public_sendAJAX( { 'action' : action }, { 'callback': callback, 'notJson': true } );
27
+ }
28
+
29
+ }
30
+ },
31
+
32
+ open: function () {
33
+ /* Cleantalk Modal CSS start */
34
+ var renderCss = function () {
35
+ var cssStr = '';
36
+ for ( key in this.styles ) {
37
+ cssStr += key + ':' + this.styles[key] + ';';
38
+ }
39
+ return cssStr;
40
+ };
41
+ var overlayCss = {
42
+ styles: {
43
+ "z-index": "9999",
44
+ "position": "fixed",
45
+ "top": "0",
46
+ "left": "0",
47
+ "width": "100%",
48
+ "height": "100%",
49
+ "background": "rgba(0,0,0,0.5)",
50
+ "display": "flex",
51
+ "justify-content" : "center",
52
+ "align-items" : "center",
53
+ },
54
+ toString: renderCss
55
+ };
56
+ var innerCss = {
57
+ styles: {
58
+ "position" : "relative",
59
+ "padding" : "30px",
60
+ "background" : "#FFF",
61
+ "border" : "1px solid rgba(0,0,0,0.75)",
62
+ "border-radius" : "4px",
63
+ "box-shadow" : "7px 7px 5px 0px rgba(50,50,50,0.75)",
64
+ },
65
+ toString: renderCss
66
+ };
67
+ var closeCss = {
68
+ styles: {
69
+ "position" : "absolute",
70
+ "background" : "#FFF",
71
+ "width" : "20px",
72
+ "height" : "20px",
73
+ "border" : "2px solid rgba(0,0,0,0.75)",
74
+ "border-radius" : "15px",
75
+ "cursor" : "pointer",
76
+ "top" : "-8px",
77
+ "right" : "-8px",
78
+ "box-sizing" : "content-box",
79
+ },
80
+ toString: renderCss
81
+ };
82
+ var closeCssBefore = {
83
+ styles: {
84
+ "content" : "\"\"",
85
+ "display" : "block",
86
+ "position" : "absolute",
87
+ "background" : "#000",
88
+ "border-radius" : "1px",
89
+ "width" : "2px",
90
+ "height" : "16px",
91
+ "top" : "2px",
92
+ "left" : "9px",
93
+ "transform" : "rotate(45deg)",
94
+ },
95
+ toString: renderCss
96
+ };
97
+ var closeCssAfter = {
98
+ styles: {
99
+ "content" : "\"\"",
100
+ "display" : "block",
101
+ "position" : "absolute",
102
+ "background" : "#000",
103
+ "border-radius" : "1px",
104
+ "width" : "2px",
105
+ "height" : "16px",
106
+ "top" : "2px",
107
+ "left" : "9px",
108
+ "transform" : "rotate(-45deg)",
109
+ },
110
+ toString: renderCss
111
+ };
112
+ var bodyCss = {
113
+ styles: {
114
+ "overflow" : "hidden",
115
+ },
116
+ toString: renderCss
117
+ };
118
+ var cleantalkModalStyle = document.createElement( 'style' );
119
+ cleantalkModalStyle.setAttribute( 'id', 'cleantalk-modal-styles' );
120
+ cleantalkModalStyle.innerHTML = 'body.cleantalk-modal-opened{' + bodyCss + '}';
121
+ cleantalkModalStyle.innerHTML += '#cleantalk-modal-overlay{' + overlayCss + '}';
122
+ cleantalkModalStyle.innerHTML += '#cleantalk-modal-close{' + closeCss + '}';
123
+ cleantalkModalStyle.innerHTML += '#cleantalk-modal-close:before{' + closeCssBefore + '}';
124
+ cleantalkModalStyle.innerHTML += '#cleantalk-modal-close:after{' + closeCssAfter + '}';
125
+ document.body.append( cleantalkModalStyle );
126
+ /* Cleantalk Modal CSS end */
127
+
128
+ var overlay = document.createElement( 'div' );
129
+ overlay.setAttribute( 'id', 'cleantalk-modal-overlay' );
130
+ document.body.append( overlay );
131
+
132
+ document.body.classList.add( 'cleantalk-modal-opened' );
133
+
134
+ var inner = document.createElement( 'div' );
135
+ inner.setAttribute( 'id', 'cleantalk-modal-inner' );
136
+ inner.setAttribute( 'style', innerCss );
137
+ overlay.append( inner );
138
+
139
+ var close = document.createElement( 'div' );
140
+ close.setAttribute( 'id', 'cleantalk-modal-close' );
141
+ inner.append( close );
142
+
143
+ var content = document.createElement( 'div' );
144
+ if ( this.loaded ) {
145
+ content.innerHTML = this.loaded;
146
+ } else {
147
+ content.innerHTML = 'Loading...';
148
+ // @ToDo Here is hardcoded parameter. Have to get this from a 'data-' attribute.
149
+ this.load( 'get_options_template' );
150
+ }
151
+ content.setAttribute( 'id', 'cleantalk-modal-content' );
152
+ inner.append( content );
153
+
154
+ this.opened = true;
155
+ },
156
+
157
+ close: function () {
158
+ document.body.classList.remove( 'cleantalk-modal-opened' );
159
+ document.getElementById( 'cleantalk-modal-overlay' ).remove();
160
+ document.getElementById( 'cleantalk-modal-styles' ).remove();
161
+ document.dispatchEvent(
162
+ new CustomEvent( "cleantalkModalClosed", {
163
+ bubbles: true,
164
+ } )
165
+ );
166
+ }
167
+
168
+ };
169
+
170
+ /* Cleantalk Modal helpers */
171
+ document.addEventListener('click',function( e ){
172
+ if( e.target && e.target.id === 'cleantalk-modal-overlay' || e.target.id === 'cleantalk-modal-close' ){
173
+ cleantalkModal.close();
174
+ }
175
+ });
176
+ document.addEventListener("cleantalkModalContentLoaded", function( e ) {
177
+ if( cleantalkModal.opened && cleantalkModal.loaded ) {
178
+ document.getElementById( 'cleantalk-modal-content' ).innerHTML = cleantalkModal.loaded;
179
+ }
180
+ });
js/src/apbct-public--4--gdpr.js ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ let buttons_to_handle = []
2
+ let gdpr_notice_for_button = 'Please, apply the GDPR agreement.'
3
+
4
+ document.addEventListener('DOMContentLoaded', function(){
5
+ buttons_to_handle = []
6
+ if(
7
+ typeof ctPublicGDPR === 'undefined' ||
8
+ ! ctPublicGDPR.gdpr_forms.length
9
+ ) {
10
+ return;
11
+ }
12
+
13
+ if ( typeof jQuery === 'undefined' ) {
14
+ return;
15
+ }
16
+ try {
17
+ ctPublicGDPR.gdpr_forms.forEach(function(item, i){
18
+
19
+ let elem = jQuery('#'+item+', .'+item);
20
+
21
+ // Filter forms
22
+ if (!elem.is('form')){
23
+ // Caldera
24
+ if (elem.find('form')[0])
25
+ elem = elem.children('form').first();
26
+ // Contact Form 7
27
+ else if(
28
+ jQuery('.wpcf7[role=form]')[0] && jQuery('.wpcf7[role=form]')
29
+ .attr('id')
30
+ .indexOf('wpcf7-f'+item) !== -1
31
+ ) {
32
+ elem = jQuery('.wpcf7[role=form]').children('form');
33
+ }
34
+
35
+ // Formidable
36
+ else if(jQuery('.frm_forms')[0] && jQuery('.frm_forms').first().attr('id').indexOf('frm_form_'+item) !== -1)
37
+ elem = jQuery('.frm_forms').first().children('form');
38
+ // WPForms
39
+ else if(jQuery('.wpforms-form')[0] && jQuery('.wpforms-form').first().attr('id').indexOf('wpforms-form-'+item) !== -1)
40
+ elem = jQuery('.wpforms-form');
41
+ }
42
+
43
+ //disable forms buttons
44
+ let button = false
45
+ let buttons_collection= elem.find('input[type|="submit"]')
46
+
47
+ if (!buttons_collection.length) {
48
+ return
49
+ } else {
50
+ button = buttons_collection[0]
51
+ }
52
+
53
+ if (button !== false){
54
+ console.log(buttons_collection)
55
+ button.disabled = true
56
+ let old_notice = jQuery(button).prop('title') ? jQuery(button).prop('title') : ''
57
+ buttons_to_handle.push({index:i,button:button,old_notice:old_notice})
58
+ jQuery(button).prop('title', gdpr_notice_for_button)
59
+ }
60
+
61
+ // Adding notice and checkbox
62
+ if(elem.is('form') || elem.attr('role') === 'form'){
63
+ elem.append('<input id="apbct_gdpr_'+i+'" type="checkbox" required="required" style=" margin-right: 10px;" onchange="apbct_gdpr_handle_buttons()">')
64
+ .append('<label style="display: inline;" for="apbct_gdpr_'+i+'">'+ctPublicGDPR.gdpr_text+'</label>');
65
+ }
66
+ });
67
+ } catch (e) {
68
+ console.info('APBCT GDPR JS ERROR: Can not add GDPR notice' + e)
69
+ }
70
+ });
71
+
72
+ function apbct_gdpr_handle_buttons(){
73
+
74
+ try {
75
+
76
+ if (buttons_to_handle === []){
77
+ return
78
+ }
79
+
80
+ buttons_to_handle.forEach((button) => {
81
+ let selector = '[id="apbct_gdpr_' + button.index + '"]'
82
+ let apbct_gdpr_item = jQuery(selector)
83
+ //chek if apbct_gdpr checkbox is set
84
+ if (jQuery(apbct_gdpr_item).prop("checked")){
85
+ button.button.disabled = false
86
+ jQuery(button.button).prop('title', button.old_notice)
87
+ } else {
88
+ button.button.disabled = true
89
+ jQuery(button.button).prop('title', gdpr_notice_for_button)
90
+ }
91
+ })
92
+ } catch (e) {
93
+ console.info('APBCT GDPR JS ERROR: Can not handle form buttons ' + e)
94
+ }
95
+ }
js/src/apbct-public--5--external-forms.js ADDED
@@ -0,0 +1,253 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Handle external forms
3
+ */
4
+ function ct_protect_external() {
5
+ for(var i = 0; i < document.forms.length; i++) {
6
+
7
+ if (document.forms[i].cleantalk_hidden_action === undefined && document.forms[i].cleantalk_hidden_method === undefined) {
8
+
9
+ // current form
10
+ var currentForm = document.forms[i];
11
+
12
+ if (currentForm.parentElement && currentForm.parentElement.classList.length > 0 && currentForm.parentElement.classList[0].indexOf('mewtwo') !== -1){
13
+ return
14
+ }
15
+
16
+ if(typeof(currentForm.action) == 'string') {
17
+
18
+ // Ajax checking for the integrated forms
19
+ if(isIntegratedForm(currentForm)) {
20
+
21
+ var cleantalk_placeholder = document.createElement("i");
22
+ cleantalk_placeholder.className = 'cleantalk_placeholder';
23
+ cleantalk_placeholder.style = 'display: none';
24
+ currentForm.parentElement.insertBefore(cleantalk_placeholder, currentForm);
25
+
26
+ // Deleting form to prevent submit event
27
+ var prev = currentForm.previousSibling,
28
+ form_html = currentForm.outerHTML,
29
+ form_original = currentForm;
30
+
31
+ // Remove the original form
32
+ currentForm.parentElement.removeChild(currentForm);
33
+
34
+ // Insert a clone
35
+ const placeholder = document.createElement("div");
36
+ placeholder.innerHTML = form_html;
37
+ prev.after(placeholder.firstElementChild);
38
+
39
+ var force_action = document.createElement("input");
40
+ force_action.name = 'action';
41
+ force_action.value = 'cleantalk_force_ajax_check';
42
+ force_action.type = 'hidden';
43
+
44
+ let reUseCurrentForm = document.forms[i];
45
+
46
+ reUseCurrentForm.appendChild(force_action);
47
+ reUseCurrentForm.apbctPrev = prev;
48
+ reUseCurrentForm.apbctFormOriginal = form_original;
49
+
50
+ // mailerlite integration - disable click on submit button
51
+ let mailerlite_detected_class = false
52
+ if (reUseCurrentForm.classList !== undefined) {
53
+ //list there all the mailerlite classes
54
+ let mailerlite_classes = ['newsletterform', 'ml-block-form']
55
+ mailerlite_classes.forEach(function(mailerlite_class) {
56
+ if (reUseCurrentForm.classList.contains(mailerlite_class)){
57
+ mailerlite_detected_class = mailerlite_class
58
+ }
59
+ });
60
+ }
61
+ if ( mailerlite_detected_class ) {
62
+ let mailerliteSubmitButton = jQuery('form.' + mailerlite_detected_class).find('button[type="submit"]');
63
+ if ( mailerliteSubmitButton !== undefined ) {
64
+ mailerliteSubmitButton.click(function (event) {
65
+ event.preventDefault();
66
+ sendAjaxCheckingFormData(event.currentTarget);
67
+ });
68
+ }
69
+ } else {
70
+ document.forms[i].onsubmit = function ( event ){
71
+ event.preventDefault();
72
+
73
+ const prev = jQuery(event.currentTarget).prev();
74
+ const form_original = jQuery(event.currentTarget).clone();
75
+
76
+ sendAjaxCheckingFormData(event.currentTarget);
77
+ };
78
+ }
79
+
80
+ // Common flow - modify form's action
81
+ }else if(currentForm.action.indexOf('http://') !== -1 || currentForm.action.indexOf('https://') !== -1) {
82
+
83
+ var tmp = currentForm.action.split('//');
84
+ tmp = tmp[1].split('/');
85
+ var host = tmp[0].toLowerCase();
86
+
87
+ if(host !== location.hostname.toLowerCase()){
88
+
89
+ var ct_action = document.createElement("input");
90
+ ct_action.name = 'cleantalk_hidden_action';
91
+ ct_action.value = currentForm.action;
92
+ ct_action.type = 'hidden';
93
+ currentForm.appendChild(ct_action);
94
+
95
+ var ct_method = document.createElement("input");
96
+ ct_method.name = 'cleantalk_hidden_method';
97
+ ct_method.value = currentForm.method;
98
+ ct_method.type = 'hidden';
99
+
100
+ currentForm.method = 'POST'
101
+
102
+ currentForm.appendChild(ct_method);
103
+
104
+ currentForm.action = document.location;
105
+ }
106
+ }
107
+ }
108
+ }
109
+
110
+ }
111
+ }
112
+ function apbct_replace_inputs_values_from_other_form( form_source, form_target ){
113
+
114
+ var inputs_source = jQuery( form_source ).find( 'button, input, textarea, select' ),
115
+ inputs_target = jQuery( form_target ).find( 'button, input, textarea, select' );
116
+
117
+ inputs_source.each( function( index, elem_source ){
118
+
119
+ var source = jQuery( elem_source );
120
+
121
+ inputs_target.each( function( index2, elem_target ){
122
+
123
+ var target = jQuery( elem_target );
124
+
125
+ if( elem_source.outerHTML === elem_target.outerHTML ){
126
+
127
+ target.val( source.val() );
128
+ }
129
+ });
130
+ });
131
+
132
+ }
133
+ window.onload = function () {
134
+
135
+ if( ! +ctPublic.settings__forms__check_external ) {
136
+ return;
137
+ }
138
+
139
+ if ( typeof jQuery === 'undefined' ) {
140
+ return;
141
+ }
142
+
143
+ setTimeout(function () {
144
+ ct_protect_external()
145
+ }, 1500);
146
+ };
147
+
148
+ /**
149
+ * Checking the form integration
150
+ */
151
+ function isIntegratedForm(formObj) {
152
+ var formAction = formObj.action;
153
+
154
+ if(
155
+ formAction.indexOf('activehosted.com') !== -1 || // ActiveCampaign form
156
+ formAction.indexOf('app.convertkit.com') !== -1 || // ConvertKit form
157
+ ( formObj.firstChild.classList !== undefined && formObj.firstChild.classList.contains('cb-form-group') ) || // Convertbox form
158
+ formAction.indexOf('mailerlite.com') !== -1 || // Mailerlite integration
159
+ formAction.indexOf('colcolmail.co.uk') !== -1 || // colcolmail.co.uk integration
160
+ formAction.indexOf('paypal.com') !== -1 ||
161
+ formAction.indexOf('infusionsoft.com') !== -1 ||
162
+ formAction.indexOf('webto.salesforce.com') !== -1 ||
163
+ formAction.indexOf('secure2.convio.net') !== -1 ||
164
+ formAction.indexOf('hookb.in') !== -1 ||
165
+ formAction.indexOf('external.url') !== -1 ||
166
+ formAction.indexOf('tp.media') !== -1 ||
167
+ formAction.indexOf('flodesk.com') !== -1 ||
168
+ formAction.indexOf('sendfox.com') !== -1 ||
169
+ formAction.indexOf('aweber.com') !== -1 ||
170
+ formAction.indexOf('secure.payu.com') !== -1
171
+
172
+ ) {
173
+ return true;
174
+ }
175
+
176
+ return false;
177
+ }
178
+
179
+ /**
180
+ * Sending Ajax for checking form data
181
+ */
182
+ function sendAjaxCheckingFormData(form, prev, formOriginal) {
183
+ // Get visible fields and set cookie
184
+ var visible_fields = {};
185
+ visible_fields[0] = apbct_collect_visible_fields(form);
186
+ apbct_visible_fields_set_cookie( visible_fields );
187
+
188
+ var data = {};
189
+ var elems = form.elements;
190
+ elems = Array.prototype.slice.call(elems);
191
+
192
+ elems.forEach( function( elem, y ) {
193
+ if( elem.name === '' ) {
194
+ data['input_' + y] = elem.value;
195
+ } else {
196
+ data[elem.name] = elem.value;
197
+ }
198
+ });
199
+
200
+ apbct_public_sendAJAX(
201
+ data,
202
+ {
203
+ async: false,
204
+ callback: function( result, data, params, obj ){
205
+
206
+ if( result.apbct === undefined || ! +result.apbct.blocked ) {
207
+
208
+ let form_new = jQuery(form).detach();
209
+ let prev = form.apbctPrev;
210
+ let formOriginal = form.apbctFormOriginal;
211
+
212
+ apbct_replace_inputs_values_from_other_form(form_new, formOriginal);
213
+
214
+ prev.after( formOriginal );
215
+
216
+ // Clear visible_fields input
217
+ jQuery(formOriginal).find('input[name="apbct_visible_fields"]').remove();
218
+ jQuery(formOriginal).find('input[value="cleantalk_force_ajax_check"]').remove();
219
+
220
+ // Common click event
221
+ var subm_button = jQuery(formOriginal).find('button[type=submit]');
222
+ if( subm_button.length !== 0 ) {
223
+ subm_button[0].click();
224
+ return;
225
+ }
226
+
227
+ subm_button = jQuery(formOriginal).find('input[type=submit]');
228
+ if( subm_button.length !== 0 ) {
229
+ subm_button[0].click();
230
+ return;
231
+ }
232
+
233
+ // ConvertKit direct integration
234
+ subm_button = jQuery(formOriginal).find('button[data-element="submit"]');
235
+ if( subm_button.length !== 0 ) {
236
+ subm_button[0].click();
237
+ return;
238
+ }
239
+
240
+ // Paypal integration
241
+ subm_button = jQuery(formOriginal).find('input[type="image"][name="submit"]');
242
+ if( subm_button.length !== 0 ) {
243
+ subm_button[0].click();
244
+ }
245
+
246
+ }
247
+ if (result.apbct !== undefined && +result.apbct.blocked) {
248
+ ctParseBlockMessage(result);
249
+ }
250
+ }
251
+ }
252
+ );
253
+ }
js/src/apbct-public--6--internal-forms.js ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function ct_check_internal(currForm){
2
+
3
+ //Gathering data
4
+ var ct_data = {},
5
+ elems = currForm.elements;
6
+
7
+ for (var key in elems) {
8
+ if(elems[key].type == 'submit' || elems[key].value == undefined || elems[key].value == '')
9
+ continue;
10
+ ct_data[elems[key].name] = currForm.elements[key].value;
11
+ }
12
+ ct_data['action'] = 'ct_check_internal';
13
+
14
+ //AJAX Request
15
+ apbct_public_sendAJAX(
16
+ ct_data,
17
+ {
18
+ url: ctPublicFunctions._ajax_url,
19
+ callback: function (data) {
20
+ if(data.success === true){
21
+ currForm.submit();
22
+ }else{
23
+ alert(data.data);
24
+ return false;
25
+ }
26
+ }
27
+ }
28
+ );
29
+ }
30
+
31
+ document.addEventListener('DOMContentLoaded',function(){
32
+ let ct_currAction = '',
33
+ ct_currForm = '';
34
+
35
+ if( ! +ctPublic.settings__forms__check_internal ) {
36
+ return;
37
+ }
38
+
39
+ for( let i=0; i<document.forms.length; i++ ){
40
+ if ( typeof(document.forms[i].action) == 'string' ){
41
+ ct_currForm = document.forms[i];
42
+ ct_currAction = ct_currForm.action;
43
+ if (
44
+ ct_currAction.indexOf('https?://') !== null && // The protocol is obligatory
45
+ ct_currAction.match(ctPublic.blog_home + '.*?\.php') !== null && // Main check
46
+ ! ct_check_internal__is_exclude_form(ct_currAction) // Exclude WordPress native scripts from processing
47
+ ) {
48
+ ctPrevHandler = ct_currForm.click;
49
+ if ( typeof jQuery !== 'undefined' ) {
50
+ jQuery(ct_currForm).off('**');
51
+ jQuery(ct_currForm).off();
52
+ jQuery(ct_currForm).on('submit', function(event){
53
+ ct_check_internal(event.target);
54
+ return false;
55
+ });
56
+ }
57
+ }
58
+ }
59
+ }
60
+ });
61
+
62
+ /**
63
+ * Check by action to exclude the form checking
64
+ * @param action string
65
+ * @return boolean
66
+ */
67
+ function ct_check_internal__is_exclude_form(action) {
68
+ // An array contains forms action need to be excluded.
69
+ let ct_internal_script_exclusions = [
70
+ ctPublic.blog_home + 'wp-login.php', // WordPress login page
71
+ ctPublic.blog_home + 'wp-comments-post.php', // WordPress Comments Form
72
+ ];
73
+
74
+ return ct_internal_script_exclusions.some((item) => {
75
+ return action.match(new RegExp('^' + item)) !== null;
76
+ });
77
+ }
js/src/apbct-public-bundle.js ADDED
@@ -0,0 +1,2448 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class ApbctCore{
2
+
3
+ ajax_parameters = {};
4
+ rest_parameters = {};
5
+
6
+ #selector = null;
7
+ elements = [];
8
+
9
+ // Event properties
10
+ #eventCallback;
11
+ #eventSelector;
12
+ #event;
13
+
14
+ /**
15
+ * Default constructor
16
+ */
17
+ constructor(selector){
18
+ this.select(selector);
19
+ }
20
+
21
+ /**
22
+ * Get elements by CSS selector
23
+ *
24
+ * @param selector
25
+ * @returns {*}
26
+ */
27
+ select(selector) {
28
+
29
+ if(selector instanceof HTMLCollection){
30
+ this.#selector = null;
31
+ this.elements = [];
32
+ this.elements = Array.prototype.slice.call(selector);
33
+ }else if( typeof selector === 'object' ){
34
+ this.#selector = null;
35
+ this.elements = [];
36
+ this.elements[0] = selector;
37
+ }else if( typeof selector === 'string' ){
38
+ this.#selector = selector;
39
+ this.elements = Array.prototype.slice.call(document.querySelectorAll(selector));
40
+ // this.elements = document.querySelectorAll(selector)[0];
41
+ }else{
42
+ this.#deselect();
43
+ }
44
+
45
+ return this;
46
+ }
47
+
48
+ #addElement(elemToAdd){
49
+ if( typeof elemToAdd === 'object' ){
50
+ this.elements.push(elemToAdd);
51
+ }else if( typeof elemToAdd === 'string' ){
52
+ this.#selector = elemToAdd;
53
+ this.elements = Array.prototype.slice.call(document.querySelectorAll(elemToAdd));
54
+ }else{
55
+ this.#deselect();
56
+ }
57
+ }
58
+
59
+ #push(elem){
60
+ this.elements.push(elem);
61
+ }
62
+
63
+ #reduce(){
64
+ this.elements = this.elements.slice(0,-1);
65
+ }
66
+
67
+ #deselect(){
68
+ this.elements = [];
69
+ }
70
+
71
+ /**
72
+ * Set or get CSS for/of currently selected element
73
+ *
74
+ * @param style
75
+ * @param getRaw
76
+ *
77
+ * @returns {boolean|*}
78
+ */
79
+ css(style, getRaw){
80
+
81
+ getRaw = getRaw | false;
82
+
83
+ // Set style
84
+ if(typeof style === "object"){
85
+
86
+ const stringToCamelCase = str =>
87
+ str.replace(/([-_][a-z])/g, group =>
88
+ group
89
+ .toUpperCase()
90
+ .replace('-', '')
91
+ .replace('_', '')
92
+ );
93
+
94
+ // Apply multiple styles
95
+ for(let style_name in style){
96
+ let DOM_style_name = stringToCamelCase(style_name);
97
+
98
+ // Apply to multiple elements (currently selected)
99
+ for(let i=0; i<this.elements.length; i++){
100
+ this.elements[i].style[DOM_style_name] = style[style_name];
101
+ }
102
+ }
103
+
104
+ return this;
105
+ }
106
+
107
+ // Get style of first currently selected element
108
+ if(typeof style === 'string'){
109
+
110
+ let computedStyle = getComputedStyle(this.elements[0])[style];
111
+
112
+ console.log(computedStyle);
113
+
114
+ // Process
115
+ if( typeof computedStyle !== 'undefined' && ! getRaw){
116
+ computedStyle = computedStyle.replace(/(\d)(em|pt|%|px){1,2}$/, '$1'); // Cut of units
117
+ computedStyle = Number(computedStyle) == computedStyle ? Number(computedStyle) : computedStyle; // Cast to INT
118
+ return computedStyle;
119
+ }
120
+
121
+ // Return unprocessed
122
+ return computedStyle;
123
+ }
124
+ }
125
+
126
+ hide(){
127
+ this.prop('prev-display', this.css('display'));
128
+ this.css({'display': 'none'});
129
+ }
130
+
131
+ show(){
132
+ this.css({'display': this.prop('prev-display')});
133
+ }
134
+
135
+ addClass(){
136
+ for(let i=0; i<this.elements.length; i++){
137
+ this.elements[i].classList.add(className);
138
+ }
139
+ }
140
+
141
+ removeClass(){
142
+ for(let i=0; i<this.elements.length; i++){
143
+ this.elements[i].classList.remove(className);
144
+ }
145
+ }
146
+
147
+ toggleClass(className){
148
+ for(let i=0; i<this.elements.length; i++){
149
+ this.elements[i].classList.toggle(className);
150
+ }
151
+ }
152
+
153
+ /**
154
+ * Wrapper for apbctAJAX class
155
+ *
156
+ * @param ajax_parameters
157
+ * @returns {ApbctAjax}
158
+ */
159
+ ajax(ajax_parameters){
160
+ this.ajax_parameters = ajax_parameters;
161
+ return new ApbctAjax(ajax_parameters);
162
+ }
163
+
164
+ /**
165
+ * Wrapper for apbctREST class
166
+ *
167
+ * @param rest_parameters
168
+ * @returns {ApbctRest}
169
+ */
170
+ rest(rest_parameters){
171
+ this.rest_parameters = rest_parameters;
172
+ return new ApbctRest(rest_parameters);
173
+ }
174
+
175
+ /************** EVENTS **************/
176
+
177
+ /**
178
+ *
179
+ * Why the mess with arguments?
180
+ *
181
+ * Because we need to support the following function signatures:
182
+ * on('click', function(){ alert('some'); });
183
+ * on('click', 'inner_selector', function(){ alert('some'); });
184
+ *
185
+ * @param args
186
+ */
187
+ on(...args){
188
+
189
+ this.#event = args[0];
190
+ this.#eventCallback = args[2] || args[1];
191
+ this.#eventSelector = typeof args[1] === "string" ? args[1] : null;
192
+
193
+ for(let i=0; i<this.elements.length; i++){
194
+ this.elements[i].addEventListener(
195
+ this.#event,
196
+ this.#eventSelector !== null
197
+ ? this.#onChecker.bind(this)
198
+ : this.#eventCallback
199
+ );
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Check if a selector of an event matches current target
205
+ *
206
+ * @param event
207
+ * @returns {*}
208
+ */
209
+ #onChecker(event){
210
+ if(event.target === document.querySelector(this.#eventSelector)){
211
+ event.stopPropagation();
212
+ return this.#eventCallback(event);
213
+ }
214
+ }
215
+
216
+ ready(callback){
217
+ document.addEventListener('DOMContentLoaded', callback);
218
+ }
219
+
220
+ change(callback){
221
+ this.on('change', callback);
222
+ }
223
+
224
+ /************** ATTRIBUTES **************/
225
+
226
+ /**
227
+ * Get an attribute or property of an element
228
+ *
229
+ * @param attrName
230
+ * @returns {*|*[]}
231
+ */
232
+ attr(attrName){
233
+
234
+ let outputValue = [];
235
+
236
+ for(let i=0; i<this.elements.length; i++){
237
+
238
+ // Use property instead of attribute if possible
239
+ if(typeof this.elements[i][attrName] !== undefined){
240
+ outputValue.push(this.elements[i][attrName]);
241
+ }else{
242
+ outputValue.push(this.elements[i].getAttribute(attrName));
243
+ }
244
+ }
245
+
246
+ // Return a single value instead of array if only one value is present
247
+ return outputValue.length === 1 ? outputValue[0] : outputValue;
248
+ }
249
+
250
+ prop(propName, value){
251
+
252
+ // Setting values
253
+ if(typeof value !== "undefined"){
254
+ for(let i=0; i<this.elements.length; i++){
255
+ this.elements[i][propName] = value;
256
+ }
257
+
258
+ return this;
259
+
260
+ // Getting values
261
+ }else{
262
+
263
+ let outputValue = [];
264
+
265
+ for(let i=0; i<this.elements.length; i++){
266
+ outputValue.push(this.elements[i][propName]);
267
+ }
268
+
269
+ // Return a single value instead of array if only one value is present
270
+ return outputValue.length === 1 ? outputValue[0] : outputValue;
271
+ }
272
+ }
273
+
274
+ /**
275
+ * Set or get inner HTML
276
+ *
277
+ * @param value
278
+ * @returns {*|*[]}
279
+ */
280
+ html(value){
281
+ return typeof value !== 'undefined'
282
+ ? this.prop('innerHTML', value)
283
+ : this.prop('innerHTML');
284
+ }
285
+
286
+ /**
287
+ * Set or get value of input tags
288
+ *
289
+ * @param value
290
+ * @returns {*|*[]|undefined}
291
+ */
292
+ val(value){
293
+ return typeof value !== 'undefined'
294
+ ? this.prop('value', value)
295
+ : this.prop('value');
296
+ }
297
+
298
+ data(name, value){
299
+ return typeof value !== 'undefined'
300
+ ? this.prop('apbct-data', name, value)
301
+ : this.prop('apbct-data');
302
+ }
303
+
304
+ /************** END OF ATTRIBUTES **************/
305
+
306
+ /************** FILTERS **************/
307
+
308
+ /**
309
+ * Check if the current elements are corresponding to filter
310
+ *
311
+ * @param filter
312
+ * @returns {boolean}
313
+ */
314
+ is(filter){
315
+
316
+ let outputValue = false;
317
+
318
+ for(let elem of this.elements){
319
+ outputValue ||= this.#isElem(elem, filter);
320
+ }
321
+
322
+ return outputValue;
323
+ }
324
+
325
+ #isElem(elemToCheck, filter){
326
+
327
+ let is = false;
328
+ let isRegisteredTagName = function(name){
329
+ let newlyCreatedElement = document.createElement(name).constructor;
330
+ return ! Boolean( ~[HTMLElement, HTMLUnknownElement].indexOf(newlyCreatedElement) );
331
+ };
332
+
333
+ // Check for filter function
334
+ if(typeof filter === 'function') {
335
+ is ||= filter.call(this, elemToCheck);
336
+ }
337
+
338
+ // Check for filter function
339
+ if(typeof filter === 'string') {
340
+
341
+ // Filter is tag name
342
+ if( filter.match(/^[a-z]/) && isRegisteredTagName(filter) ){
343
+ is ||= elemToCheck.tagName.toLowerCase() === filter.toLowerCase();
344
+
345
+ // Filter is property
346
+ }else if( filter.match(/^[a-z]/) ){
347
+ is ||= Boolean(elemToCheck[filter]);
348
+
349
+ // Filter is CSS selector
350
+ }else {
351
+ is ||= this.#selector !== null
352
+ ? document.querySelector(this.#selector + filter) !== null // If possible
353
+ : this.#isWithoutSelector(elemToCheck, filter); // Search through all elems with such selector
354
+ }
355
+ }
356
+
357
+ return is;
358
+ }
359
+
360
+ #isWithoutSelector(elemToCheck, filter){
361
+
362
+ let elems = document.querySelectorAll(filter);
363
+ let outputValue = false;
364
+
365
+ for(let elem of elems){
366
+ outputValue ||= elemToCheck === elem;
367
+ }
368
+
369
+ return outputValue;
370
+ }
371
+
372
+ filter(filter){
373
+
374
+ this.#selector = null;
375
+
376
+ for( let i = this.elements.length - 1; i >= 0; i-- ){
377
+ if( ! this.#isElem(this.elements[i], filter) ){
378
+ this.elements.splice(Number(i), 1);
379
+ }
380
+ }
381
+
382
+ return this;
383
+ }
384
+
385
+ /************** NODES **************/
386
+
387
+ parent(filter){
388
+
389
+ this.select(this.elements[0].parentElement);
390
+
391
+ if( typeof filter !== 'undefined' && ! this.is(filter) ){
392
+ this.#deselect();
393
+ }
394
+
395
+ return this;
396
+ }
397
+
398
+ parents(filter){
399
+
400
+ this.select(this.elements[0]);
401
+
402
+ for ( ; this.elements[ this.elements.length - 1].parentElement !== null ; ) {
403
+ this.#push(this.elements[ this.elements.length - 1].parentElement);
404
+ }
405
+
406
+ this.elements.splice(0,1); // Deleting initial element from the set
407
+
408
+ if( typeof filter !== 'undefined' ){
409
+ this.filter(filter);
410
+ }
411
+
412
+ return this;
413
+ }
414
+
415
+ children(filter){
416
+
417
+ this.select(this.elements[0].children);
418
+
419
+ if( typeof filter !== 'undefined' ){
420
+ this.filter(filter);
421
+ }
422
+
423
+ return this;
424
+ }
425
+
426
+ siblings(filter){
427
+
428
+ let current = this.elements[0]; // Remember current to delete it later
429
+
430
+ this.parent();
431
+ this.children(filter);
432
+ this.elements.splice(this.elements.indexOf(current), 1); // Remove current element
433
+
434
+ return this;
435
+ }
436
+
437
+ /************** DOM MANIPULATIONS **************/
438
+ remove(){
439
+ for(let elem of this.elements){
440
+ elem.remove();
441
+ }
442
+ }
443
+
444
+ after(content){
445
+ for(let elem of this.elements){
446
+ elem.after(content);
447
+ }
448
+ }
449
+
450
+ append(content){
451
+ for(let elem of this.elements){
452
+ elem.append(content);
453
+ }
454
+ }
455
+
456
+ /** ANIMATION **/
457
+ fadeIn(time) {
458
+ for(let elem of this.elements){
459
+ elem.style.opacity = 0;
460
+ elem.style.display = 'block';
461
+
462
+ let last = +new Date();
463
+ const tick = function () {
464
+ elem.style.opacity = +elem.style.opacity + (new Date() - last) / time;
465
+ last = +new Date();
466
+
467
+ if (+elem.style.opacity < 1) {
468
+ (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
469
+ }
470
+ };
471
+
472
+ tick();
473
+ }
474
+ }
475
+
476
+ fadeOut(time) {
477
+ for(let elem of this.elements){
478
+ elem.style.opacity = 1;
479
+
480
+ let last = +new Date();
481
+ const tick = function () {
482
+ elem.style.opacity = +elem.style.opacity - (new Date() - last) / time;
483
+ last = +new Date();
484
+
485
+ if (+elem.style.opacity > 0) {
486
+ (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);
487
+ } else {
488
+ elem.style.display = 'none';
489
+ }
490
+ };
491
+
492
+ tick();
493
+ }
494
+ }
495
+
496
+ }
497
+
498
+ /**
499
+ * Hack
500
+ *
501
+ * Make a proxy to keep both properties and methods from:
502
+ * - the native object and
503
+ * - the new one from ApbctCore for selected element.
504
+ *
505
+ * For example:
506
+ * apbct('#id).innerHTML = 'some';
507
+ * apbct('#id).css({'backgorund-color': 'black'});
508
+ */
509
+ // apbct = new Proxy(
510
+ // apbct,
511
+ // {
512
+ // get(target, prop) {
513
+ // if (target.elements.length) {
514
+ // return target.elements[0][prop];
515
+ // } else {
516
+ // return null;
517
+ // }
518
+ // },
519
+ // set(target, prop, value){
520
+ // if (target.elements.length) {
521
+ // target.elements[0][prop] = value;
522
+ // return true;
523
+ // } else {
524
+ // return false;
525
+ // }
526
+ // },
527
+ // apply(target, thisArg, argArray) {
528
+ //
529
+ // }
530
+ // }
531
+ // );
532
+
533
+ /**
534
+ * Enter point to ApbctCore class
535
+ *
536
+ * @param params
537
+ * @returns {*}
538
+ */
539
+ function apbct(params){
540
+ return new ApbctCore()
541
+ .select(params);
542
+ }
543
+ class ApbctXhr{
544
+
545
+ #xhr = new XMLHttpRequest();
546
+
547
+ // Base parameters
548
+ method = 'POST'; // HTTP-request type
549
+ url = ''; // URL to send the request
550
+ async = true;
551
+ user = null; // HTTP-authorization username
552
+ password = null; // HTTP-authorization password
553
+ data = {}; // Data to send
554
+
555
+
556
+ // Optional params
557
+ button = null; // Button that should be disabled when request is performing
558
+ spinner = null; // Spinner that should appear when request is in process
559
+ progressbar = null; // Progress bar for the current request
560
+ context = this; // Context
561
+ callback = null;
562
+ onErrorCallback = null;
563
+
564
+ responseType = 'json'; // Expected data type from server
565
+ headers = {};
566
+ timeout = 15000; // Request timeout in milliseconds
567
+
568
+ #methods_to_convert_data_to_URL = [
569
+ 'GET',
570
+ 'HEAD',
571
+ ];
572
+
573
+ #body = null;
574
+ #http_code = 0;
575
+ #status_text = '';
576
+
577
+ constructor(parameters){
578
+
579
+ console.log('%cXHR%c started', 'color: red; font-weight: bold;', 'color: grey; font-weight: normal;');
580
+
581
+ // Set class properties
582
+ for( let key in parameters ){
583
+ if( typeof this[key] !== 'undefined' ){
584
+ this[key] = parameters[key];
585
+ }
586
+ }
587
+
588
+ // Modifying DOM-elements
589
+ this.#prepare();
590
+
591
+ // Modify URL with data for GET and HEAD requests
592
+ if ( Object.keys(this.data).length ) {
593
+ this.deleteDoubleJSONEncoding(this.data);
594
+ this.convertData();
595
+ }
596
+
597
+ if( ! this.url ){
598
+ console.log('%cXHR%c not URL provided', 'color: red; font-weight: bold;', 'color: grey; font-weight: normal;')
599
+ return false;
600
+ }
601
+
602
+ // Configure the request
603
+ this.#xhr.open(this.method, this.url, this.async, this.user, this.password);
604
+ this.setHeaders();
605
+
606
+ this.#xhr.responseType = this.responseType;
607
+ this.#xhr.timeout = this.timeout;
608
+
609
+ /* EVENTS */
610
+ // Monitoring status
611
+ this.#xhr.onreadystatechange = function(){
612
+ this.onReadyStateChange();
613
+ }.bind(this);
614
+
615
+ // Run callback
616
+ this.#xhr.onload = function(){
617
+ this.onLoad();
618
+ }.bind(this);
619
+
620
+ // On progress
621
+ this.#xhr.onprogress = function(event){
622
+ this.onProgress(event);
623
+ }.bind(this);
624
+
625
+ // On error
626
+ this.#xhr.onerror = function(){
627
+ this.onError();
628
+ }.bind(this);
629
+
630
+ this.#xhr.ontimeout = function(){
631
+ this.onTimeout();
632
+ }.bind(this);
633
+
634
+ // Send the request
635
+ this.#xhr.send(this.#body);
636
+ }
637
+
638
+ #prepare(){
639
+
640
+ // Disable button
641
+ if(this.button){
642
+ this.button.setAttribute('disabled', 'disabled');
643
+ this.button.style.cursor = 'not-allowed';
644
+ }
645
+
646
+ // Enable spinner
647
+ if(this.spinner) {
648
+ this.spinner.style.display = 'inline';
649
+ }
650
+ }
651
+
652
+ #complete(){
653
+
654
+ this.#http_code = this.#xhr.status;
655
+ this.#status_text = this.#xhr.statusText;
656
+
657
+ // Disable button
658
+ if(this.button){
659
+ this.button.removeAttribute('disabled');
660
+ this.button.style.cursor = 'auto';
661
+ }
662
+
663
+ // Enable spinner
664
+ if(this.spinner) {
665
+ this.spinner.style.display = 'none';
666
+ }
667
+
668
+ if( this.progressbar ) {
669
+ this.progressbar.fadeOut('slow');
670
+ }
671
+ }
672
+
673
+ onReadyStateChange(){
674
+ if (this.on_ready_state_change !== null && typeof this.on_ready_state_change === 'function'){
675
+ this.on_ready_state_change();
676
+ }
677
+ }
678
+
679
+ onProgress(event) {
680
+ if (this.on_progress !== null && typeof this.on_progress === 'function'){
681
+ this.on_progress();
682
+ }
683
+ }
684
+
685
+ onError(){
686
+
687
+ console.log('error');
688
+
689
+ this.#complete();
690
+ this.#error(
691
+ this.#http_code,
692
+ this.#status_text
693
+ );
694
+
695
+ if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function'){
696
+ this.onErrorCallback(this.#status_text);
697
+ }
698
+ }
699
+
700
+ onTimeout(){
701
+ this.#complete();
702
+ this.#error(
703
+ 0,
704
+ 'timeout'
705
+ );
706
+
707
+ if (this.onErrorCallback !== null && typeof this.onErrorCallback === 'function'){
708
+ this.onErrorCallback('Timeout');
709
+ }
710
+ }
711
+
712
+ onLoad(){
713
+
714
+ this.#complete();
715
+
716
+ if (this.responseType === 'json' ){
717
+ if(this.#xhr.response === null){
718
+ this.#error(this.#http_code, this.#status_text, 'No response');
719
+ return false;
720
+ }else if( typeof this.#xhr.response.error !== 'undefined') {
721
+ this.#error(this.#http_code, this.#status_text, this.#xhr.response.error);
722
+ return false;
723
+ }
724
+ }
725
+
726
+ if (this.callback !== null && typeof this.callback === 'function') {
727
+ this.callback.call(this.context, this.#xhr.response, this.data);
728
+ }
729
+ }
730
+
731
+ #error(http_code, status_text, additional_msg){
732
+
733
+ let error_string = '';
734
+
735
+ if( status_text === 'timeout' ){
736
+ error_string += 'Server response timeout'
737
+
738
+ }else if( http_code === 200 ){
739
+
740
+ if( status_text === 'parsererror' ){
741
+ error_string += 'Unexpected response from server. See console for details.';
742
+ }else {
743
+ error_string += 'Unexpected error. Status: ' + status_text + '.';
744
+ if( typeof additional_msg !== 'undefined' )
745
+ error_string += ' Additional error info: ' + additional_msg;
746
+ }
747
+
748
+ }else if(http_code === 500){
749
+ error_string += 'Internal server error.';
750
+
751
+ }else {
752
+ error_string += 'Unexpected response code:' + http_code;
753
+ }
754
+
755
+ this.errorOutput( error_string );
756
+ }
757
+
758
+ errorOutput(error_msg){
759
+ console.log( '%c ctXHR error: %c' + error_msg, 'color: red;', 'color: grey;' );
760
+ }
761
+
762
+ setHeaders(){
763
+ // Set headers if passed
764
+ for( let header_name in this.headers ){
765
+ if( typeof this.headers[header_name] !== 'undefined' ){
766
+ this.#xhr.setRequestHeader(header_name, this.headers[header_name]);
767
+ }
768
+ }
769
+ }
770
+
771
+ convertData()
772
+ {
773
+ // GET, HEAD request-type
774
+ if( ~this.#methods_to_convert_data_to_URL.indexOf( this.method ) ){
775
+ return this.convertDataToURL();
776
+
777
+ // POST request-type
778
+ }else{
779
+ return this.convertDataToBody()
780
+ }
781
+ }
782
+
783
+ convertDataToURL(){
784
+ let params_appendix = new URLSearchParams(this.data).toString();
785
+ let params_prefix = this.url.match(/^(https?:\/{2})?[a-z0-9.]+\?/) ? '&' : '?';
786
+ this.url += params_prefix + params_appendix;
787
+
788
+ return this.url;
789
+ }
790
+
791
+ /**
792
+ *
793
+ * @returns {null}
794
+ */
795
+ convertDataToBody()
796
+ {
797
+ this.#body = new FormData();
798
+
799
+ for (let dataKey in this.data) {
800
+ this.#body.append(
801
+ dataKey,
802
+ typeof this.data[dataKey] === 'object'
803
+ ? JSON.stringify(this.data[dataKey])
804
+ : this.data[dataKey]
805
+ );
806
+ }
807
+
808
+ return this.#body;
809
+ }
810
+
811
+ /**
812
+ * Recursive
813
+ *
814
+ * Recursively decode JSON-encoded properties
815
+ *
816
+ * @param object
817
+ * @returns {*}
818
+ */
819
+ deleteDoubleJSONEncoding(object){
820
+
821
+ if( typeof object === 'object'){
822
+
823
+ for (let objectKey in object) {
824
+
825
+ // Recursion
826
+ if( typeof object[objectKey] === 'object'){
827
+ object[objectKey] = this.deleteDoubleJSONEncoding(object[objectKey]);
828
+ }
829
+
830
+ // Common case (out)
831
+ if(
832
+ typeof object[objectKey] === 'string' &&
833
+ object[objectKey].match(/^[\[{].*?[\]}]$/) !== null // is like JSON
834
+ ){
835
+ let parsedValue = JSON.parse(object[objectKey]);
836
+ if( typeof parsedValue === 'object' ){
837
+ object[objectKey] = parsedValue;
838
+ }
839
+ }
840
+ }
841
+ }
842
+
843
+ return object;
844
+ }
845
+ }
846
+ class ApbctAjax extends ApbctXhr{
847
+
848
+ constructor(...args) {
849
+ super(args[0]);
850
+ }
851
+ }
852
+ class ApbctRest extends ApbctXhr{
853
+
854
+ static default_route = ctPublicFunctions._rest_url + 'cleantalk-antispam/v1/';
855
+ route = '';
856
+
857
+ constructor(...args) {
858
+ args = args[0];
859
+ args.url = ApbctRest.default_route + args.route;
860
+ args.headers = {
861
+ "X-WP-Nonce": ctPublicFunctions._rest_nonce
862
+ };
863
+ super(args);
864
+ }
865
+ }
866
+
867
+ function ctSetCookie( cookies, value, expires ){
868
+
869
+ if( typeof cookies === 'string' && typeof value === 'string' || typeof value === 'number'){
870
+ var skip_alt = cookies === 'ct_pointer_data';
871
+ cookies = [ [ cookies, value, expires ] ];
872
+ }
873
+
874
+ // Cookies disabled
875
+ if( ctPublicFunctions.data__cookies_type === 'none' ){
876
+ cookies.forEach( function (item, i, arr ) {
877
+ apbctLocalStorage.set(item[0], encodeURIComponent(item[1]))
878
+ });
879
+ ctNoCookieAttachHiddenFieldsToForms()
880
+ // Using traditional cookies
881
+ }else if( ctPublicFunctions.data__cookies_type === 'native' ){
882
+ cookies.forEach( function (item, i, arr ) {
883
+ var expires = typeof item[2] !== 'undefined' ? "expires=" + expires + '; ' : '';
884
+ var ctSecure = location.protocol === 'https:' ? '; secure' : '';
885
+ document.cookie = ctPublicFunctions.cookiePrefix + item[0] + "=" + encodeURIComponent(item[1]) + "; " + expires + "path=/; samesite=lax" + ctSecure;
886
+ });
887
+
888
+ // Using alternative cookies
889
+ }else if( ctPublicFunctions.data__cookies_type === 'alternative' && ! skip_alt ){
890
+
891
+ if (typeof (getJavascriptClientData) === "function"){
892
+ //reprocess already gained cookies data
893
+ cookies = getJavascriptClientData(cookies);
894
+ } else {
895
+ console.log('APBCT ERROR: getJavascriptClientData() is not loaded')
896
+ }
897
+
898
+ try {
899
+ JSON.parse(cookies)
900
+ } catch (e){
901
+ console.log('APBCT ERROR: JSON parse error:' + e)
902
+ return
903
+ }
904
+
905
+ // Using REST API handler
906
+ if( ctPublicFunctions.data__ajax_type === 'rest' ){
907
+ apbct_public_sendREST(
908
+ 'alt_sessions',
909
+ {
910
+ method: 'POST',
911
+ data: { cookies: cookies }
912
+ }
913
+ );
914
+
915
+ // Using AJAX request and handler
916
+ } else if( ctPublicFunctions.data__ajax_type === 'admin_ajax' ) {
917
+ apbct_public_sendAJAX(
918
+ {
919
+ action: 'apbct_alt_session__save__AJAX',
920
+ cookies: cookies,
921
+ },
922
+ {
923
+ notJson: 1,
924
+ }
925
+ );
926
+ }
927
+ }
928
+ }
929
+
930
+ /**
931
+ * Get cookie by name
932
+ * @param name
933
+ * @returns {string|undefined}
934
+ */
935
+ function ctGetCookie(name) {
936
+ var matches = document.cookie.match(new RegExp(
937
+ "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
938
+ ));
939
+ return matches ? decodeURIComponent(matches[1]) : undefined;
940
+ }
941
+
942
+ function ctDeleteCookie(cookieName) {
943
+ // Cookies disabled
944
+ if( ctPublicFunctions.data__cookies_type === 'none' ){
945
+ return;
946
+
947
+ // Using traditional cookies
948
+ }else if( ctPublicFunctions.data__cookies_type === 'native' ){
949
+
950
+ var ctSecure = location.protocol === 'https:' ? '; secure' : '';
951
+ document.cookie = cookieName + "=\"\"; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; samesite=lax" + ctSecure;
952
+
953
+ // Using alternative cookies
954
+ }else if( ctPublicFunctions.data__cookies_type === 'alternative' ){
955
+ // @ToDo implement this logic
956
+ }
957
+ }
958
+
959
+ function apbct_public_sendAJAX(data, params, obj){
960
+
961
+ // Default params
962
+ let _params = [];
963
+ _params["callback"] = params.callback || null;
964
+ _params["onErrorCallback"] = params.onErrorCallback || null;
965
+ _params["callback_context"] = params.callback_context || null;
966
+ _params["callback_params"] = params.callback_params || null;
967
+ _params["async"] = params.async || true;
968
+ _params["notJson"] = params.notJson || null;
969
+ _params["timeout"] = params.timeout || 15000;
970
+ _params["obj"] = obj || null;
971
+ _params["button"] = params.button || null;
972
+ _params["progressbar"] = params.progressbar || null;
973
+ _params["silent"] = params.silent || null;
974
+ _params["no_nonce"] = params.no_nonce || null;
975
+ _params["data"] = data;
976
+ _params["url"] = ctPublicFunctions._ajax_url;
977
+
978
+ if(typeof (data) === 'string') {
979
+ if( ! _params["no_nonce"] ) {
980
+ _params["data"] = _params["data"] + '&_ajax_nonce=' + ctPublicFunctions._ajax_nonce;
981
+ }
982
+ _params["data"] = _params["data"] + '&no_cache=' + Math.random()
983
+ } else {
984
+ if( ! _params["no_nonce"] ) {
985
+ _params["data"]._ajax_nonce = ctPublicFunctions._ajax_nonce;
986
+ }
987
+ _params["data"].no_cache = Math.random();
988
+ }
989
+
990
+ new ApbctCore().ajax(_params);
991
+ }
992
+
993
+ function apbct_public_sendREST( route, params ) {
994
+
995
+ let _params = [];
996
+ _params["route"] = route;
997
+ _params["callback"] = params.callback || null;
998
+ _params["onErrorCallback"] = params.onErrorCallback || null;
999
+ _params["data"] = params.data || [];
1000
+ _params["method"] = params.method || 'POST';
1001
+
1002
+ new ApbctCore().rest(_params);
1003
+ }
1004
+
1005
+ apbctLocalStorage = {
1006
+ get : function(key, property) {
1007
+ if ( typeof property === 'undefined' ) {
1008
+ property = 'value';
1009
+ }
1010
+ const storageValue = localStorage.getItem(key);
1011
+ if ( storageValue !== null ) {
1012
+ try {
1013
+ const json = JSON.parse(storageValue);
1014
+ return json.hasOwnProperty(property) ? JSON.parse(json[property]) : json;
1015
+ } catch (e) {
1016
+ return storageValue;
1017
+ }
1018
+ }
1019
+ return false;
1020
+ },
1021
+ set : function(key, value, is_json = true) {
1022
+ if (is_json){
1023
+ let objToSave = {'value': JSON.stringify(value), 'timestamp': Math.floor(new Date().getTime() / 1000)};
1024
+ localStorage.setItem(key, JSON.stringify(objToSave));
1025
+ } else {
1026
+ localStorage.setItem(key, value);
1027
+ }
1028
+ },
1029
+ isAlive : function(key, maxLifetime) {
1030
+ if ( typeof maxLifetime === 'undefined' ) {
1031
+ maxLifetime = 86400;
1032
+ }
1033
+ const keyTimestamp = this.get(key, 'timestamp');
1034
+ return keyTimestamp + maxLifetime > Math.floor(new Date().getTime() / 1000);
1035
+ },
1036
+ isSet : function(key) {
1037
+ return localStorage.getItem(key) !== null;
1038
+ },
1039
+ delete : function (key) {
1040
+ localStorage.removeItem(key);
1041
+ },
1042
+ getCleanTalkData : function () {
1043
+ let data = {}
1044
+ for(let i=0; i<localStorage.length; i++) {
1045
+ let key = localStorage.key(i);
1046
+ if (key.indexOf('ct_') !==-1 || key.indexOf('apbct_') !==-1){
1047
+ data[key.toString()] = apbctLocalStorage.get(key)
1048
+ }
1049
+ }
1050
+ return data
1051
+ },
1052
+
1053
+ }
1054
+ var ct_date = new Date(),
1055
+ ctTimeMs = new Date().getTime(),
1056
+ ctMouseEventTimerFlag = true, //Reading interval flag
1057
+ ctMouseData = [],
1058
+ ctMouseDataCounter = 0,
1059
+ ctCheckedEmails = {};
1060
+
1061
+ function apbct_attach_event_handler(elem, event, callback){
1062
+ if(typeof window.addEventListener === "function") elem.addEventListener(event, callback);
1063
+ else elem.attachEvent(event, callback);
1064
+ }
1065
+
1066
+ function apbct_remove_event_handler(elem, event, callback){
1067
+ if(typeof window.removeEventListener === "function") elem.removeEventListener(event, callback);
1068
+ else elem.detachEvent(event, callback);
1069
+ }
1070
+
1071
+ //Writing first key press timestamp
1072
+ var ctFunctionFirstKey = function output(event){
1073
+ var KeyTimestamp = Math.floor(new Date().getTime()/1000);
1074
+ ctSetCookie("ct_fkp_timestamp", KeyTimestamp);
1075
+ ctKeyStopStopListening();
1076
+ };
1077
+
1078
+ //Reading interval
1079
+ var ctMouseReadInterval = setInterval(function(){
1080
+ ctMouseEventTimerFlag = true;
1081
+ }, 150);
1082
+
1083
+ //Writting interval
1084
+ var ctMouseWriteDataInterval = setInterval(function(){
1085
+ ctSetCookie("ct_pointer_data", JSON.stringify(ctMouseData));
1086
+ }, 1200);
1087
+
1088
+ //Logging mouse position each 150 ms
1089
+ var ctFunctionMouseMove = function output(event){
1090
+ ctSetMouseMoved();
1091
+ if(ctMouseEventTimerFlag === true){
1092
+
1093
+ ctMouseData.push([
1094
+ Math.round(event.clientY),
1095
+ Math.round(event.clientX),
1096
+ Math.round(new Date().getTime() - ctTimeMs)
1097
+ ]);
1098
+
1099
+ ctMouseDataCounter++;
1100
+ ctMouseEventTimerFlag = false;
1101
+ if(ctMouseDataCounter >= 50){
1102
+ ctMouseStopData();
1103
+ }
1104
+ }
1105
+ };
1106
+
1107
+ //Stop mouse observing function
1108
+ function ctMouseStopData(){
1109
+ apbct_remove_event_handler(window, "mousemove", ctFunctionMouseMove);
1110
+ clearInterval(ctMouseReadInterval);
1111
+ clearInterval(ctMouseWriteDataInterval);
1112
+ }
1113
+
1114
+ //Stop key listening function
1115
+ function ctKeyStopStopListening(){
1116
+ apbct_remove_event_handler(window, "mousedown", ctFunctionFirstKey);
1117
+ apbct_remove_event_handler(window, "keydown", ctFunctionFirstKey);
1118
+ }
1119
+
1120
+ function checkEmail(e) {
1121
+ var current_email = e.target.value;
1122
+ if (current_email && !(current_email in ctCheckedEmails)) {
1123
+ // Using REST API handler
1124
+ if( ctPublicFunctions.data__ajax_type === 'rest' ){
1125
+ apbct_public_sendREST(
1126
+ 'check_email_before_post',
1127
+ {
1128
+ method: 'POST',
1129
+ data: {'email' : current_email},
1130
+ callback: function (result) {
1131
+ if (result.result) {
1132
+ ctCheckedEmails[current_email] = {'result' : result.result, 'timestamp': Date.now() / 1000 |0};
1133
+ ctSetCookie('ct_checked_emails', JSON.stringify(ctCheckedEmails));
1134
+ }
1135
+ },
1136
+ }
1137
+ );
1138
+ // Using AJAX request and handler
1139
+ } else if( ctPublicFunctions.data__ajax_type === 'admin_ajax' ) {
1140
+ apbct_public_sendAJAX(
1141
+ {
1142
+ action: 'apbct_email_check_before_post',
1143
+ email : current_email,
1144
+ },
1145
+ {
1146
+ callback: function (result) {
1147
+ if (result.result) {
1148
+ ctCheckedEmails[current_email] = {'result' : result.result, 'timestamp': Date.now() / 1000 |0};
1149
+ ctSetCookie('ct_checked_emails', JSON.stringify(ctCheckedEmails));
1150
+ }
1151
+ },
1152
+ }
1153
+ );
1154
+ }
1155
+ }
1156
+ }
1157
+
1158
+ function ctSetPixelImg(pixelUrl) {
1159
+ ctSetCookie('apbct_pixel_url', pixelUrl);
1160
+ if( +ctPublic.pixel__enabled ){
1161
+ if( ! document.getElementById('apbct_pixel') ) {
1162
+ let insertedImg = document.createElement('img');
1163
+ insertedImg.setAttribute('alt', 'CleanTalk Pixel');
1164
+ insertedImg.setAttribute('id', 'apbct_pixel');
1165
+ insertedImg.setAttribute('style', 'display: none; left: 99999px;');
1166
+ insertedImg.setAttribute('src', pixelUrl);
1167
+ apbct('body').append(insertedImg);
1168
+ }
1169
+ }
1170
+ }
1171
+
1172
+ function ctGetPixelUrl() {
1173
+ // Check if pixel is already in localstorage and is not outdated
1174
+ let local_storage_pixel_url = apbctLocalStorage.get('apbct_pixel_url');
1175
+ if ( local_storage_pixel_url !== false ) {
1176
+ if ( apbctLocalStorage.isAlive('apbct_pixel_url', 3600 * 3) ) {
1177
+ apbctLocalStorage.delete('apbct_pixel_url')
1178
+ } else {
1179
+ //if so - load pixel from localstorage and draw it skipping AJAX
1180
+ ctSetPixelImg(local_storage_pixel_url);
1181
+ return;
1182
+ }
1183
+ }
1184
+ // Using REST API handler
1185
+ if( ctPublicFunctions.data__ajax_type === 'rest' ){
1186
+ apbct_public_sendREST(
1187
+ 'apbct_get_pixel_url',
1188
+ {
1189
+ method: 'POST',
1190
+ callback: function (result) {
1191
+ if (result) {
1192
+ //set pixel url to localstorage
1193
+ if ( ! apbctLocalStorage.get('apbct_pixel_url') ){
1194
+ //set pixel to the storage
1195
+ apbctLocalStorage.set('apbct_pixel_url', result)
1196
+ //update pixel data in the hidden fields
1197
+ ctNoCookieAttachHiddenFieldsToForms()
1198
+ }
1199
+ //then run pixel drawing
1200
+ ctSetPixelImg(result);
1201
+ }
1202
+ },
1203
+ }
1204
+ );
1205
+ // Using AJAX request and handler
1206
+ }else{
1207
+ apbct_public_sendAJAX(
1208
+ {
1209
+ action: 'apbct_get_pixel_url',
1210
+ },
1211
+ {
1212
+ notJson: true,
1213
+ callback: function (result) {
1214
+ if (result) {
1215
+ //set pixel url to localstorage
1216
+ if ( ! apbctLocalStorage.get('apbct_pixel_url') ){
1217
+ //set pixel to the storage
1218
+ apbctLocalStorage.set('apbct_pixel_url', result)
1219
+ //update pixel data in the hidden fields
1220
+ ctNoCookieAttachHiddenFieldsToForms()
1221
+ }
1222
+ //then run pixel drawing
1223
+ ctSetPixelImg(result);
1224
+ }
1225
+ },
1226
+ }
1227
+ );
1228
+ }
1229
+ }
1230
+
1231
+ function ctSetHasScrolled() {
1232
+ if( ! apbctLocalStorage.isSet('ct_has_scrolled') || ! apbctLocalStorage.get('ct_has_scrolled') ) {
1233
+ ctSetCookie("ct_has_scrolled", 'true');
1234
+ apbctLocalStorage.set('ct_has_scrolled', true);
1235
+ }
1236
+ }
1237
+
1238
+ function ctSetMouseMoved() {
1239
+ if( ! apbctLocalStorage.isSet('ct_mouse_moved') || ! apbctLocalStorage.get('ct_mouse_moved') ) {
1240
+ ctSetCookie("ct_mouse_moved", 'true');
1241
+ apbctLocalStorage.set('ct_mouse_moved', true);
1242
+ }
1243
+ }
1244
+
1245
+ function ctPreloadLocalStorage(){
1246
+ if (ctPublic.data__to_local_storage){
1247
+ let data = Object.entries(ctPublic.data__to_local_storage)
1248
+ data.forEach(([key, value]) => {
1249
+ apbctLocalStorage.set(key,value)
1250
+ });
1251
+ }
1252
+ }
1253
+
1254
+ apbct_attach_event_handler(window, "mousemove", ctFunctionMouseMove);
1255
+ apbct_attach_event_handler(window, "mousedown", ctFunctionFirstKey);
1256
+ apbct_attach_event_handler(window, "keydown", ctFunctionFirstKey);
1257
+ apbct_attach_event_handler(window, "scroll", ctSetHasScrolled);
1258
+
1259
+ // Ready function
1260
+ function apbct_ready(){
1261
+
1262
+ ctPreloadLocalStorage()
1263
+
1264
+ let cookiesType = apbctLocalStorage.get('ct_cookies_type');
1265
+ if ( ! cookiesType || cookiesType !== ctPublic.data__cookies_type ) {
1266
+ apbctLocalStorage.set('ct_cookies_type', ctPublic.data__cookies_type);
1267
+ apbctLocalStorage.delete('ct_mouse_moved');
1268
+ apbctLocalStorage.delete('ct_has_scrolled');
1269
+ }
1270
+
1271
+ // Collect scrolling info
1272
+ var initCookies = [
1273
+ ["ct_ps_timestamp", Math.floor(new Date().getTime() / 1000)],
1274
+ ["ct_fkp_timestamp", "0"],
1275
+ ["ct_pointer_data", "0"],
1276
+ ["ct_timezone", ct_date.getTimezoneOffset()/60*(-1) ],
1277
+ ["ct_screen_info", apbctGetScreenInfo()],
1278
+ ["apbct_headless", navigator.webdriver],
1279
+ ];
1280
+
1281
+ apbctLocalStorage.set('ct_ps_timestamp', Math.floor(new Date().getTime() / 1000));
1282
+ apbctLocalStorage.set('ct_fkp_timestamp', "0");
1283
+ apbctLocalStorage.set('ct_pointer_data', "0");
1284
+ apbctLocalStorage.set('ct_timezone', ct_date.getTimezoneOffset()/60*(-1) );
1285
+ apbctLocalStorage.set('ct_screen_info', apbctGetScreenInfo());
1286
+ apbctLocalStorage.set('apbct_headless', navigator.webdriver);
1287
+
1288
+ if( ctPublic.data__cookies_type !== 'native' ) {
1289
+ initCookies.push(['apbct_visible_fields', '0']);
1290
+ } else {
1291
+ // Delete all visible fields cookies on load the page
1292
+ var cookiesArray = document.cookie.split(";");
1293
+ if( cookiesArray.length !== 0 ) {
1294
+ for ( var i = 0; i < cookiesArray.length; i++ ) {
1295
+ var currentCookie = cookiesArray[i].trim();
1296
+ var cookieName = currentCookie.split("=")[0];
1297
+ if( cookieName.indexOf("apbct_visible_fields_") === 0 ) {
1298
+ ctDeleteCookie(cookieName);
1299
+ }
1300
+ }
1301
+ }
1302
+ }
1303
+
1304
+ if( +ctPublic.pixel__setting ){
1305
+ if( +ctPublic.pixel__enabled ){
1306
+ ctGetPixelUrl()
1307
+ } else {
1308
+ initCookies.push(['apbct_pixel_url', ctPublic.pixel__url]);
1309
+ }
1310
+ }
1311
+
1312
+ if ( +ctPublic.data__email_check_before_post) {
1313
+ initCookies.push(['ct_checked_emails', '0']);
1314
+ apbct("input[type = 'email'], #email").on('blur', checkEmail);
1315
+ }
1316
+
1317
+ if (apbctLocalStorage.isSet('ct_checkjs')) {
1318
+ initCookies.push(['ct_checkjs', apbctLocalStorage.get('ct_checkjs')]);
1319
+ } else {
1320
+ initCookies.push(['ct_checkjs', 0]);
1321
+ }
1322
+
1323
+ ctSetCookie(initCookies);
1324
+
1325
+ setTimeout(function(){
1326
+
1327
+ ctNoCookieAttachHiddenFieldsToForms()
1328
+
1329
+ for(var i = 0; i < document.forms.length; i++){
1330
+ var form = document.forms[i];
1331
+
1332
+ //Exclusion for forms
1333
+ if (
1334
+ +ctPublic.data__visible_fields_required === 0 ||
1335
+ form.method.toString().toLowerCase() === 'get' ||
1336
+ form.classList.contains('slp_search_form') || //StoreLocatorPlus form
1337
+ form.parentElement.classList.contains('mec-booking') ||
1338
+ form.action.toString().indexOf('activehosted.com') !== -1 || // Active Campaign
1339
+ (form.id && form.id === 'caspioform') || //Caspio Form
1340
+ (form.classList && form.classList.contains('tinkoffPayRow')) || // TinkoffPayForm
1341
+ (form.classList && form.classList.contains('give-form')) || // GiveWP
1342
+ (form.id && form.id === 'ult-forgot-password-form') || //ult forgot password
1343
+ (form.id && form.id.toString().indexOf('calculatedfields') !== -1) || // CalculatedFieldsForm
1344
+ (form.id && form.id.toString().indexOf('sac-form') !== -1) || // Simple Ajax Chat
1345
+ (form.id && form.id.toString().indexOf('cp_tslotsbooking_pform') !== -1) || // WP Time Slots Booking Form
1346
+ (form.name && form.name.toString().indexOf('cp_tslotsbooking_pform') !== -1) || // WP Time Slots Booking Form
1347
+ form.action.toString() === 'https://epayment.epymtservice.com/epay.jhtml' || // Custom form
1348
+ (form.name && form.name.toString().indexOf('tribe-bar-form') !== -1) // The Events Calendar
1349
+ ) {
1350
+ continue;
1351
+ }
1352
+
1353
+ var hiddenInput = document.createElement( 'input' );
1354
+ hiddenInput.setAttribute( 'type', 'hidden' );
1355
+ hiddenInput.setAttribute( 'id', 'apbct_visible_fields_' + i );
1356
+ hiddenInput.setAttribute( 'name', 'apbct_visible_fields');
1357
+ var visibleFieldsToInput = {};
1358
+ visibleFieldsToInput[0] = apbct_collect_visible_fields(form);
1359
+ hiddenInput.value = JSON.stringify(visibleFieldsToInput);
1360
+ form.append( hiddenInput );
1361
+
1362
+ form.onsubmit_prev = form.onsubmit;
1363
+
1364
+ form.ctFormIndex = i;
1365
+ form.onsubmit = function (event) {
1366
+
1367
+ if ( ctPublic.data__cookies_type !== 'native' && typeof event.target.ctFormIndex !== 'undefined' ) {
1368
+
1369
+ var visible_fields = {};
1370
+ visible_fields[0] = apbct_collect_visible_fields(this);
1371
+ console.log("visible_fields[0]" + visible_fields[0])
1372
+ apbct_visible_fields_set_cookie( visible_fields, event.target.ctFormIndex );
1373
+ }
1374
+
1375
+ // Call previous submit action
1376
+ if (event.target.onsubmit_prev instanceof Function) {
1377
+ setTimeout(function () {
1378
+ event.target.onsubmit_prev.call(event.target, event);
1379
+ }, 500);
1380
+ }
1381
+ };
1382
+ }
1383
+
1384
+ }, 1000);
1385
+
1386
+ // Listen clicks on encoded emails
1387
+ let decodedEmailNodes = document.querySelectorAll("[data-original-string]");
1388
+ if (decodedEmailNodes.length) {
1389
+ for (let i = 0; i < decodedEmailNodes.length; ++i) {
1390
+ if (
1391
+ decodedEmailNodes[i].parentElement.href ||
1392
+ decodedEmailNodes[i].parentElement.parentElement.href
1393
+ ) {
1394
+ // Skip listening click on hyperlinks
1395
+ continue;
1396
+ }
1397
+ decodedEmailNodes[i].addEventListener('click', ctFillDecodedEmailHandler);
1398
+ }
1399
+ }
1400
+ }
1401
+ apbct_attach_event_handler(window, "DOMContentLoaded", apbct_ready);
1402
+
1403
+ function ctFillDecodedEmailHandler(event) {
1404
+ this.removeEventListener('click', ctFillDecodedEmailHandler);
1405
+ apbctAjaxEmailDecode(event, this);
1406
+ }
1407
+
1408
+ function apbctAjaxEmailDecode(event, baseElement){
1409
+ const element = event.target;
1410
+ const javascriptClientData = getJavascriptClientData();
1411
+ let data = {
1412
+ event_javascript_data: javascriptClientData,
1413
+ post_url: document.location.href,
1414
+ referrer: document.referrer,
1415
+ };
1416
+
1417
+ if (typeof baseElement.href !== 'undefined' && baseElement.href.indexOf('mailto:') === 0) {
1418
+ event.preventDefault();
1419
+ } else {
1420
+ element.setAttribute('title', ctPublicFunctions.text__wait_for_decoding);
1421
+ element.style.cursor = 'progress';
1422
+
1423
+ // Adding a tooltip
1424
+ let apbctTooltip = document.createElement('div');
1425
+ apbctTooltip.setAttribute('class', 'apbct-tooltip');
1426
+ let apbctTooltipText = document.createElement('div');
1427
+ apbctTooltipText.setAttribute('class', 'apbct-tooltip--text');
1428
+ let apbctTooltipArrow = document.createElement('div');
1429
+ apbctTooltipArrow.setAttribute('class', 'apbct-tooltip--arrow');
1430
+ apbct(element).append(apbctTooltip);
1431
+ apbct(apbctTooltip).append(apbctTooltipText);
1432
+ apbct(apbctTooltip).append(apbctTooltipArrow);
1433
+ ctShowDecodeComment(element, ctPublicFunctions.text__wait_for_decoding);
1434
+ }
1435
+
1436
+ let encodedEmail = event.target.dataset.originalString;
1437
+
1438
+ if (typeof baseElement.href !== 'undefined' && baseElement.href.indexOf('mailto:') === 0) {
1439
+ encodedEmail = baseElement.dataset.originalString;
1440
+ }
1441
+
1442
+ data.encodedEmail = encodedEmail;
1443
+
1444
+ // Using REST API handler
1445
+ if( ctPublicFunctions.data__ajax_type === 'rest' ){
1446
+ apbct_public_sendREST(
1447
+ 'apbct_decode_email',
1448
+ {
1449
+ data: data,
1450
+ method: 'POST',
1451
+ callback: function (result) {
1452
+ if (result.success) {
1453
+ if (typeof baseElement.href !== 'undefined' && baseElement.href.indexOf('mailto:') === 0) {
1454
+ let encodedEmail = baseElement.href.replace('mailto:', '');
1455
+ let baseElementContent = baseElement.innerHTML;
1456
+ baseElement.innerHTML = baseElementContent.replace(encodedEmail, result.data.decoded_email);
1457
+ baseElement.href = 'mailto:' + result.data.decoded_email;
1458
+ baseElement.click();
1459
+ } else {
1460
+ setTimeout(function(){
1461
+ ctProcessDecodedDataResult(result.data, event.target);
1462
+ }, 3000);
1463
+ }
1464
+ }
1465
+ setTimeout(function () {
1466
+ apbct(element.getElementsByClassName('apbct-tooltip')).fadeOut(700);
1467
+ }, 4000);
1468
+ },
1469
+ onErrorCallback: function (res) {
1470
+ element.addEventListener('click', ctFillDecodedEmailHandler);
1471
+ element.removeAttribute('style');
1472
+ ctShowDecodeComment(element, 'Error occurred: ' + res);
1473
+ },
1474
+ }
1475
+ );
1476
+
1477
+ // Using AJAX request and handler
1478
+ }else{
1479
+ data.action = 'apbct_decode_email';
1480
+ apbct_public_sendAJAX(
1481
+ data,
1482
+ {
1483
+ notJson: true,
1484
+ callback: function (result) {
1485
+ if (result.success) {
1486
+ if (typeof baseElement.href !== 'undefined' && baseElement.href.indexOf('mailto:') === 0) {
1487
+ let encodedEmail = baseElement.href.replace('mailto:', '');
1488
+ let baseElementContent = baseElement.innerHTML;
1489
+ baseElement.innerHTML = baseElementContent.replace(encodedEmail, result.data.decoded_email);
1490
+ baseElement.href = 'mailto:' + result.data.decoded_email;
1491
+ baseElement.click();
1492
+ } else {
1493
+ setTimeout(function(){
1494
+ ctProcessDecodedDataResult(result.data, event.target);
1495
+ }, 3000);
1496
+ }
1497
+ }
1498
+ setTimeout(function () {
1499
+ apbct(element.getElementsByClassName('apbct-tooltip')).fadeOut(700);
1500
+ }, 4000);
1501
+ },
1502
+ onErrorCallback: function (res) {
1503
+ element.addEventListener('click', ctFillDecodedEmailHandler);
1504
+ element.removeAttribute('style');
1505
+ ctShowDecodeComment(element, 'Error occurred: ' + res);
1506
+ },
1507
+ }
1508
+ );
1509
+ }
1510
+ }
1511
+
1512
+ function getJavascriptClientData(common_cookies = []) {
1513
+ let resultDataJson = {};
1514
+
1515
+ resultDataJson.apbct_headless = ctGetCookie(ctPublicFunctions.cookiePrefix + 'apbct_headless');
1516
+ resultDataJson.apbct_pixel_url = ctGetCookie(ctPublicFunctions.cookiePrefix + 'apbct_pixel_url');
1517
+ resultDataJson.ct_checked_emails = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_checked_emails');
1518
+ resultDataJson.ct_checkjs = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_checkjs');
1519
+ resultDataJson.ct_fkp_timestamp = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_fkp_timestamp');
1520
+ resultDataJson.ct_pointer_data = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_pointer_data');
1521
+ resultDataJson.ct_ps_timestamp = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_ps_timestamp');
1522
+ resultDataJson.ct_screen_info = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_screen_info');
1523
+ resultDataJson.ct_timezone = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_timezone');
1524
+
1525
+ // collecting data from localstorage
1526
+ const ctMouseMovedLocalStorage = apbctLocalStorage.get(ctPublicFunctions.cookiePrefix + 'ct_mouse_moved');
1527
+ const ctHasScrolledLocalStorage = apbctLocalStorage.get(ctPublicFunctions.cookiePrefix + 'ct_has_scrolled');
1528
+ const ctCookiesTypeLocalStorage = apbctLocalStorage.get(ctPublicFunctions.cookiePrefix + 'ct_cookies_type');
1529
+
1530
+ // collecting data from cookies
1531
+ const ctMouseMovedCookie = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_mouse_moved');
1532
+ const ctHasScrolledCookie = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_has_scrolled');
1533
+ const ctCookiesTypeCookie = ctGetCookie(ctPublicFunctions.cookiePrefix + 'ct_cookies_type');
1534
+
1535
+ resultDataJson.ct_mouse_moved = ctMouseMovedLocalStorage !== undefined ? ctMouseMovedLocalStorage : ctMouseMovedCookie;
1536
+ resultDataJson.ct_has_scrolled = ctHasScrolledLocalStorage !== undefined ? ctHasScrolledLocalStorage : ctHasScrolledCookie;
1537
+ resultDataJson.ct_cookies_type = ctCookiesTypeLocalStorage !== undefined ? ctCookiesTypeLocalStorage : ctCookiesTypeCookie;
1538
+
1539
+ if (
1540
+ typeof (common_cookies) === "object"
1541
+ && common_cookies !== []
1542
+ ){
1543
+ for (let i = 0; i < common_cookies.length; ++i){
1544
+ if ( typeof (common_cookies[i][1]) === "object" ){
1545
+ //this is for handle SFW cookies
1546
+ resultDataJson[common_cookies[i][1][0]] = common_cookies[i][1][1]
1547
+ } else {
1548
+ resultDataJson[common_cookies[i][0]] = common_cookies[i][1]
1549
+ }
1550
+ }
1551
+ } else {
1552
+ console.log('APBCT JS ERROR: Collecting data type mismatch')
1553
+ }
1554
+
1555
+ // Parse JSON properties to prevent double JSON encoding
1556
+ resultDataJson = removeDoubleJsonEncoding(resultDataJson);
1557
+
1558
+ return JSON.stringify(resultDataJson);
1559
+ }
1560
+
1561
+ /**
1562
+ * Recursive
1563
+ *
1564
+ * Recursively decode JSON-encoded properties
1565
+ *
1566
+ * @param object
1567
+ * @returns {*}
1568
+ */
1569
+ function removeDoubleJsonEncoding(object){
1570
+
1571
+ if( typeof object === 'object'){
1572
+
1573
+ for (let objectKey in object) {
1574
+
1575
+ // Recursion
1576
+ if( typeof object[objectKey] === 'object'){
1577
+ object[objectKey] = removeDoubleJsonEncoding(object[objectKey]);
1578
+ }
1579
+
1580
+ // Common case (out)
1581
+ if(
1582
+ typeof object[objectKey] === 'string' &&
1583
+ object[objectKey].match(/^[\[{].*?[\]}]$/) !== null // is like JSON
1584
+ ){
1585
+ let parsedValue = JSON.parse(object[objectKey]);
1586
+ if( typeof parsedValue === 'object' ){
1587
+ object[objectKey] = parsedValue;
1588
+ }
1589
+ }
1590
+ }
1591
+ }
1592
+
1593
+ return object;
1594
+ }
1595
+
1596
+ function ctProcessDecodedDataResult(response, targetElement) {
1597
+
1598
+ targetElement.setAttribute('title', '');
1599
+ targetElement.removeAttribute('style');
1600
+
1601
+ if( !! response.is_allowed) {
1602
+ ctFillDecodedEmail(targetElement, response.decoded_email);
1603
+ }
1604
+
1605
+ if( !! response.show_comment ){
1606
+ ctShowDecodeComment(targetElement, response.comment);
1607
+ }
1608
+ }
1609
+
1610
+ function ctFillDecodedEmail(target, email){
1611
+ apbct(target).html(
1612
+ apbct(target)
1613
+ .html()
1614
+ .replace(/.+?(<div class=["']apbct-tooltip["'].+?<\/div>)/, email + "$1")
1615
+ );
1616
+ }
1617
+
1618
+ function ctShowDecodeComment(target, comment){
1619
+
1620
+ if( ! comment ){
1621
+ return;
1622
+ }
1623
+
1624
+ apbct(target.getElementsByClassName('apbct-tooltip')).fadeIn(300);
1625
+ apbct(target.getElementsByClassName('apbct-tooltip--text')).html(comment);
1626
+ setTimeout(function(){
1627
+ apbct(target.getElementsByClassName('apbct-tooltip')).fadeOut(700);
1628
+ }, 5000);
1629
+ }
1630
+
1631
+ function apbct_collect_visible_fields( form ) {
1632
+
1633
+ // Get only fields
1634
+ var inputs = [],
1635
+ inputs_visible = '',
1636
+ inputs_visible_count = 0,
1637
+ inputs_invisible = '',
1638
+ inputs_invisible_count = 0,
1639
+ inputs_with_duplicate_names = [];
1640
+
1641
+ for(var key in form.elements){
1642
+ if(!isNaN(+key))
1643
+ inputs[key] = form.elements[key];
1644
+ }
1645
+
1646
+ // Filter fields
1647
+ inputs = inputs.filter(function(elem){
1648
+
1649
+ // Filter already added fields
1650
+ if( inputs_with_duplicate_names.indexOf( elem.getAttribute('name') ) !== -1 ){
1651
+ return false;
1652
+ }
1653
+ // Filter inputs with same names for type == radio
1654
+ if( -1 !== ['radio', 'checkbox'].indexOf( elem.getAttribute("type") )){
1655
+ inputs_with_duplicate_names.push( elem.getAttribute('name') );
1656
+ return false;
1657
+ }
1658
+ return true;
1659
+ });
1660
+
1661
+ // Visible fields
1662
+ inputs.forEach(function(elem, i, elements){
1663
+ // Unnecessary fields
1664
+ if(
1665
+ elem.getAttribute("type") === "submit" || // type == submit
1666
+ elem.getAttribute('name') === null ||
1667
+ elem.getAttribute('name') === 'ct_checkjs'
1668
+ ) {
1669
+ return;
1670
+ }
1671
+ // Invisible fields
1672
+ if(
1673
+ getComputedStyle(elem).display === "none" || // hidden
1674
+ getComputedStyle(elem).visibility === "hidden" || // hidden
1675
+ getComputedStyle(elem).opacity === "0" || // hidden
1676
+ elem.getAttribute("type") === "hidden" // type == hidden
1677
+ ) {
1678
+ if( elem.classList.contains("wp-editor-area") ) {
1679
+ inputs_visible += " " + elem.getAttribute("name");
1680
+ inputs_visible_count++;
1681
+ } else {
1682
+ inputs_invisible += " " + elem.getAttribute("name");
1683
+ inputs_invisible_count++;
1684
+ }
1685
+ }
1686
+ // Visible fields
1687
+ else {
1688
+ inputs_visible += " " + elem.getAttribute("name");
1689
+ inputs_visible_count++;
1690
+ }
1691
+
1692
+ });
1693
+
1694
+ inputs_invisible = inputs_invisible.trim();
1695
+ inputs_visible = inputs_visible.trim();
1696
+
1697
+ return {
1698
+ visible_fields : inputs_visible,
1699
+ visible_fields_count : inputs_visible_count,
1700
+ invisible_fields : inputs_invisible,
1701
+ invisible_fields_count : inputs_invisible_count,
1702
+ }
1703
+
1704
+ }
1705
+
1706
+ function apbct_visible_fields_set_cookie( visible_fields_collection, form_id ) {
1707
+
1708
+ var collection = typeof visible_fields_collection === 'object' && visible_fields_collection !== null ? visible_fields_collection : {};
1709
+
1710
+ if( ctPublic.data__cookies_type === 'native' ) {
1711
+ for ( var i in collection ) {
1712
+ if ( i > 10 ) {
1713
+ // Do not generate more than 10 cookies
1714
+ return;
1715
+ }
1716
+ var collectionIndex = form_id !== undefined ? form_id : i;
1717
+ ctSetCookie("apbct_visible_fields_" + collectionIndex, JSON.stringify( collection[i] ) );
1718
+ }
1719
+ } else {
1720
+ if (ctPublic.data__cookies_type === 'none'){
1721
+ ctSetCookie("apbct_visible_fields", JSON.stringify( collection[0] ) );
1722
+ } else {
1723
+ ctSetCookie("apbct_visible_fields", JSON.stringify( collection ) );
1724
+ }
1725
+
1726
+ }
1727
+ }
1728
+
1729
+ function apbct_js_keys__set_input_value(result, data, params, obj){
1730
+ if( document.querySelectorAll('[name^=ct_checkjs]').length > 0 ) {
1731
+ var elements = document.querySelectorAll('[name^=ct_checkjs]');
1732
+ for ( var i = 0; i < elements.length; i++ ) {
1733
+ elements[i].value = result.js_key;
1734
+ }
1735
+ }
1736
+ }
1737
+
1738
+ function apbctGetScreenInfo() {
1739
+ return JSON.stringify({
1740
+ fullWidth : document.documentElement.scrollWidth,
1741
+ fullHeight : Math.max(
1742
+ document.body.scrollHeight, document.documentElement.scrollHeight,
1743
+ document.body.offsetHeight, document.documentElement.offsetHeight,
1744
+ document.body.clientHeight, document.documentElement.clientHeight
1745
+ ),
1746
+ visibleWidth : document.documentElement.clientWidth,
1747
+ visibleHeight : document.documentElement.clientHeight,
1748
+ });
1749
+ }
1750
+
1751
+ if(typeof jQuery !== 'undefined') {
1752
+
1753
+ // Capturing responses and output block message for unknown AJAX forms
1754
+ jQuery(document).ajaxComplete(function (event, xhr, settings) {
1755
+ if (xhr.responseText && xhr.responseText.indexOf('"apbct') !== -1) {
1756
+ try {
1757
+ var response = JSON.parse(responseText);
1758
+ } catch (e) {
1759
+ console.log(e.toString());
1760
+ return;
1761
+ }
1762
+ ctParseBlockMessage(response);
1763
+ }
1764
+ });
1765
+ }
1766
+
1767
+ function ctParseBlockMessage(response) {
1768
+
1769
+ if (typeof response.apbct !== 'undefined') {
1770
+ response = response.apbct;
1771
+ if (response.blocked) {
1772
+ document.dispatchEvent(
1773
+ new CustomEvent( "apbctAjaxBockAlert", {
1774
+ bubbles: true,
1775
+ detail: { message: response.comment }
1776
+ } )
1777
+ );
1778
+
1779
+ // Show the result by modal
1780
+ cleantalkModal.loaded = response.comment;
1781
+ cleantalkModal.open();
1782
+
1783
+ if(+response.stop_script == 1)
1784
+ window.stop();
1785
+ }
1786
+ }
1787
+ }
1788
+
1789
+ function ctSetPixelUrlLocalstorage(ajax_pixel_url) {
1790
+ //set pixel to the storage
1791
+ ctSetCookie('apbct_pixel_url', ajax_pixel_url)
1792
+ }
1793
+
1794
+ function ctNoCookieConstructHiddenField(){
1795
+ let field = ''
1796
+ let no_cookie_data = apbctLocalStorage.getCleanTalkData()
1797
+ no_cookie_data = JSON.stringify(no_cookie_data)
1798
+ no_cookie_data = btoa(no_cookie_data)
1799
+ field = document.createElement('input')
1800
+ field.setAttribute('id','ct_no_cookie_hidden_field')
1801
+ field.setAttribute('name','ct_no_cookie_hidden_field')
1802
+ field.setAttribute('value', no_cookie_data)
1803
+ field.setAttribute('type', 'hidden')
1804
+ return field
1805
+ }
1806
+
1807
+ function ctNoCookieGetForms(){
1808
+ let forms = document.forms
1809
+ if (forms) {
1810
+ return forms
1811
+ }
1812
+ return false
1813
+ }
1814
+
1815
+ function ctNoCookieAttachHiddenFieldsToForms(){
1816
+
1817
+ if (ctPublic.data__cookies_type !== 'none'){
1818
+ return
1819
+ }
1820
+
1821
+ let forms = ctNoCookieGetForms()
1822
+
1823
+ if (forms){
1824
+ for ( let i = 0; i < forms.length; i++ ){
1825
+ //ignore forms with get method @todo We need to think about this
1826
+ if (document.forms[i].getAttribute('method') === null ||
1827
+ document.forms[i].getAttribute('method').toLowerCase() === 'post'){
1828
+
1829
+ let elements = document.getElementsByName('ct_no_cookie_hidden_field')
1830
+ //clear previous hidden set
1831
+ if (elements){
1832
+ for (let j = 0; j < elements.length; j++) {
1833
+ elements[j].parentNode.removeChild(elements[j])
1834
+ }
1835
+ }
1836
+ // add new set
1837
+ document.forms[i].append(ctNoCookieConstructHiddenField())
1838
+ }
1839
+ }
1840
+ }
1841
+
1842
+ }
1843
+ /* Cleantalk Modal object */
1844
+ cleantalkModal = {
1845
+
1846
+ // Flags
1847
+ loaded: false,
1848
+ loading: false,
1849
+ opened: false,
1850
+ opening: false,
1851
+
1852
+ // Methods
1853
+ load: function( action ) {
1854
+ if( ! this.loaded ) {
1855
+ this.loading = true;
1856
+ callback = function( result, data, params, obj ) {
1857
+ cleantalkModal.loading = false;
1858
+ cleantalkModal.loaded = result;
1859
+ document.dispatchEvent(
1860
+ new CustomEvent( "cleantalkModalContentLoaded", {
1861
+ bubbles: true,
1862
+ } )
1863
+ );
1864
+ };
1865
+ if( typeof apbct_admin_sendAJAX === "function" ) {
1866
+ apbct_admin_sendAJAX( { 'action' : action }, { 'callback': callback, 'notJson': true } );
1867
+ } else {
1868
+ apbct_public_sendAJAX( { 'action' : action }, { 'callback': callback, 'notJson': true } );
1869
+ }
1870
+
1871
+ }
1872
+ },
1873
+
1874
+ open: function () {
1875
+ /* Cleantalk Modal CSS start */
1876
+ var renderCss = function () {
1877
+ var cssStr = '';
1878
+ for ( key in this.styles ) {
1879
+ cssStr += key + ':' + this.styles[key] + ';';
1880
+ }
1881
+ return cssStr;
1882
+ };
1883
+ var overlayCss = {
1884
+ styles: {
1885
+ "z-index": "9999",
1886
+ "position": "fixed",
1887
+ "top": "0",
1888
+ "left": "0",
1889
+ "width": "100%",
1890
+ "height": "100%",
1891
+ "background": "rgba(0,0,0,0.5)",
1892
+ "display": "flex",
1893
+ "justify-content" : "center",
1894
+ "align-items" : "center",
1895
+ },
1896
+ toString: renderCss
1897
+ };
1898
+ var innerCss = {
1899
+ styles: {
1900
+ "position" : "relative",
1901
+ "padding" : "30px",
1902
+ "background" : "#FFF",
1903
+ "border" : "1px solid rgba(0,0,0,0.75)",
1904
+ "border-radius" : "4px",
1905
+ "box-shadow" : "7px 7px 5px 0px rgba(50,50,50,0.75)",
1906
+ },
1907
+ toString: renderCss
1908
+ };
1909
+ var closeCss = {
1910
+ styles: {
1911
+ "position" : "absolute",
1912
+ "background" : "#FFF",
1913
+ "width" : "20px",
1914
+ "height" : "20px",
1915
+ "border" : "2px solid rgba(0,0,0,0.75)",
1916
+ "border-radius" : "15px",
1917
+ "cursor" : "pointer",
1918
+ "top" : "-8px",
1919
+ "right" : "-8px",
1920
+ "box-sizing" : "content-box",
1921
+ },
1922
+ toString: renderCss
1923
+ };
1924
+ var closeCssBefore = {
1925
+ styles: {
1926
+ "content" : "\"\"",
1927
+ "display" : "block",
1928
+ "position" : "absolute",
1929
+ "background" : "#000",
1930
+ "border-radius" : "1px",
1931
+ "width" : "2px",
1932
+ "height" : "16px",
1933
+ "top" : "2px",
1934
+ "left" : "9px",
1935
+ "transform" : "rotate(45deg)",
1936
+ },
1937
+ toString: renderCss
1938
+ };
1939
+ var closeCssAfter = {
1940
+ styles: {
1941
+ "content" : "\"\"",
1942
+ "display" : "block",
1943
+ "position" : "absolute",
1944
+ "background" : "#000",
1945
+ "border-radius" : "1px",
1946
+ "width" : "2px",
1947
+ "height" : "16px",
1948
+ "top" : "2px",
1949
+ "left" : "9px",
1950
+ "transform" : "rotate(-45deg)",
1951
+ },
1952
+ toString: renderCss
1953
+ };
1954
+ var bodyCss = {
1955
+ styles: {
1956
+ "overflow" : "hidden",
1957
+ },
1958
+ toString: renderCss
1959
+ };
1960
+ var cleantalkModalStyle = document.createElement( 'style' );
1961
+ cleantalkModalStyle.setAttribute( 'id', 'cleantalk-modal-styles' );
1962
+ cleantalkModalStyle.innerHTML = 'body.cleantalk-modal-opened{' + bodyCss + '}';
1963
+ cleantalkModalStyle.innerHTML += '#cleantalk-modal-overlay{' + overlayCss + '}';
1964
+ cleantalkModalStyle.innerHTML += '#cleantalk-modal-close{' + closeCss + '}';
1965
+ cleantalkModalStyle.innerHTML += '#cleantalk-modal-close:before{' + closeCssBefore + '}';
1966
+ cleantalkModalStyle.innerHTML += '#cleantalk-modal-close:after{' + closeCssAfter + '}';
1967
+ document.body.append( cleantalkModalStyle );
1968
+ /* Cleantalk Modal CSS end */
1969
+
1970
+ var overlay = document.createElement( 'div' );
1971
+ overlay.setAttribute( 'id', 'cleantalk-modal-overlay' );
1972
+ document.body.append( overlay );
1973
+
1974
+ document.body.classList.add( 'cleantalk-modal-opened' );
1975
+
1976
+ var inner = document.createElement( 'div' );
1977
+ inner.setAttribute( 'id', 'cleantalk-modal-inner' );
1978
+ inner.setAttribute( 'style', innerCss );
1979
+ overlay.append( inner );
1980
+
1981
+ var close = document.createElement( 'div' );
1982
+ close.setAttribute( 'id', 'cleantalk-modal-close' );
1983
+ inner.append( close );
1984
+
1985
+ var content = document.createElement( 'div' );
1986
+ if ( this.loaded ) {
1987
+ content.innerHTML = this.loaded;
1988
+ } else {
1989
+ content.innerHTML = 'Loading...';
1990
+ // @ToDo Here is hardcoded parameter. Have to get this from a 'data-' attribute.
1991
+ this.load( 'get_options_template' );
1992
+ }
1993
+ content.setAttribute( 'id', 'cleantalk-modal-content' );
1994
+ inner.append( content );
1995
+
1996
+ this.opened = true;
1997
+ },
1998
+
1999
+ close: function () {
2000
+ document.body.classList.remove( 'cleantalk-modal-opened' );
2001
+ document.getElementById( 'cleantalk-modal-overlay' ).remove();
2002
+ document.getElementById( 'cleantalk-modal-styles' ).remove();
2003
+ document.dispatchEvent(
2004
+ new CustomEvent( "cleantalkModalClosed", {
2005
+ bubbles: true,
2006
+ } )
2007
+ );
2008
+ }
2009
+
2010
+ };
2011
+
2012
+ /* Cleantalk Modal helpers */
2013
+ document.addEventListener('click',function( e ){
2014
+ if( e.target && e.target.id === 'cleantalk-modal-overlay' || e.target.id === 'cleantalk-modal-close' ){
2015
+ cleantalkModal.close();
2016
+ }
2017
+ });
2018
+ document.addEventListener("cleantalkModalContentLoaded", function( e ) {
2019
+ if( cleantalkModal.opened && cleantalkModal.loaded ) {
2020
+ document.getElementById( 'cleantalk-modal-content' ).innerHTML = cleantalkModal.loaded;
2021
+ }
2022
+ });
2023
+ let buttons_to_handle = []
2024
+ let gdpr_notice_for_button = 'Please, apply the GDPR agreement.'
2025
+
2026
+ document.addEventListener('DOMContentLoaded', function(){
2027
+ buttons_to_handle = []
2028
+ if(
2029
+ typeof ctPublicGDPR === 'undefined' ||
2030
+ ! ctPublicGDPR.gdpr_forms.length
2031
+ ) {
2032
+ return;
2033
+ }
2034
+
2035
+ if ( typeof jQuery === 'undefined' ) {
2036
+ return;
2037
+ }
2038
+ try {
2039
+ ctPublicGDPR.gdpr_forms.forEach(function(item, i){
2040
+
2041
+ let elem = jQuery('#'+item+', .'+item);
2042
+
2043
+ // Filter forms
2044
+ if (!elem.is('form')){
2045
+ // Caldera
2046
+ if (elem.find('form')[0])
2047
+ elem = elem.children('form').first();
2048
+ // Contact Form 7
2049
+ else if(
2050
+ jQuery('.wpcf7[role=form]')[0] && jQuery('.wpcf7[role=form]')
2051
+ .attr('id')
2052
+ .indexOf('wpcf7-f'+item) !== -1
2053
+ ) {
2054
+ elem = jQuery('.wpcf7[role=form]').children('form');
2055
+ }
2056
+
2057
+ // Formidable
2058
+ else if(jQuery('.frm_forms')[0] && jQuery('.frm_forms').first().attr('id').indexOf('frm_form_'+item) !== -1)
2059
+ elem = jQuery('.frm_forms').first().children('form');
2060
+ // WPForms
2061
+ else if(jQuery('.wpforms-form')[0] && jQuery('.wpforms-form').first().attr('id').indexOf('wpforms-form-'+item) !== -1)
2062
+ elem = jQuery('.wpforms-form');
2063
+ }
2064
+
2065
+ //disable forms buttons
2066
+ let button = false
2067
+ let buttons_collection= elem.find('input[type|="submit"]')
2068
+
2069
+ if (!buttons_collection.length) {
2070
+ return
2071
+ } else {
2072
+ button = buttons_collection[0]
2073
+ }
2074
+
2075
+ if (button !== false){
2076
+ console.log(buttons_collection)
2077
+ button.disabled = true
2078
+ let old_notice = jQuery(button).prop('title') ? jQuery(button).prop('title') : ''
2079
+ buttons_to_handle.push({index:i,button:button,old_notice:old_notice})
2080
+ jQuery(button).prop('title', gdpr_notice_for_button)
2081
+ }
2082
+
2083
+ // Adding notice and checkbox
2084
+ if(elem.is('form') || elem.attr('role') === 'form'){
2085
+ elem.append('<input id="apbct_gdpr_'+i+'" type="checkbox" required="required" style=" margin-right: 10px;" onchange="apbct_gdpr_handle_buttons()">')
2086
+ .append('<label style="display: inline;" for="apbct_gdpr_'+i+'">'+ctPublicGDPR.gdpr_text+'</label>');
2087
+ }
2088
+ });
2089
+ } catch (e) {
2090
+ console.info('APBCT GDPR JS ERROR: Can not add GDPR notice' + e)
2091
+ }
2092
+ });
2093
+
2094
+ function apbct_gdpr_handle_buttons(){
2095
+
2096
+ try {
2097
+
2098
+ if (buttons_to_handle === []){
2099
+ return
2100
+ }
2101
+
2102
+ buttons_to_handle.forEach((button) => {
2103
+ let selector = '[id="apbct_gdpr_' + button.index + '"]'
2104
+ let apbct_gdpr_item = jQuery(selector)
2105
+ //chek if apbct_gdpr checkbox is set
2106
+ if (jQuery(apbct_gdpr_item).prop("checked")){
2107
+ button.button.disabled = false
2108
+ jQuery(button.button).prop('title', button.old_notice)
2109
+ } else {
2110
+ button.button.disabled = true
2111
+ jQuery(button.button).prop('title', gdpr_notice_for_button)
2112
+ }
2113
+ })
2114
+ } catch (e) {
2115
+ console.info('APBCT GDPR JS ERROR: Can not handle form buttons ' + e)
2116
+ }
2117
+ }
2118
+ /**
2119
+ * Handle external forms
2120
+ */
2121
+ function ct_protect_external() {
2122
+ for(var i = 0; i < document.forms.length; i++) {
2123
+
2124
+ if (document.forms[i].cleantalk_hidden_action === undefined && document.forms[i].cleantalk_hidden_method === undefined) {
2125
+
2126
+ // current form
2127
+ var currentForm = document.forms[i];
2128
+
2129
+ if (currentForm.parentElement && currentForm.parentElement.classList.length > 0 && currentForm.parentElement.classList[0].indexOf('mewtwo') !== -1){
2130
+ return
2131
+ }
2132
+
2133
+ if(typeof(currentForm.action) == 'string') {
2134
+
2135
+ // Ajax checking for the integrated forms
2136
+ if(isIntegratedForm(currentForm)) {
2137
+
2138
+ var cleantalk_placeholder = document.createElement("i");
2139
+ cleantalk_placeholder.className = 'cleantalk_placeholder';
2140
+ cleantalk_placeholder.style = 'display: none';
2141
+ currentForm.parentElement.insertBefore(cleantalk_placeholder, currentForm);
2142
+
2143
+ // Deleting form to prevent submit event
2144
+ var prev = currentForm.previousSibling,
2145
+ form_html = currentForm.outerHTML,
2146
+ form_original = currentForm;
2147
+
2148
+ // Remove the original form
2149
+ currentForm.parentElement.removeChild(currentForm);
2150
+
2151
+ // Insert a clone
2152
+ const placeholder = document.createElement("div");
2153
+ placeholder.innerHTML = form_html;
2154
+ prev.after(placeholder.firstElementChild);
2155
+
2156
+ var force_action = document.createElement("input");
2157
+ force_action.name = 'action';
2158
+ force_action.value = 'cleantalk_force_ajax_check';
2159
+ force_action.type = 'hidden';
2160
+
2161
+ let reUseCurrentForm = document.forms[i];
2162
+
2163
+ reUseCurrentForm.appendChild(force_action);
2164
+ reUseCurrentForm.apbctPrev = prev;
2165
+ reUseCurrentForm.apbctFormOriginal = form_original;
2166
+
2167
+ // mailerlite integration - disable click on submit button
2168
+ let mailerlite_detected_class = false
2169
+ if (reUseCurrentForm.classList !== undefined) {
2170
+ //list there all the mailerlite classes
2171
+ let mailerlite_classes = ['newsletterform', 'ml-block-form']
2172
+ mailerlite_classes.forEach(function(mailerlite_class) {
2173
+ if (reUseCurrentForm.classList.contains(mailerlite_class)){
2174
+ mailerlite_detected_class = mailerlite_class
2175
+ }
2176
+ });
2177
+ }
2178
+ if ( mailerlite_detected_class ) {
2179
+ let mailerliteSubmitButton = jQuery('form.' + mailerlite_detected_class).find('button[type="submit"]');
2180
+ if ( mailerliteSubmitButton !== undefined ) {
2181
+ mailerliteSubmitButton.click(function (event) {
2182
+ event.preventDefault();
2183
+ sendAjaxCheckingFormData(event.currentTarget);
2184
+ });
2185
+ }
2186
+ } else {
2187
+ document.forms[i].onsubmit = function ( event ){
2188
+ event.preventDefault();
2189
+
2190
+ const prev = jQuery(event.currentTarget).prev();
2191
+ const form_original = jQuery(event.currentTarget).clone();
2192
+
2193
+ sendAjaxCheckingFormData(event.currentTarget);
2194
+ };
2195
+ }
2196
+
2197
+ // Common flow - modify form's action
2198
+ }else if(currentForm.action.indexOf('http://') !== -1 || currentForm.action.indexOf('https://') !== -1) {
2199
+
2200
+ var tmp = currentForm.action.split('//');
2201
+ tmp = tmp[1].split('/');
2202
+ var host = tmp[0].toLowerCase();
2203
+
2204
+ if(host !== location.hostname.toLowerCase()){
2205
+
2206
+ var ct_action = document.createElement("input");
2207
+ ct_action.name = 'cleantalk_hidden_action';
2208
+ ct_action.value = currentForm.action;
2209
+ ct_action.type = 'hidden';
2210
+ currentForm.appendChild(ct_action);
2211
+
2212
+ var ct_method = document.createElement("input");
2213
+ ct_method.name = 'cleantalk_hidden_method';
2214
+ ct_method.value = currentForm.method;
2215
+ ct_method.type = 'hidden';
2216
+
2217
+ currentForm.method = 'POST'
2218
+
2219
+ currentForm.appendChild(ct_method);
2220
+
2221
+ currentForm.action = document.location;
2222
+ }
2223
+ }
2224
+ }
2225
+ }
2226
+
2227
+ }
2228
+ }
2229
+ function apbct_replace_inputs_values_from_other_form( form_source, form_target ){
2230
+
2231
+ var inputs_source = jQuery( form_source ).find( 'button, input, textarea, select' ),
2232
+ inputs_target = jQuery( form_target ).find( 'button, input, textarea, select' );
2233
+
2234
+ inputs_source.each( function( index, elem_source ){
2235
+
2236
+ var source = jQuery( elem_source );
2237
+
2238
+ inputs_target.each( function( index2, elem_target ){
2239
+
2240
+ var target = jQuery( elem_target );
2241
+
2242
+ if( elem_source.outerHTML === elem_target.outerHTML ){
2243
+
2244
+ target.val( source.val() );
2245
+ }
2246
+ });
2247
+ });
2248
+
2249
+ }
2250
+ window.onload = function () {
2251
+
2252
+ if( ! +ctPublic.settings__forms__check_external ) {
2253
+ return;
2254
+ }
2255
+
2256
+ if ( typeof jQuery === 'undefined' ) {
2257
+ return;
2258
+ }
2259
+
2260
+ setTimeout(function () {
2261
+ ct_protect_external()
2262
+ }, 1500);
2263
+ };
2264
+
2265
+ /**
2266
+ * Checking the form integration
2267
+ */
2268
+ function isIntegratedForm(formObj) {
2269
+ var formAction = formObj.action;
2270
+
2271
+ if(
2272
+ formAction.indexOf('activehosted.com') !== -1 || // ActiveCampaign form
2273
+ formAction.indexOf('app.convertkit.com') !== -1 || // ConvertKit form
2274
+ ( formObj.firstChild.classList !== undefined && formObj.firstChild.classList.contains('cb-form-group') ) || // Convertbox form
2275
+ formAction.indexOf('mailerlite.com') !== -1 || // Mailerlite integration
2276
+ formAction.indexOf('colcolmail.co.uk') !== -1 || // colcolmail.co.uk integration
2277
+ formAction.indexOf('paypal.com') !== -1 ||
2278
+ formAction.indexOf('infusionsoft.com') !== -1 ||
2279
+ formAction.indexOf('webto.salesforce.com') !== -1 ||
2280
+ formAction.indexOf('secure2.convio.net') !== -1 ||
2281
+ formAction.indexOf('hookb.in') !== -1 ||
2282
+ formAction.indexOf('external.url') !== -1 ||
2283
+ formAction.indexOf('tp.media') !== -1 ||
2284
+ formAction.indexOf('flodesk.com') !== -1 ||
2285
+ formAction.indexOf('sendfox.com') !== -1 ||
2286
+ formAction.indexOf('aweber.com') !== -1 ||
2287
+ formAction.indexOf('secure.payu.com') !== -1
2288
+
2289
+ ) {
2290
+ return true;
2291
+ }
2292
+
2293
+ return false;
2294
+ }
2295
+
2296
+ /**
2297
+ * Sending Ajax for checking form data
2298
+ */
2299
+ function sendAjaxCheckingFormData(form, prev, formOriginal) {
2300
+ // Get visible fields and set cookie
2301
+ var visible_fields = {};
2302
+ visible_fields[0] = apbct_collect_visible_fields(form);
2303
+ apbct_visible_fields_set_cookie( visible_fields );
2304
+
2305
+ var data = {};
2306
+ var elems = form.elements;
2307
+ elems = Array.prototype.slice.call(elems);
2308
+
2309
+ elems.forEach( function( elem, y ) {
2310
+ if( elem.name === '' ) {
2311
+ data['input_' + y] = elem.value;
2312
+ } else {
2313
+ data[elem.name] = elem.value;
2314
+ }
2315
+ });
2316
+
2317
+ apbct_public_sendAJAX(
2318
+ data,
2319
+ {
2320
+ async: false,
2321
+ callback: function( result, data, params, obj ){
2322
+
2323
+ if( result.apbct === undefined || ! +result.apbct.blocked ) {
2324
+
2325
+ let form_new = jQuery(form).detach();
2326
+ let prev = form.apbctPrev;
2327
+ let formOriginal = form.apbctFormOriginal;
2328
+
2329
+ apbct_replace_inputs_values_from_other_form(form_new, formOriginal);
2330
+
2331
+ prev.after( formOriginal );
2332
+
2333
+ // Clear visible_fields input
2334
+ jQuery(formOriginal).find('input[name="apbct_visible_fields"]').remove();
2335
+ jQuery(formOriginal).find('input[value="cleantalk_force_ajax_check"]').remove();
2336
+
2337
+ // Common click event
2338
+ var subm_button = jQuery(formOriginal).find('button[type=submit]');
2339
+ if( subm_button.length !== 0 ) {
2340
+ subm_button[0].click();
2341
+ return;
2342
+ }
2343
+
2344
+ subm_button = jQuery(formOriginal).find('input[type=submit]');
2345
+ if( subm_button.length !== 0 ) {
2346
+ subm_button[0].click();
2347
+ return;
2348
+ }
2349
+
2350
+ // ConvertKit direct integration
2351
+ subm_button = jQuery(formOriginal).find('button[data-element="submit"]');
2352
+ if( subm_button.length !== 0 ) {
2353
+ subm_button[0].click();
2354
+ return;
2355
+ }
2356
+
2357
+ // Paypal integration
2358
+ subm_button = jQuery(formOriginal).find('input[type="image"][name="submit"]');
2359
+ if( subm_button.length !== 0 ) {
2360
+ subm_button[0].click();
2361
+ }
2362
+
2363
+ }
2364
+ if (result.apbct !== undefined && +result.apbct.blocked) {
2365
+ ctParseBlockMessage(result);
2366
+ }
2367
+ }
2368
+ }
2369
+ );
2370
+ }
2371
+
2372
+ function ct_check_internal(currForm){
2373
+
2374
+ //Gathering data
2375
+ var ct_data = {},
2376
+ elems = currForm.elements;
2377
+
2378
+ for (var key in elems) {
2379
+ if(elems[key].type == 'submit' || elems[key].value == undefined || elems[key].value == '')
2380
+ continue;
2381
+ ct_data[elems[key].name] = currForm.elements[key].value;
2382
+ }
2383
+ ct_data['action'] = 'ct_check_internal';
2384
+
2385
+ //AJAX Request
2386
+ apbct_public_sendAJAX(
2387
+ ct_data,
2388
+ {
2389
+ url: ctPublicFunctions._ajax_url,
2390
+ callback: function (data) {
2391
+ if(data.success === true){
2392
+ currForm.submit();
2393
+ }else{
2394
+ alert(data.data);
2395
+ return false;
2396
+ }
2397
+ }
2398
+ }
2399
+ );
2400
+ }
2401
+
2402
+ document.addEventListener('DOMContentLoaded',function(){
2403
+ let ct_currAction = '',
2404
+ ct_currForm = '';
2405
+
2406
+ if( ! +ctPublic.settings__forms__check_internal ) {
2407
+ return;
2408
+ }
2409
+
2410
+ for( let i=0; i<document.forms.length; i++ ){
2411
+ if ( typeof(document.forms[i].action) == 'string' ){
2412
+ ct_currForm = document.forms[i];
2413
+ ct_currAction = ct_currForm.action;
2414
+ if (
2415
+ ct_currAction.indexOf('https?://') !== null && // The protocol is obligatory
2416
+ ct_currAction.match(ctPublic.blog_home + '.*?\.php') !== null && // Main check
2417
+ ! ct_check_internal__is_exclude_form(ct_currAction) // Exclude WordPress native scripts from processing
2418
+ ) {
2419
+ ctPrevHandler = ct_currForm.click;
2420
+ if ( typeof jQuery !== 'undefined' ) {
2421
+ jQuery(ct_currForm).off('**');
2422
+ jQuery(ct_currForm).off();
2423
+ jQuery(ct_currForm).on('submit', function(event){
2424
+ ct_check_internal(event.target);
2425
+ return false;
2426
+ });
2427
+ }
2428
+ }
2429
+ }
2430
+ }
2431
+ });
2432
+
2433
+ /**
2434
+ * Check by action to exclude the form checking
2435
+ * @param action string
2436
+ * @return boolean
2437
+ */
2438
+ function ct_check_internal__is_exclude_form(action) {
2439
+ // An array contains forms action need to be excluded.
2440
+ let ct_internal_script_exclusions = [
2441
+ ctPublic.blog_home + 'wp-login.php', // WordPress login page
2442
+ ctPublic.blog_home + 'wp-comments-post.php', // WordPress Comments Form
2443
+ ];
2444
+
2445
+ return ct_internal_script_exclusions.some((item) => {
2446
+ return action.match(new RegExp('^' + item)) !== null;
2447
+ });
2448
+ }
js/src/cleantalk-admin-settings-page.js ADDED
@@ -0,0 +1,560 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function(){
2
+
3
+ // Top level settings
4
+ jQuery('.apbct_setting---data__email_decoder').on('click', (event) => {
5
+ if ( event.target.type === 'checkbox' ) {
6
+ const postFix = event.target.checked ? '__On' : '__Off';
7
+ document.getElementById('apbct_setting_data__email_decoder' + postFix).checked = true;
8
+ } else {
9
+ document.getElementById('apbct_setting_data__email_decoder').checked = parseInt(event.target.value) === 1;
10
+ }
11
+ });
12
+
13
+ // Crunch for Right to Left direction languages
14
+ if(document.getElementsByClassName('apbct_settings-title')[0]) {
15
+ if(getComputedStyle(document.getElementsByClassName('apbct_settings-title')[0]).direction === 'rtl'){
16
+ jQuery('.apbct_switchers').css('text-align', 'right');
17
+ }
18
+ }
19
+
20
+ // Show/Hide access key
21
+ jQuery('#apbct_showApiKey').on('click', function(){
22
+ jQuery('.apbct_setting---apikey').val(jQuery('.apbct_setting---apikey').attr('key'));
23
+ jQuery('.apbct_setting---apikey+div').show();
24
+ jQuery(this).fadeOut(300);
25
+ });
26
+
27
+ var d = new Date();
28
+ jQuery('#ct_admin_timezone').val(d.getTimezoneOffset()/60*(-1));
29
+
30
+ // Key KEY automatically
31
+ jQuery('#apbct_button__get_key_auto').on('click', function(){
32
+ apbct_admin_sendAJAX(
33
+ {action: 'apbct_get_key_auto'},
34
+ {
35
+ timeout: 25000,
36
+ button: document.getElementById('apbct_button__get_key_auto' ),
37
+ spinner: jQuery('#apbct_button__get_key_auto .apbct_preloader_button' ),
38
+ callback: function(result, data, params, obj){
39
+ jQuery('#apbct_button__get_key_auto .apbct_success').show(300);
40
+ setTimeout(function(){jQuery('#apbct_button__get_key_auto .apbct_success').hide(300);}, 2000);
41
+ if(result.reload)
42
+ document.location.reload();
43
+ if(result.getTemplates) {
44
+ cleantalkModal.loaded = result.getTemplates;
45
+ cleantalkModal.open();
46
+ document.addEventListener("cleantalkModalClosed", function( e ) {
47
+ document.location.reload();
48
+ });
49
+ }
50
+ }
51
+ }
52
+ );
53
+ });
54
+
55
+ // Import settings
56
+ jQuery( document ).on('click', '#apbct_settings_templates_import_button', function(){
57
+ jQuery('#apbct-ajax-result').remove();
58
+ var optionSelected = jQuery('option:selected', jQuery('#apbct_settings_templates_import'));
59
+ var templateNameInput = jQuery('#apbct_settings_templates_import_name');
60
+ templateNameInput.css('border-color', 'inherit');
61
+ if( typeof optionSelected.data('id') === "undefined" ) {
62
+ console.log( 'Attribute "data-id" not set for the option.' );
63
+ return;
64
+ }
65
+ var data = {
66
+ 'template_id' : optionSelected.data('id'),
67
+ 'template_name' : optionSelected.data('name'),
68
+ 'settings' : optionSelected.data('settings')
69
+ };
70
+ var button = this;
71
+ apbct_admin_sendAJAX(
72
+ {action: 'settings_templates_import', data: data},
73
+ {
74
+ timeout: 25000,
75
+ button: button,
76
+ spinner: jQuery('#apbct_settings_templates_import_button .apbct_preloader_button' ),
77
+ notJson: true,
78
+ callback: function(result, data, params, obj){
79
+ if(result.success) {
80
+ jQuery( "<p id='apbct-ajax-result' class='success'>" + result.data + "</p>" ).insertAfter( jQuery(button) );
81
+ jQuery('#apbct_settings_templates_import_button .apbct_success').show(300);
82
+ setTimeout(function(){jQuery('#apbct_settings_templates_import_button .apbct_success').hide(300);}, 2000);
83
+ document.addEventListener("cleantalkModalClosed", function( e ) {
84
+ document.location.reload();
85
+ });
86
+ setTimeout(function(){cleantalkModal.close()}, 2000);
87
+ } else {
88
+ jQuery( "<p id='apbct-ajax-result' class='error'>" + result.data + "</p>" ).insertAfter( jQuery(button) );
89
+ }
90
+ }
91
+ }
92
+ );
93
+ });
94
+
95
+ // Export settings
96
+ jQuery( document ).on('click', '#apbct_settings_templates_export_button', function(){
97
+ jQuery('#apbct-ajax-result').remove();
98
+ var optionSelected = jQuery('option:selected', jQuery('#apbct_settings_templates_export'));
99
+ var templateNameInput = jQuery('#apbct_settings_templates_export_name');
100
+ templateNameInput.css('border-color', 'inherit');
101
+ if( typeof optionSelected.data('id') === "undefined" ) {
102
+ console.log( 'Attribute "data-id" not set for the option.' );
103
+ return;
104
+ }
105
+ if( optionSelected.data('id') === 'new_template' ) {
106
+ var templateName = templateNameInput.val();
107
+ if( templateName === '' ) {
108
+ templateNameInput.css('border-color', 'red');
109
+ return;
110
+ }
111
+ var data = {
112
+ 'template_name' : templateName
113
+ }
114
+ } else {
115
+ var data = {
116
+ 'template_id' : optionSelected.data('id')
117
+ }
118
+ }
119
+ var button = this;
120
+ apbct_admin_sendAJAX(
121
+ {action: 'settings_templates_export', data: data},
122
+ {
123
+ timeout: 25000,
124
+ button: button,
125
+ spinner: jQuery('#apbct_settings_templates_export_button .apbct_preloader_button' ),
126
+ notJson: true,
127
+ callback: function(result, data, params, obj){
128
+ if(result.success) {
129
+ jQuery( "<p id='apbct-ajax-result' class='success'>" + result.data + "</p>" ).insertAfter( jQuery(button) );
130
+ jQuery('#apbct_settings_templates_export_button .apbct_success').show(300);
131
+ setTimeout(function(){jQuery('#apbct_settings_templates_export_button .apbct_success').hide(300);}, 2000);
132
+ document.addEventListener("cleantalkModalClosed", function( e ) {
133
+ document.location.reload();
134
+ });
135
+ setTimeout(function(){cleantalkModal.close()}, 2000);
136
+ } else {
137
+ jQuery( "<p id='apbct-ajax-result' class='error'>" + result.data + "</p>" ).insertAfter( jQuery(button) );
138
+ }
139
+ }
140
+ }
141
+ );
142
+ });
143
+
144
+ // Reset settings
145
+ jQuery( document ).on('click', '#apbct_settings_templates_reset_button', function(){
146
+ var button = this;
147
+ apbct_admin_sendAJAX(
148
+ {action: 'settings_templates_reset'},
149
+ {
150
+ timeout: 25000,
151
+ button: button,
152
+ spinner: jQuery('#apbct_settings_templates_reset_button .apbct_preloader_button' ),
153
+ notJson: true,
154
+ callback: function(result, data, params, obj){
155
+ if(result.success) {
156
+ jQuery( "<p id='apbct-ajax-result' class='success'>" + result.data + "</p>" ).insertAfter( jQuery(button) );
157
+ jQuery('#apbct_settings_templates_reset_button .apbct_success').show(300);
158
+ setTimeout(function(){jQuery('#apbct_settings_templates_reset_button .apbct_success').hide(300);}, 2000);
159
+ document.addEventListener("cleantalkModalClosed", function( e ) {
160
+ document.location.reload();
161
+ });
162
+ setTimeout(function(){cleantalkModal.close()}, 2000);
163
+ } else {
164
+ jQuery( "<p id='apbct-ajax-result' class='error'>" + result.data + "</p>" ).insertAfter( jQuery(button) );
165
+ }
166
+ }
167
+ }
168
+ );
169
+ });
170
+
171
+ // Sync button
172
+ jQuery('#apbct_button__sync').on('click', function(){
173
+ apbct_admin_sendAJAX(
174
+ {action: 'apbct_sync'},
175
+ {
176
+ timeout: 25000,
177
+ button: document.getElementById('apbct_button__sync' ),
178
+ spinner: jQuery('#apbct_button__sync .apbct_preloader_button' ),
179
+ callback: function(result, data, params, obj){
180
+ jQuery('#apbct_button__sync .apbct_success').show(300);
181
+ setTimeout(function(){jQuery('#apbct_button__sync .apbct_success').hide(300);}, 2000);
182
+ if(result.reload)
183
+ document.location.reload();
184
+ }
185
+ }
186
+ );
187
+ });
188
+
189
+ if( ctSettingsPage.key_changed )
190
+ jQuery('#apbct_button__sync').click();
191
+
192
+ jQuery(document).on('click', '.apbct_settings-long_description---show', function(){
193
+ self = jQuery(this);
194
+ apbct_settings__showDescription(self, self.attr('setting'));
195
+ });
196
+
197
+ if (jQuery('#cleantalk_notice_renew').length || jQuery('#cleantalk_notice_trial').length)
198
+ apbct_banner_check();
199
+
200
+ jQuery(document).on('change', '#apbct_settings_templates_export',function(){
201
+ var optionSelected = jQuery("option:selected", this);
202
+ if ( optionSelected.data("id") === 'new_template' ) {
203
+ jQuery(this).parent().parent().find('#apbct_settings_templates_export_name').show();
204
+ } else {
205
+ jQuery(this).parent().parent().find('#apbct_settings_templates_export_name').hide();
206
+ }
207
+ });
208
+
209
+ apbct_save_button_position();
210
+ window.addEventListener('scroll', apbct_save_button_position);
211
+ jQuery('#ct_adv_showhide a').on('click', apbct_save_button_position);
212
+
213
+
214
+ /**
215
+ * Change cleantalk account email
216
+ */
217
+ jQuery('#apbct-change-account-email').on('click', function (e) {
218
+ e.preventDefault();
219
+
220
+ var $this = jQuery(this);
221
+ var accountEmailField = jQuery('#apbct-account-email');
222
+ var accountEmail = accountEmailField.text();
223
+
224
+ $this.toggleClass('active');
225
+
226
+ if ($this.hasClass('active')) {
227
+ $this.text($this.data('save-text'));
228
+ accountEmailField.attr('contenteditable', 'true');
229
+ accountEmailField.on('keydown', function (e) {
230
+ if (e.code === 'Enter') {
231
+ e.preventDefault()
232
+ }
233
+ })
234
+ accountEmailField.on('input', function (e) {
235
+ if (e.inputType === 'insertParagraph') {
236
+ e.preventDefault()
237
+ }
238
+ })
239
+ } else {
240
+ apbct_admin_sendAJAX(
241
+ {
242
+ action: 'apbct_update_account_email',
243
+ accountEmail: accountEmail
244
+ },
245
+ {
246
+ timeout: 5000,
247
+ callback: function(result, data, params, obj){
248
+ if (result.success !== undefined && result.success === 'ok') {
249
+ if (result.manuallyLink !== undefined) {
250
+ jQuery('#apbct-key-manually-link').attr('href', result.manuallyLink);
251
+ }
252
+ }
253
+
254
+ if (result.error !== undefined) {
255
+ jQuery('#apbct-account-email').css('border-color', 'red');
256
+ }
257
+ }
258
+ }
259
+ );
260
+
261
+ accountEmailField.attr('contenteditable', 'false');
262
+ $this.text($this.data('default-text'));
263
+ }
264
+ });
265
+
266
+ /**
267
+ * Validate apkikey and hide get auto btn
268
+ */
269
+ jQuery('#apbct_setting_apikey').on('input', function () {
270
+ var enteredValue = jQuery(this).val();
271
+ jQuery('button.cleantalk_link[value="save_changes"]').off('click')
272
+ if (enteredValue !== '' && enteredValue.match(/^[a-z\d]{3,30}\s*$/) === null) {
273
+ jQuery('#apbct_button__get_key_auto__wrapper').show();
274
+ jQuery('button.cleantalk_link[value="save_changes"]').on('click',
275
+ function (e) {
276
+ e.preventDefault()
277
+ if (!jQuery('#apbct_bad_key_notice').length){
278
+ jQuery( "<div class='apbct_notice_inner error'><h4 id='apbct_bad_key_notice'>" +
279
+ "Please, insert a correct access key before saving changes!" +
280
+ "</h4></div>" ).insertAfter( jQuery('#apbct_setting_apikey') );
281
+ }
282
+ apbct_highlight_element('apbct_setting_apikey',3)
283
+
284
+ }
285
+ )
286
+ return;
287
+ }
288
+
289
+ });
290
+
291
+ if ( jQuery('#apbct_setting_apikey').val() && ctSettingsPage.key_is_ok) {
292
+ jQuery('#apbct_button__get_key_auto__wrapper').hide();
293
+ }
294
+
295
+ /**
296
+ * Handle synchronization errors when key is no ok to force user check the key and restart the sync
297
+ */
298
+ if( !ctSettingsPage.key_is_ok ){
299
+ jQuery('button.cleantalk_link[value="save_changes"]').on('click',
300
+ function (e) {
301
+ e.preventDefault()
302
+ if (!jQuery('#sync_required_notice').length){
303
+ jQuery( "<div class='apbct_notice_inner error'><h4 id='sync_required_notice'>" +
304
+ "Synchronization process failed. Please, check the acces key and restart the synch." +
305
+ "<h4></div>" ).insertAfter( jQuery('#apbct_button__sync') );
306
+ }
307
+ apbct_highlight_element('apbct_setting_apikey',3)
308
+ apbct_highlight_element('apbct_button__sync',3)
309
+ jQuery('#apbct_button__get_key_auto__wrapper').show();
310
+ }
311
+ )
312
+ }
313
+
314
+ });
315
+
316
+ /**
317
+ * Checking current account status for renew notice
318
+ */
319
+ function apbct_banner_check() {
320
+ var bannerChecker = setInterval( function() {
321
+ apbct_admin_sendAJAX(
322
+ {action: 'apbct_settings__check_renew_banner'},
323
+ {
324
+ callback: function(result, data, params, obj){
325
+ if (result.close_renew_banner) {
326
+ if (jQuery('#cleantalk_notice_renew').length)
327
+ jQuery('#cleantalk_notice_renew').hide('slow');
328
+ if (jQuery('#cleantalk_notice_trial').length)
329
+ jQuery('#cleantalk_notice_trial').hide('slow');
330
+ clearInterval(bannerChecker);
331
+ }
332
+ }
333
+ }
334
+ );
335
+ }, 900000);
336
+ }
337
+
338
+ /**
339
+ * Select elems like #{selector} or .{selector}
340
+ * Selector passed in string separated by ,
341
+ *
342
+ * @param elems
343
+ * @returns {*}
344
+ */
345
+ function apbct_get_elems(elems){
346
+ elems = elems.split(',');
347
+ for( var i=0, len = elems.length, tmp; i < len; i++){
348
+ tmp = jQuery('#'+elems[i]);
349
+ elems[i] = tmp.length === 0 ? jQuery('.'+elems[i]) : tmp;
350
+ }
351
+ return elems;
352
+ }
353
+
354
+ /**
355
+ * Select elems like #{selector} or .{selector}
356
+ * Selector could be passed in a string ( separated by comma ) or in array ( [ elem1, elem2, ... ] )
357
+ *
358
+ * @param elems string|array
359
+ * @returns array
360
+ */
361
+ function apbct_get_elems__native(elems){
362
+
363
+ // Make array from a string
364
+ if(typeof elems === 'string')
365
+ elems = elems.split(',');
366
+
367
+ var out = [];
368
+
369
+ elems.forEach(function(elem, i, arr) {
370
+
371
+ // try to get elements with such IDs
372
+ var tmp = document.getElementById(elem);
373
+ if (tmp !== null){
374
+ out.push( tmp[key] );
375
+ return;
376
+ }
377
+
378
+ // try to get elements with such class name
379
+ // write each elem from collection to new element of output array
380
+ tmp = document.getElementsByClassName(elem);
381
+ if (tmp !== null && tmp.length !==0 ){
382
+ for(key in tmp){
383
+ if( +key >= 0 ){
384
+ out.push( tmp[key] );
385
+ }
386
+ }
387
+ }
388
+ });
389
+
390
+ return out;
391
+ }
392
+
393
+ function apbct_show_hide_elem(elems){
394
+ elems = apbct_get_elems(elems);
395
+ for( var i=0, len = elems.length; i < len; i++){
396
+ elems[i].each(function (i, elem) {
397
+ elem = jQuery(elem);
398
+ var label = elem.next('label') || elem.prev('label') || null;
399
+ if (elem.is(":visible")) {
400
+ elem.hide();
401
+ if (label) label.hide();
402
+ } else {
403
+ elem.show();
404
+ if (label) label.show();
405
+ }
406
+ });
407
+ }
408
+ }
409
+
410
+ /**
411
+ * Settings dependences. Switch|toggle depended elements state (disabled|enabled)
412
+ * Recieve list of selectors ( without class mark (.) or id mark (#) )
413
+ *
414
+ * @param ids string|array Selectors
415
+ * @param enable
416
+ */
417
+ function apbctSettingsDependencies(ids, enable){
418
+
419
+
420
+ enable = ! isNaN(enable) ? enable : null;
421
+
422
+ // Get elements
423
+ var elems = apbct_get_elems__native( ids );
424
+
425
+ elems.forEach(function(elem, i, arr){
426
+
427
+ var do_disable = function(){elem.setAttribute('disabled', 'disabled');},
428
+ do_enable = function(){elem.removeAttribute('disabled');};
429
+
430
+ // Set defined state
431
+ if(enable === null) // Set
432
+ enable = elem.getAttribute('disabled') === null ? 0 : 1;
433
+
434
+ enable === 1 ? do_enable() : do_disable();
435
+
436
+ if( elem.getAttribute('apbct_children') !== null){
437
+ var state = apbctSettingsDependencies_getState( elem ) && enable;
438
+ if( state !== null ) {
439
+ apbctSettingsDependencies( elem.getAttribute('apbct_children'), state );
440
+ }
441
+ }
442
+
443
+ });
444
+ }
445
+
446
+ function apbctSettingsDependencies_getState( elem ){
447
+
448
+ var state;
449
+
450
+ switch ( elem.getAttribute( 'type' ) ){
451
+ case 'checkbox':
452
+ state = +elem.checked;
453
+ break;
454
+ case 'radio':
455
+ state = +(+elem.getAttribute('value') === 1);
456
+ break;
457
+ default:
458
+ state = null;
459
+ }
460
+
461
+ return state;
462
+ }
463
+
464
+ function apbct_settings__showDescription(label, setting_id){
465
+
466
+ var remove_desc_func = function(e){
467
+ if(typeof e === 'undefined' || ((jQuery(e.target).parent('.apbct_long_desc').length == 0 || jQuery(e.target).hasClass('apbct_long_desc__cancel')) && !jQuery(e.target).hasClass('apbct_long_description__show'))){
468
+ jQuery('.apbct_long_desc').remove();
469
+ jQuery(document).off('click', remove_desc_func);
470
+ }
471
+ };
472
+
473
+ remove_desc_func();
474
+
475
+ label.after("<div id='apbct_long_desc__"+setting_id+"' class='apbct_long_desc'></div>");
476
+ var obj = jQuery('#apbct_long_desc__'+setting_id);
477
+ obj.append("<i class= 'apbct-icon-spin1 animate-spin'></i>")
478
+ .append("<div class='apbct_long_desc__angle'></div>")
479
+ .css({
480
+ top: label.position().top - 5,
481
+ left: label.position().left + 25
482
+ });
483
+
484
+
485
+ apbct_admin_sendAJAX(
486
+ {action: 'apbct_settings__get__long_description', setting_id: setting_id},
487
+ {
488
+ spinner: obj.children('img'),
489
+ callback: function(result, data, params, obj){
490
+
491
+ obj.empty()
492
+ .append("<div class='apbct_long_desc__angle'></div>")
493
+ .append("<i class='apbct_long_desc__cancel apbct-icon-cancel'></i>")
494
+ .append("<h3 class='apbct_long_desc__title'>"+result.title+"</h3>")
495
+ .append("<p>"+result.desc+"</p>");
496
+
497
+ jQuery(document).on('click', remove_desc_func);
498
+ }
499
+ },
500
+ obj
501
+ );
502
+ }
503
+
504
+ function apbct_save_button_position() {
505
+ if (
506
+ document.getElementById('apbct_settings__before_advanced_settings') === null ||
507
+ document.getElementById('apbct_settings__after_advanced_settings') === null ||
508
+ document.getElementById('apbct_settings__button_section') === null ||
509
+ document.getElementById('apbct_settings__advanced_settings') === null ||
510
+ document.getElementById('apbct_hidden_section_nav') === null
511
+ ) {
512
+ return;
513
+ }
514
+ var docInnerHeight = window.innerHeight;
515
+ var advSettingsBlock = document.getElementById('apbct_settings__advanced_settings');
516
+ var advSettingsOffset = advSettingsBlock.getBoundingClientRect().top;
517
+ var buttonBlock = document.getElementById('apbct_settings__button_section');
518
+ var buttonHeight = buttonBlock.getBoundingClientRect().height;
519
+ var navBlock = document.getElementById('apbct_hidden_section_nav');
520
+ var navBlockOffset = navBlock.getBoundingClientRect().top;
521
+ var navBlockHeight = navBlock.getBoundingClientRect().height;
522
+
523
+ // Set Save button position
524
+ if ( getComputedStyle(advSettingsBlock).display !== "none" ) {
525
+ jQuery('#apbct_settings__main_save_button').hide();
526
+ if ( docInnerHeight < navBlockOffset + navBlockHeight + buttonHeight ) {
527
+ buttonBlock.style.bottom = '';
528
+ buttonBlock.style.top = navBlockOffset + navBlockHeight + 20 + 'px';
529
+ } else {
530
+ buttonBlock.style.bottom = 0;
531
+ buttonBlock.style.top = '';
532
+ }
533
+ } else {
534
+ jQuery('#apbct_settings__main_save_button').show();
535
+ }
536
+
537
+ // Set nav position
538
+ if ( advSettingsOffset <= 0 ) {
539
+ navBlock.style.top = - advSettingsOffset + 30 + 'px';
540
+ } else {
541
+ navBlock.style.top = 0;
542
+ }
543
+ }
544
+
545
+ // Hightlights element
546
+ function apbct_highlight_element(id, times){
547
+ times = times-1 || 0;
548
+ let key_field = jQuery('#'+id)
549
+ jQuery("html, body").animate({ scrollTop: key_field.offset().top - 100 }, "slow");
550
+ key_field.addClass('apbct_highlighted');
551
+ key_field.animate({opacity: 0 }, 400, 'linear', function(){
552
+ key_field.animate({opacity: 1 }, 400, 'linear', function(){
553
+ if(times>0){
554
+ apbct_highlight_element(id, times);
555
+ }else{
556
+ key_field.removeClass('apbct_highlighted');
557
+ }
558
+ });
559
+ });
560
+ }
js/src/cleantalk-admin.js ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function(){
2
+
3
+ // Auto update banner close handler
4
+ jQuery('.apbct_update_notice').on('click', 'button', function(){
5
+ var ct_date = new Date(new Date().getTime() + 1000 * 86400 * 30 );
6
+ var ctSecure = location.protocol === 'https:' ? '; secure' : '';
7
+ document.cookie = "apbct_update_banner_closed=1; path=/; expires=" + ct_date.toUTCString() + "; samesite=lax" + ctSecure;
8
+ });
9
+
10
+ jQuery('li a[href="options-general.php?page=cleantalk"]').css('white-space','nowrap').css('display','inline-block');
11
+
12
+ jQuery('body').on('click', '.apbct-notice .notice-dismiss', function(e){
13
+ var apbct_notice_name = jQuery(e.target).parent().attr('id');
14
+ if( apbct_notice_name ) {
15
+ apbct_admin_sendAJAX( { 'action' : 'cleantalk_dismiss_notice', 'notice_id' : apbct_notice_name }, { 'callback' : null } );
16
+ }
17
+ });
18
+
19
+ // Notice when deleting user
20
+ jQuery('.ct_username .row-actions .delete a').on('click', function (e) {
21
+ e.preventDefault();
22
+
23
+ let result = confirm(ctAdminCommon.notice_when_deleting_user_text);
24
+
25
+ if (result) {
26
+ window.location = this.href
27
+ }
28
+ });
29
+
30
+ });
31
+ function apbct_admin_sendAJAX(data, params, obj){
32
+
33
+ // Default params
34
+ var callback = params.callback || null;
35
+ var callback_context = params.callback_context || null;
36
+ var callback_params = params.callback_params || null;
37
+ var async = params.async || true;
38
+ var notJson = params.notJson || null;
39
+ var timeout = params.timeout || 15000;
40
+ var obj = obj || null;
41
+ var button = params.button || null;
42
+ var spinner = params.spinner || null;
43
+ var progressbar = params.progressbar || null;
44
+
45
+ if(typeof (data) === 'string') {
46
+ data = data + '&_ajax_nonce=' + ctAdminCommon._ajax_nonce + '&no_cache=' + Math.random();
47
+ } else {
48
+ data._ajax_nonce = ctAdminCommon._ajax_nonce;
49
+ data.no_cache = Math.random();
50
+ }
51
+ // Button and spinner
52
+ if(button) {button.setAttribute('disabled', 'disabled'); button.style.cursor = 'not-allowed'; }
53
+ if(spinner) jQuery(spinner).css('display', 'inline');
54
+
55
+ jQuery.ajax({
56
+ type: "POST",
57
+ url: ctAdminCommon._ajax_url,
58
+ data: data,
59
+ async: async,
60
+ success: function(result){
61
+ if(button){ button.removeAttribute('disabled'); button.style.cursor = 'pointer'; }
62
+ if(spinner) jQuery(spinner).css('display', 'none');
63
+ if(!notJson) result = JSON.parse(result);
64
+ if(result.error){
65
+ setTimeout(function(){ if(progressbar) progressbar.fadeOut('slow'); }, 1000);
66
+ if( typeof cleantalkModal !== 'undefined' ) {
67
+ // Show the result by modal
68
+ cleantalkModal.loaded = 'Error:<br>' + result.error.toString();
69
+ cleantalkModal.open();
70
+ } else {
71
+ alert('Error happens: ' + (result.error || 'Unkown'));
72
+ }
73
+
74
+ }else{
75
+ if(callback) {
76
+ if (callback_params)
77
+ callback.apply( callback_context, callback_params.concat( result, data, params, obj ) );
78
+ else
79
+ callback(result, data, params, obj);
80
+ }
81
+ }
82
+ },
83
+ error: function(jqXHR, textStatus, errorThrown){
84
+ if(button){ button.removeAttribute('disabled'); button.style.cursor = 'pointer'; }
85
+ if(spinner) jQuery(spinner).css('display', 'none');
86
+ console.log('APBCT_AJAX_ERROR');
87
+ console.log(jqXHR);
88
+ console.log(textStatus);
89
+ console.log(errorThrown);
90
+ },
91
+ timeout: timeout,
92
+ });
93
+ }
js/src/cleantalk-comments-checkspam.js ADDED
@@ -0,0 +1,455 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Printf for JS
2
+ String.prototype.printf = function(){
3
+ var formatted = this;
4
+ for( var arg in arguments ) {
5
+ var before_formatted = formatted.substring(0, formatted.indexOf("%s", 0));
6
+ var after_formatted = formatted.substring(formatted.indexOf("%s", 0)+2, formatted.length);
7
+ formatted = before_formatted + arguments[arg] + after_formatted;
8
+ }
9
+ return formatted;
10
+ };
11
+
12
+ // Flags
13
+ var ct_working = false,
14
+ ct_new_check = true,
15
+ ct_cooling_down_flag = false,
16
+ ct_close_animate = true,
17
+ ct_accurate_check = false,
18
+ ct_pause = false,
19
+ ct_prev_accurate = ctCommentsCheck.ct_prev_accurate,
20
+ ct_prev_from = ctCommentsCheck.ct_prev_from,
21
+ ct_prev_till = ctCommentsCheck.ct_prev_till;
22
+ // Settings
23
+ var ct_cool_down_time = 90000,
24
+ ct_requests_counter = 0,
25
+ ct_max_requests = 60;
26
+ // Variables
27
+ var ct_ajax_nonce = ctCommentsCheck.ct_ajax_nonce,
28
+ ct_comments_total = 0,
29
+ ct_comments_checked = 0,
30
+ ct_comments_spam = 0,
31
+ ct_comments_bad = 0,
32
+ ct_unchecked = 'unset',
33
+ ct_date_from = 0,
34
+ ct_date_till = 0;
35
+
36
+ function animate_comment(to,id){
37
+ if(ct_close_animate){
38
+ if(to==0.3){
39
+ jQuery('#comment-'+id).fadeTo(200,to,function(){
40
+ animate_comment(1,id)
41
+ });
42
+ }else{
43
+ jQuery('#comment-'+id).fadeTo(200,to,function(){
44
+ animate_comment(0.3,id)
45
+ });
46
+ }
47
+ }else{
48
+ ct_close_animate=true;
49
+ }
50
+ }
51
+
52
+ function ct_clear_comments(){
53
+
54
+ var from = 0, till = 0;
55
+ if(jQuery('#ct_allow_date_range').is(':checked')) {
56
+ from = jQuery('#ct_date_range_from').val();
57
+ till = jQuery('#ct_date_range_till').val();
58
+ }
59
+ var ctSecure = location.protocol === 'https:' ? '; secure' : '';
60
+ document.cookie = 'apbct_check_comments_offset' + "=" + 0 + "; path=/; samesite=lax" + ctSecure;
61
+
62
+ var data = {
63
+ 'action' : 'ajax_clear_comments',
64
+ 'security' : ct_ajax_nonce,
65
+ 'from' : from,
66
+ 'till' : till
67
+ };
68
+
69
+ jQuery.ajax({
70
+ type: "POST",
71
+ url: ajaxurl,
72
+ data: data,
73
+ success: function(msg){
74
+ ct_show_info();
75
+ ct_send_comments();
76
+ }
77
+ });
78
+ }
79
+
80
+ //Continues the check after cooldown time
81
+ //Called by ct_send_users();
82
+ function ct_cooling_down_toggle(){
83
+ ct_cooling_down_flag = false;
84
+ ct_send_comments();
85
+ ct_show_info();
86
+ }
87
+
88
+ function ct_send_comments(){
89
+
90
+ if(ct_cooling_down_flag === true)
91
+ return;
92
+
93
+ if(ct_requests_counter >= ct_max_requests){
94
+ setTimeout(ct_cooling_down_toggle, ct_cool_down_time);
95
+ ct_requests_counter = 0;
96
+ ct_cooling_down_flag = true;
97
+ return;
98
+ }else{
99
+ ct_requests_counter++;
100
+ }
101
+
102
+ var data = {
103
+ 'action': 'ajax_check_comments',
104
+ 'security': ct_ajax_nonce,
105
+ 'new_check': ct_new_check,
106
+ 'unchecked': ct_unchecked,
107
+ 'offset' : Number(ctGetCookie('apbct_check_comments_offset'))
108
+ };
109
+
110
+ if(ct_accurate_check)
111
+ data['accurate_check'] = true;
112
+
113
+ if(ct_date_from && ct_date_till){
114
+ data['from'] = ct_date_from;
115
+ data['till'] = ct_date_till;
116
+ }
117
+
118
+ jQuery.ajax({
119
+ type: "POST",
120
+ url: ajaxurl,
121
+ data: data,
122
+ success: function(msg){
123
+
124
+ msg = jQuery.parseJSON(msg);
125
+
126
+ if(parseInt(msg.error)){
127
+ ct_working=false;
128
+ if(!confirm(msg.error_message+". Do you want to proceed?")){
129
+ var new_href = 'edit-comments.php?page=ct_check_spam';
130
+ if(ct_date_from != 0 && ct_date_till != 0)
131
+ new_href+='&from='+ct_date_from+'&till='+ct_date_till;
132
+ location.href = new_href;
133
+ }else
134
+ ct_send_comments();
135
+ }else{
136
+ ct_new_check = false;
137
+ if(parseInt(msg.end) == 1 || ct_pause === true){
138
+ if(parseInt(msg.end) == 1)
139
+ document.cookie = 'ct_paused_spam_check=0; path=/; samesite=lax';
140
+ ct_working=false;
141
+ jQuery('#ct_working_message').hide();
142
+ var new_href = 'edit-comments.php?page=ct_check_spam';
143
+ if(ct_date_from != 0 && ct_date_till != 0)
144
+ new_href+='&from='+ct_date_from+'&till='+ct_date_till;
145
+ location.href = new_href;
146
+ }else if(parseInt(msg.end) == 0){
147
+ ct_comments_checked += msg.checked;
148
+ ct_comments_spam += msg.spam;
149
+ ct_comments_bad += msg.bad;
150
+ ct_comments_total += msg.total;
151
+ ct_unchecked = ct_comments_total - ct_comments_checked - ct_comments_bad;
152
+ var status_string = String(ctCommentsCheck.ct_status_string);
153
+ var status_string = status_string.printf(ct_comments_checked, ct_comments_spam, ct_comments_bad);
154
+ if(parseInt(ct_comments_spam) > 0)
155
+ status_string += ctCommentsCheck.ct_status_string_warning;
156
+ jQuery('#ct_checking_status').html(status_string);
157
+ jQuery('#ct_error_message').hide();
158
+ // If DB woks not properly
159
+ if(+ct_comments_total < ct_comments_checked + ct_comments_bad){
160
+ document.cookie = 'ct_comments_start_check=1; path=/; samesite=lax';
161
+ location.href = 'edit-comments.php?page=ct_check_spam';
162
+ }
163
+
164
+ var offset = Number(ctGetCookie('apbct_check_comments_offset')) + 100;
165
+ document.cookie = 'apbct_check_comments_offset' + "=" + offset + "; path=/";
166
+
167
+ ct_send_comments();
168
+ }
169
+ }
170
+ },
171
+ error: function(jqXHR, textStatus, errorThrown) {
172
+ jQuery('#ct_error_message').show();
173
+ jQuery('#cleantalk_ajax_error').html(textStatus);
174
+ jQuery('#cleantalk_js_func').html('Check comments');
175
+ setTimeout(ct_send_comments(), 3000);
176
+ },
177
+ timeout: 25000
178
+ });
179
+ }
180
+ function ct_show_info(){
181
+
182
+ if(ct_working){
183
+
184
+ if(ct_cooling_down_flag == true){
185
+ jQuery('#ct_cooling_notice').html('Waiting for API to cool down. (About a minute)');
186
+ jQuery('#ct_cooling_notice').show();
187
+ return;
188
+ }else{
189
+ jQuery('#ct_cooling_notice').hide();
190
+ }
191
+
192
+ if(!ct_comments_total){
193
+
194
+ var data = {
195
+ 'action': 'ajax_info_comments',
196
+ 'security': ct_ajax_nonce
197
+ };
198
+
199
+ if(ct_date_from && ct_date_till){
200
+ data['from'] = ct_date_from;
201
+ data['till'] = ct_date_till;
202
+ }
203
+
204
+ jQuery.ajax({
205
+ type: "POST",
206
+ url: ajaxurl,
207
+ data: data,
208
+ success: function(msg){
209
+ msg = jQuery.parseJSON(msg);
210
+ jQuery('#ct_checking_status').html(msg.message);
211
+ ct_comments_total = msg.total;
212
+ ct_comments_spam = msg.spam;
213
+ ct_comments_checked = msg.checked;
214
+ ct_comments_bad = msg.bad;
215
+ },
216
+ error: function(jqXHR, textStatus, errorThrown) {
217
+ jQuery('#ct_error_message').show();
218
+ jQuery('#cleantalk_ajax_error').html(textStatus);
219
+ jQuery('#cleantalk_js_func').html('Check comments');
220
+ setTimeout(ct_show_info(), 3000);
221
+ },
222
+ timeout: 15000
223
+ });
224
+ }
225
+ }
226
+ }
227
+
228
+ // Function to toggle dependences
229
+ function ct_toggle_depended(obj, secondary){
230
+
231
+ secondary = secondary || null;
232
+
233
+ var depended = jQuery(obj.data('depended')),
234
+ state = obj.data('state');
235
+
236
+ if(!state && !secondary){
237
+ obj.data('state', true);
238
+ depended.removeProp('disabled');
239
+ }else{
240
+ obj.data('state', false);
241
+ depended.prop('disabled', true);
242
+ depended.removeProp('checked');
243
+ if(depended.data('depended'))
244
+ ct_toggle_depended(depended, true);
245
+ }
246
+ }
247
+
248
+ function ct_trash_all( e ) {
249
+
250
+ var data = {
251
+ 'action': 'ajax_trash_all',
252
+ 'security': ct_ajax_nonce
253
+ };
254
+
255
+ jQuery('.' + e.target.id).addClass('disabled');
256
+ jQuery('.spinner').css('visibility', 'visible');
257
+ jQuery.ajax({
258
+ type: "POST",
259
+ url: ajaxurl,
260
+ data: data,
261
+ success: function( msg ){
262
+ if( msg > 0 ){
263
+ jQuery('#cleantalk_comments_left').html(msg);
264
+ ct_trash_all( e );
265
+ }else{
266
+ jQuery('.' + e.target.id).removeClass('disabled');
267
+ jQuery('.spinner').css('visibility', 'hidden');
268
+ location.href='edit-comments.php?page=ct_check_spam';
269
+ }
270
+ },
271
+ error: function(jqXHR, textStatus, errorThrown) {
272
+ jQuery('#ct_error_message').show();
273
+ jQuery('#cleantalk_ajax_error').html(textStatus);
274
+ jQuery('#cleantalk_js_func').html('Check comments');
275
+ setTimeout(ct_trash_all( e ), 3000);
276
+ },
277
+ timeout: 25000
278
+ });
279
+
280
+ }
281
+
282
+ function ct_spam_all( e ) {
283
+
284
+ var data = {
285
+ 'action': 'ajax_spam_all',
286
+ 'security': ct_ajax_nonce
287
+ };
288
+
289
+ jQuery('.' + e.target.id).addClass('disabled');
290
+ jQuery('.spinner').css('visibility', 'visible');
291
+ jQuery.ajax({
292
+ type: "POST",
293
+ url: ajaxurl,
294
+ data: data,
295
+ success: function( msg ){
296
+ if( msg > 0 ){
297
+ jQuery('#cleantalk_comments_left').html(msg);
298
+ ct_spam_all( e );
299
+ }else{
300
+ jQuery('.' + e.target.id).removeClass('disabled');
301
+ jQuery('.spinner').css('visibility', 'hidden');
302
+ location.href='edit-comments.php?page=ct_check_spam';
303
+ }
304
+ },
305
+ error: function(jqXHR, textStatus, errorThrown) {
306
+ jQuery('#ct_error_message').show();
307
+ jQuery('#cleantalk_ajax_error').html(textStatus);
308
+ jQuery('#cleantalk_js_func').html('Check comments');
309
+ setTimeout(ct_spam_all( e ), 3000);
310
+ },
311
+ timeout: 25000
312
+ });
313
+
314
+ }
315
+
316
+ jQuery(document).ready(function(){
317
+
318
+ // Prev check parameters
319
+ if(ct_prev_accurate){
320
+ jQuery("#ct_accurate_check").prop('checked', true);
321
+ }
322
+ if(ct_prev_from){
323
+ jQuery("#ct_allow_date_range").prop('checked', true).data('state', true);
324
+ jQuery("#ct_date_range_from").removeProp('disabled').val(ct_prev_from);
325
+ jQuery("#ct_date_range_till").removeProp('disabled').val(ct_prev_till);
326
+ }
327
+
328
+ // Toggle dependences
329
+ jQuery("#ct_allow_date_range").on('change', function(){
330
+ document.cookie = 'ct_spam_dates_from='+ jQuery('#ct_date_range_from').val() +'; path=/; samesite=lax';
331
+ document.cookie = 'ct_spam_dates_till='+ jQuery('#ct_date_range_till').val() +'; path=/; samesite=lax';
332
+ if( this.checked ) {
333
+ document.cookie = 'ct_spam_dates_allowed=1; path=/; samesite=lax';
334
+ jQuery('.ct_date').prop('checked', true).attr('disabled',false);
335
+ } else {
336
+ document.cookie = 'ct_spam_dates_allowed=0; path=/; samesite=lax';
337
+ jQuery('.ct_date').prop('disabled', true).attr('disabled',true);
338
+ }
339
+ });
340
+
341
+ jQuery.datepicker.setDefaults(jQuery.datepicker.regional['en']);
342
+ var dates = jQuery('#ct_date_range_from, #ct_date_range_till').datepicker(
343
+ {
344
+ dateFormat: 'M d yy',
345
+ maxDate:"+0D",
346
+ changeMonth:true,
347
+ changeYear:true,
348
+ showAnim: 'slideDown',
349
+ onSelect: function(selectedDate){
350
+ var option = this.id == "ct_date_range_from" ? "minDate" : "maxDate",
351
+ instance = jQuery( this ).data( "datepicker" ),
352
+ date = jQuery.datepicker.parseDate(
353
+ instance.settings.dateFormat || jQuery.datepicker._defaults.dateFormat,
354
+ selectedDate, instance.settings);
355
+ dates.not(this).datepicker("option", option, date);
356
+ document.cookie = 'ct_spam_dates_from='+ jQuery('#ct_date_range_from').val() +'; path=/; samesite=lax';
357
+ document.cookie = 'ct_spam_dates_till='+ jQuery('#ct_date_range_till').val() +'; path=/; samesite=lax';
358
+ }
359
+ }
360
+ );
361
+
362
+ function ct_start_check(continue_check){
363
+
364
+ continue_check = continue_check || null;
365
+
366
+ if(jQuery('#ct_allow_date_range').is(':checked')){
367
+
368
+ ct_date_from = jQuery('#ct_date_range_from').val();
369
+ ct_date_till = jQuery('#ct_date_range_till').val();
370
+
371
+ if(!(ct_date_from != '' && ct_date_till != '')){
372
+ alert('Please, specify a date range.');
373
+ return;
374
+ }
375
+ }
376
+
377
+ if(jQuery('#ct_accurate_check').is(':checked')){
378
+ ct_accurate_check = true;
379
+ }
380
+
381
+ jQuery('.ct_to_hide').hide();
382
+ jQuery('#ct_working_message').show();
383
+ jQuery('#ct_preloader').show();
384
+ jQuery('#ct_pause').show();
385
+
386
+ ct_working=true;
387
+
388
+ if(continue_check){
389
+ ct_show_info();
390
+ ct_send_comments();
391
+ }else
392
+ ct_clear_comments();
393
+
394
+ }
395
+
396
+ // Check comments
397
+ jQuery("#ct_check_spam_button").click(function(){
398
+ document.cookie = 'ct_paused_spam_check=0; path=/; samesite=lax';
399
+ ct_start_check(false);
400
+ });
401
+ jQuery("#ct_proceed_check_button").click(function(){
402
+ ct_start_check(true);
403
+ });
404
+
405
+ // Pause the check
406
+ jQuery('#ct_pause').on('click', function(){
407
+ ct_pause = true;
408
+ var ct_check = {
409
+ 'accurate': ct_accurate_check,
410
+ 'from' : ct_date_from,
411
+ 'till' : ct_date_till
412
+ };
413
+ document.cookie = 'ct_paused_spam_check=' + JSON.stringify(ct_check) + '; path=/; samesite=lax';
414
+ });
415
+
416
+
417
+ if(ctCommentsCheck.start === '1'){
418
+ document.cookie = 'ct_comments_start_check=0; expires=' + new Date(0).toUTCString() + '; path=/; samesite=lax';
419
+ jQuery('#ct_check_spam_button').click();
420
+ }
421
+
422
+ // Delete all spam comments
423
+ jQuery(".ct_trash_all").click(function( e ){
424
+
425
+ if (!confirm(ctCommentsCheck.ct_confirm_trash_all))
426
+ return false;
427
+
428
+ ct_trash_all( e );
429
+
430
+ });
431
+
432
+ // Mark as spam all spam comments
433
+ jQuery(".ct_spam_all").click(function( e ){
434
+
435
+ if (!confirm(ctCommentsCheck.ct_confirm_spam_all))
436
+ return false;
437
+
438
+ ct_spam_all( e );
439
+
440
+ });
441
+
442
+ });
443
+
444
+
445
+ /**
446
+ * Get cookie by name
447
+ * @param name
448
+ * @returns {string|undefined}
449
+ */
450
+ function ctGetCookie(name) {
451
+ var matches = document.cookie.match(new RegExp(
452
+ "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
453
+ ));
454
+ return matches ? decodeURIComponent(matches[1]) : undefined;
455
+ }
js/src/cleantalk-comments-editscreen.js ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function ct_is_email(str){
2
+ return str.search(/.*@.*\..*/);
3
+ }
4
+ function ct_is_ip(str){
5
+ return str.search(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
6
+ }
7
+
8
+ jQuery(document).ready(function(){
9
+
10
+ /* Shows link to blacklists near every email and IP address */
11
+ if(parseInt(ctCommentsScreen.ct_show_check_links))
12
+ jQuery('.column-author a, .comment-author a').each(function(){
13
+ var ct_curr_str = jQuery(this).html();
14
+ if(ct_is_email(ct_curr_str) != -1 || ct_is_ip(ct_curr_str) != -1){
15
+ jQuery(this).after('&nbsp;<a href="https://cleantalk.org/blacklists/'+ct_curr_str+'" target="_blank" title="https://cleantalk.org/blacklists/'+ct_curr_str+'" class="ct_link_new_tab"><img src="'+ctCommentsScreen.ct_img_src_new_tab+'"></a>');
16
+ }
17
+ });
18
+
19
+ /* Feedback for comments */
20
+ var ct_comment_id;
21
+
22
+ // For approved
23
+ jQuery('span.approve').on('click', function(){
24
+ var result = jQuery(this).children('a').attr('href');
25
+ result = result.match(/^comment\.php\?.*c=(\d*).*/);
26
+ ct_comment_id = result[1];
27
+ undo_comment_id = ct_comment_id;
28
+ ct_send_feedback_request(ct_comment_id, 'approve', 0);
29
+ });
30
+
31
+ // For unapprove
32
+ jQuery('span.unapprove').on('click', function(){
33
+ var result = jQuery(this).children('a').attr('href');
34
+ result = result.match(/^comment\.php\?.*c=(\d*).*/);
35
+ ct_comment_id = result[1];
36
+ undo_comment_id = ct_comment_id;
37
+ ct_send_feedback_request(ct_comment_id, 'spam', 0);
38
+ });
39
+
40
+ // For spammed
41
+ jQuery('span.spam').on('click', function(){
42
+ var result = jQuery(this).children('a').attr('href');
43
+ result = result.match(/^comment\.php\?.*c=(\d*).*/);
44
+ ct_comment_id = result[1];
45
+ undo_comment_id = ct_comment_id;
46
+ ct_send_feedback_request(ct_comment_id, 'spam', 0);
47
+
48
+ setTimeout(function(){
49
+ jQuery('tr#undo-'+ct_comment_id+' span.unspam a').click(function(){
50
+ var result = jQuery(this).attr('href');
51
+ result = result.match(/^comment\.php\?.*&c=(\d*).*/);
52
+ ct_comment_id = result[1];
53
+ ct_send_feedback_request(ct_comment_id, 'approve', 1);
54
+ });
55
+ }, 202);
56
+
57
+ });
58
+
59
+ // For unspammed
60
+ jQuery('span.unspam').on('click', function(){
61
+ var result = jQuery(this).children('a').attr('href');
62
+ result = result.match(/^comment\.php\?.*c=(\d*).*/);
63
+ ct_comment_id = result[1];
64
+ ct_send_feedback_request(ct_comment_id, 'approve', 0);
65
+ });
66
+
67
+ // For untrashed
68
+ jQuery('span.untrash a').on('click', function(){
69
+ var result = jQuery(this).attr('href');
70
+ result = result.match(/^comment\.php\?.*c=(\d*).*/);
71
+ ct_comment_id = result[1];
72
+ feedback_result = ct_send_feedback_request(ct_comment_id, 'approve', 0);
73
+ });
74
+ });
75
+
76
+ // Send feedback to backend
77
+ function ct_send_feedback_request(ct_comment_id, ct_comment_status, ct_undo){
78
+
79
+ var data = {
80
+ 'action': 'ct_feedback_comment',
81
+ 'security': ctCommentsScreen.ct_ajax_nonce,
82
+ 'comment_id': ct_comment_id,
83
+ 'comment_status': ct_comment_status
84
+ };
85
+
86
+ jQuery.ajax({
87
+ type: "POST",
88
+ url: ajaxurl,
89
+ data: data,
90
+ success: function(msg){
91
+ ct_feedback_message_output(ct_comment_id, ct_comment_status, msg, ct_undo);
92
+ },
93
+ error: function(jqXHR, textStatus, errorThrown) {
94
+ console.log(jqXHR);
95
+ console.log(textStatus);
96
+ console.log(errorThrown);
97
+ },
98
+ timeout: 5000
99
+ });
100
+ }
101
+
102
+ // Outputs CT message about feedback
103
+ function ct_feedback_message_output(ct_comment_id, ct_comment_status, ct_result, ct_undo){
104
+ if(ct_result == 1){
105
+ if(ct_comment_status == 'approve' && !ct_undo){
106
+ jQuery('tr#comment-'+ct_comment_id)
107
+ .html('')
108
+ .show()
109
+ .append("<td colspan='5'></td>").children('td')
110
+ .css('background', 'rgba(110,240,110,0.7)')
111
+ .append("<div class='spam-undo-inside'>"+ctCommentsScreen.ct_feedback_msg+"</div>");
112
+ }
113
+ if(ct_comment_status == 'spam'){
114
+ if(jQuery('tr').is('#undo-'+ct_comment_id)){
115
+ jQuery('tr#undo-'+ct_comment_id)
116
+ .css('background', 'rgba(240,110,110,0.7)');
117
+ jQuery('tr#undo-'+ct_comment_id+' div.spam-undo-inside')
118
+ .append(" "+ctCommentsScreen.ct_feedback_msg);
119
+ }else{
120
+ jQuery('tr#comment-'+ct_comment_id)
121
+ .html('')
122
+ .show()
123
+ .css('background', 'rgba(240,110,110,0.7)')
124
+ .append("<td colspan='5'></td>").children('td')
125
+ .append("<div class='spam-undo-inside'>"+ctCommentsScreen.ct_feedback_msg+"</div>");
126
+ }
127
+ }
128
+ }
129
+ if(ct_result == 0){
130
+ // Error occurred
131
+ }if(ct_result == 'no_hash'){
132
+ // No hash for this comment
133
+ }
134
+ }
js/src/cleantalk-dashboard-widget.js ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function(){
2
+
3
+ // Set "refresh" link handler
4
+ jQuery(".ct_widget_refresh_link").on('click', function(){
5
+ jQuery('.ct_preloader').show();
6
+ setTimeout(function(){window.scrollTo(0, jQuery('#ct_widget_wrapper').offset().top - 130);}, 1);
7
+ setTimeout(function(){jQuery("#ct_refresh_form").submit();}, 2500);
8
+ });
9
+
10
+ if(location.hash == '#ct_widget')
11
+ setTimeout(function(){window.scrollTo(0, jQuery('#ct_widget_wrapper').offset().top - 130);}, 1);
12
+
13
+ // Fixing default wrapper style
14
+ jQuery("#ct_widget_wrapper").parent().css('padding', 0);
15
+
16
+ // Chart
17
+ var ct_chart = document.getElementById('ct_widget_chart'),
18
+ locale = navigator.language || navigator.userLanguage;
19
+
20
+ function ctParseData(date){
21
+ var date_formatter = new Intl.DateTimeFormat(locale, {
22
+ month: "short",
23
+ day: "numeric"
24
+ });
25
+ date.sort(function(a,b){
26
+ return new Date(a[0]) - new Date(b[0])
27
+ });
28
+ date.forEach(function(d){
29
+ d[0] = Date.parse(d[0]);
30
+ d[0] = date_formatter.format(d[0]);
31
+ });
32
+ }
33
+
34
+ google.charts.load('current', {packages:['corechart', 'bar']});
35
+ google.charts.setOnLoadCallback(drawStuff);
36
+
37
+ function drawStuff() {
38
+ var data = new google.visualization.DataTable();
39
+ data.addColumn('string', 'Spam Blocked');
40
+ data.addColumn('number', 'Frequency');
41
+
42
+ ctParseData(apbctDashboardWidget.data);
43
+ data.addRows(apbctDashboardWidget.data);
44
+
45
+ var options = {
46
+ width: jQuery(".ct_widget_block").first().width(),
47
+ height: 300,
48
+ colors: ['steelblue'],
49
+ legend: 'none',
50
+ bar: {groupWidth: '95%'},
51
+ chartArea:{left:30,top:20,width:'93%',height:'80%'},
52
+ vAxis: { gridlines: { count: 5 } }
53
+ };
54
+
55
+ if(ct_chart){
56
+ var chart = new google.visualization.ColumnChart(ct_chart);
57
+ chart.draw(data, options);
58
+ }
59
+ };
60
+ });
js/src/cleantalk-debug-ajax.js ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function(){
2
+
3
+ console.log('CT debug');
4
+
5
+ // Debug. Console all AJAX requests.
6
+ jQuery(document).ajaxComplete(function(event, xhr, settings, data) {
7
+ console.log("Success!")
8
+ console.log('Event:\n');
9
+ console.log(event);
10
+ console.log('Response:\n');
11
+ console.log(xhr);
12
+ console.log('Request settings:\n');
13
+ console.log(settings);
14
+ console.log('Data:\n');
15
+ console.log(data);
16
+ });
17
+
18
+ });
js/src/cleantalk-public-admin.js ADDED
@@ -0,0 +1,89 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery(document).ready(function(){
2
+
3
+ // Set background-color similar to parents
4
+ jQuery('.ct_comment_info').parents().each(function() {
5
+ if ((e = jQuery(this).css('background-color')).length > 0 && e != 'rgba(0, 0, 0, 0)'){
6
+ jQuery('.ct_comment_info').css('background', e);
7
+ return false;
8
+ }
9
+ });
10
+
11
+ // Set same float style with article
12
+ var ct_post_float = jQuery('.ct_comment_info').prev().last().css('float');
13
+ jQuery('.ct_comment_info').css('float', ct_post_float);
14
+
15
+ var ct_posts = jQuery('.ct_comment_info');
16
+
17
+ jQuery(ct_posts).each(function(indx, elem){
18
+ curr_elem = jQuery(elem);
19
+ curr_elem.parent().prepend(curr_elem);
20
+ });
21
+
22
+ // Handler for buttons
23
+ jQuery('.ct_this_is').on('click', function(){
24
+
25
+ var ct_current_button = jQuery(this),
26
+ ct_feedback_wrap = jQuery(this).siblings('.ct_feedback_wrap'),
27
+ ct_feedback_msg = jQuery('.ct_feedback_msg'),
28
+ ct_comment_status;
29
+
30
+ if(ct_current_button.hasClass('ct_this_is_spam'))
31
+ ct_comment_status = 'spam';
32
+ else
33
+ ct_comment_status = 'approve';
34
+
35
+ var data = {
36
+ 'action': 'ct_feedback_comment',
37
+ 'security': ctPublicAdmin.ct_ajax_nonce,
38
+ 'comment_id': ct_current_button.attr('commentid'),
39
+ 'comment_status': ct_comment_status,
40
+ 'change_status': 1
41
+ };
42
+
43
+ jQuery.ajax({
44
+ type: "POST",
45
+ url: ctPublicAdmin.ajaxurl,
46
+ data: data,
47
+ success: function(msg){
48
+ ct_current_button.hide();
49
+ ct_current_button.siblings('span.ct_this_is').show();
50
+
51
+ jQuery('.ct_feedback_result').hide();
52
+ if(ct_comment_status == 'approve')
53
+ jQuery('.ct_feedback_result_not_spam').show();
54
+ else
55
+ jQuery('.ct_feedback_result_spam').show();
56
+
57
+ if(msg == 1){
58
+ ct_feedback_msg.addClass('ct_feedback_success');
59
+ ct_feedback_msg.html(ctPublicAdmin.ct_feedback_msg);
60
+ }else if(msg == 0){
61
+ // Error occurred
62
+ ct_feedback_msg.addClass('ct_feedback_error');
63
+ ct_feedback_msg.html(ctPublicAdmin.ct_feedback_error);
64
+ }else if(msg == 'no_hash'){
65
+ // No hash for this comment
66
+ ct_feedback_msg.addClass('ct_feedback_no_hash');
67
+ ct_feedback_msg.html(ctPublicAdmin.ct_feedback_no_hash);
68
+ }
69
+ // Hidding feedback message for every message type
70
+ ct_feedback_wrap.show();
71
+ ct_feedback_wrap.css('display', 'inline-block');
72
+
73
+ var ct_timeout_id = ct_feedback_wrap.data('interval_id');
74
+ clearInterval(ct_timeout_id);
75
+ ct_timeout_id = setTimeout(function(){
76
+ ct_feedback_wrap.fadeOut(1000);
77
+ }, 5000);
78
+ ct_feedback_wrap.data('interval_id', ct_timeout_id);
79
+ },
80
+ error: function(jqXHR, textStatus, errorThrown) {
81
+ console.log(jqXHR);
82
+ console.log(textStatus);
83
+ console.log(errorThrown);
84
+ },
85
+ timeout: 15000
86
+ });
87
+ });
88
+
89
+ });
js/src/cleantalk-users-checkspam.js ADDED
@@ -0,0 +1,596 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Printf for JS
2
+ String.prototype.printf = function(){
3
+ var formatted = this;
4
+ for( var arg in arguments ) {
5
+ var before_formatted = formatted.substring(0, formatted.indexOf("%s", 0));
6
+ var after_formatted = formatted.substring(formatted.indexOf("%s", 0)+2, formatted.length);
7
+ formatted = before_formatted + arguments[arg] + after_formatted;
8
+ }
9
+ return formatted;
10
+ };
11
+
12
+ // Set deafult amount to check by request.
13
+ document.cookie = "ct_check_users__amount=" + 100 + "; path=/; samesite=lax";
14
+
15
+ // Flags
16
+ var ct_working = false,
17
+ ct_new_check = true,
18
+ ct_cooling_down_flag = false,
19
+ ct_close_animate = true,
20
+ ct_accurate_check = false,
21
+ ct_pause = false,
22
+ ct_prev_accurate = ctUsersCheck.ct_prev_accurate,
23
+ ct_prev_from = ctUsersCheck.ct_prev_from,
24
+ ct_prev_till = ctUsersCheck.ct_prev_till;
25
+ // Settings
26
+ var ct_cool_down_time = 90000,
27
+ ct_requests_counter = 0,
28
+ ct_max_requests = 60;
29
+ // Variables
30
+ var ct_ajax_nonce = ctUsersCheck.ct_ajax_nonce,
31
+ ct_users_total = 0,
32
+ ct_users_checked = 0,
33
+ ct_users_spam = 0,
34
+ ct_users_bad = 0,
35
+ ct_unchecked = 'unset',
36
+ ct_date_from = 0,
37
+ ct_date_till = 0;
38
+
39
+ /* Function: Reuturns cookie with prefix */
40
+ function apbct_cookie__get(names, prefixes){
41
+ var cookie = {};
42
+ names = names || null;
43
+ if(typeof names == 'string') names = names.split();
44
+ prefixes = prefixes || ['apbct_', 'ct_'];
45
+ if(prefixes === 'none') prefixes = null;
46
+ if(typeof prefixes == 'string') prefixes = prefixes.split();
47
+ document.cookie.split(';').forEach(function(item, i, arr){
48
+ var curr = item.trim().split('=');
49
+ // Detect by full cookie name
50
+ if(names){
51
+ names.forEach(function(name, i, all){
52
+ if(curr[0] === name)
53
+ cookie[curr[0]] = (curr[1]);
54
+ });
55
+ }
56
+ // Detect by name prefix
57
+ if(prefixes){
58
+ prefixes.forEach(function(prefix, i, all){
59
+ if(curr[0].indexOf(prefix) === 0)
60
+ cookie[curr[0]] = (curr[1]);
61
+ });
62
+ }
63
+ });
64
+ return cookie;
65
+ }
66
+
67
+ function apbct_get_cookie( name ){
68
+ var cookie = apbct_cookie__get( name, name );
69
+ if(typeof cookie === 'object' && typeof cookie[name] != 'undefined'){
70
+ return cookie[name];
71
+ }else
72
+ return null;
73
+ }
74
+
75
+ function animate_comment(to,id){
76
+ if(ct_close_animate){
77
+ if(to === 0.3){
78
+ jQuery('#comment-'+id).fadeTo(200,to,function(){
79
+ animate_comment(1,id)
80
+ });
81
+ }else{
82
+ jQuery('#comment-'+id).fadeTo(200,to,function(){
83
+ animate_comment(0.3,id)
84
+ });
85
+ }
86
+ }else{
87
+ ct_close_animate=true;
88
+ }
89
+ }
90
+
91
+ function ct_clear_users(){
92
+
93
+ var from = 0, till = 0;
94
+ if(jQuery('#ct_allow_date_range').is(':checked')) {
95
+ from = jQuery('#ct_date_range_from').val();
96
+ till = jQuery('#ct_date_range_till').val();
97
+ }
98
+
99
+ var ctSecure = location.protocol === 'https:' ? '; secure' : '';
100
+ document.cookie = 'apbct_check_users_offset' + "=" + 0 + "; path=/; samesite=lax" + ctSecure;
101
+
102
+ var data = {
103
+ 'action' : 'ajax_clear_users',
104
+ 'security' : ct_ajax_nonce,
105
+ 'from' : from,
106
+ 'till' : till,
107
+ 'no_cache': Math.random()
108
+ };
109
+
110
+ jQuery.ajax({
111
+ type: "POST",
112
+ url: ajaxurl,
113
+ data: data,
114
+ success: function(msg){
115
+ ct_show_users_info();
116
+ ct_send_users();
117
+ }
118
+ });
119
+
120
+ }
121
+
122
+ //Continues the check after cooldown time
123
+ //Called by ct_send_users();
124
+ function ct_cooling_down_toggle(){
125
+ ct_cooling_down_flag = false;
126
+ ct_send_users();
127
+ ct_show_users_info();
128
+ }
129
+
130
+ function ct_send_users(){
131
+
132
+ if(ct_cooling_down_flag === true)
133
+ return;
134
+
135
+ if(ct_requests_counter >= ct_max_requests){
136
+ setTimeout(ct_cooling_down_toggle, ct_cool_down_time);
137
+ ct_requests_counter = 0;
138
+ ct_cooling_down_flag = true;
139
+ return;
140
+ }else{
141
+ ct_requests_counter++;
142
+ }
143
+
144
+ var check_amount = apbct_get_cookie('ct_check_users__amount');
145
+
146
+ var data = {
147
+ action: 'ajax_check_users',
148
+ security: ct_ajax_nonce,
149
+ new_check: ct_new_check,
150
+ unchecked: ct_unchecked,
151
+ amount: check_amount,
152
+ 'no_cache': Math.random(),
153
+ 'offset' : Number(getCookie('apbct_check_users_offset'))
154
+ };
155
+
156
+ if(ct_accurate_check)
157
+ data['accurate_check'] = true;
158
+
159
+ if(ct_date_from && ct_date_till){
160
+ data['from'] = ct_date_from;
161
+ data['till'] = ct_date_till;
162
+ }
163
+
164
+ jQuery.ajax({
165
+ type: "POST",
166
+ url: ajaxurl,
167
+ data: data,
168
+ success: function(msg){
169
+
170
+ msg = jQuery.parseJSON(msg);
171
+
172
+ if(parseInt(msg.error)){
173
+ ct_working=false;
174
+ if(!confirm(msg.error_message+". Do you want to proceed?")){
175
+ var new_href = 'users.php?page=ct_check_users';
176
+ if(ct_date_from != 0 && ct_date_till != 0)
177
+ new_href+='&from='+ct_date_from+'&till='+ct_date_till;
178
+ location.href = new_href;
179
+ }else
180
+ ct_send_users();
181
+ }else{
182
+ ct_new_check = false;
183
+ if(parseInt(msg.end) == 1 || ct_pause == true){
184
+ if(parseInt(msg.end) == 1)
185
+ document.cookie = 'ct_paused_users_check=0; path=/; samesite=lax';
186
+ ct_working=false;
187
+ jQuery('#ct_working_message').hide();
188
+ var new_href = 'users.php?page=ct_check_users&ct_worked=1';
189
+ if(ct_date_from != 0 && ct_date_till != 0)
190
+ new_href+='&from='+ct_date_from+'&till='+ct_date_till;
191
+ location.href = new_href;
192
+ }else if(parseInt(msg.end) == 0){
193
+ ct_users_checked = parseInt( ct_users_checked ) + parseInt( msg.checked );
194
+ ct_users_spam = parseInt( ct_users_spam ) + parseInt (msg.spam );
195
+ ct_users_bad = parseInt( msg.bad );
196
+ ct_unchecked = ct_users_total - ct_users_checked - ct_users_bad;
197
+ var status_string = String(ctUsersCheck.ct_status_string);
198
+ var status_string = status_string.printf(ct_users_checked, ct_users_spam, ct_users_bad);
199
+ if(parseInt(ct_users_spam) > 0)
200
+ status_string += ctUsersCheck.ct_status_string_warning;
201
+ jQuery('#ct_checking_status').html(status_string);
202
+ jQuery('#ct_error_message').hide();
203
+
204
+ var offset = Number(getCookie('apbct_check_users_offset')) + 100;
205
+ var ctSecure = location.protocol === 'https:' ? '; secure' : '';
206
+ document.cookie = 'apbct_check_users_offset' + "=" + offset + "; path=/; samesite=lax" + ctSecure;
207
+
208
+ ct_send_users();
209
+ }
210
+ }
211
+ },
212
+ error: function(jqXHR, textStatus, errorThrown) {
213
+ if(check_amount > 20){
214
+ check_amount -= 20;
215
+ document.cookie = "ct_check_users__amount=" + check_amount + "; path=/; samesite=lax";
216
+ }
217
+ jQuery('#ct_error_message').show();
218
+ jQuery('#cleantalk_ajax_error').html(textStatus);
219
+ jQuery('#cleantalk_js_func').html('Check users');
220
+ setTimeout(ct_send_users(), 3000);
221
+ },
222
+ timeout: 25000
223
+ });
224
+ }
225
+ function ct_show_users_info(){
226
+
227
+ if( ct_working ){
228
+
229
+ if(ct_cooling_down_flag === true){
230
+ jQuery('#ct_cooling_notice').html('Waiting for API to cool down. (About a minute)').show();
231
+ return;
232
+ }else{
233
+ jQuery('#ct_cooling_notice').hide();
234
+ }
235
+
236
+ if( ! ct_users_total ){
237
+
238
+ var data = {
239
+ 'action': 'ajax_info_users',
240
+ 'security': ct_ajax_nonce,
241
+ 'no_cache': Math.random()
242
+ };
243
+
244
+ if( ct_date_from && ct_date_till ){
245
+ data['from'] = ct_date_from;
246
+ data['till'] = ct_date_till;
247
+ }
248
+
249
+ jQuery.ajax({
250
+ type: "POST",
251
+ url: ajaxurl,
252
+ data: data,
253
+ success: function(msg){
254
+ msg = jQuery.parseJSON(msg);
255
+ jQuery('#ct_checking_status').html(msg.message);
256
+ ct_users_spam = msg.spam;
257
+ ct_users_checked = msg.checked;
258
+ ct_users_bad = msg.bad;
259
+ },
260
+ error: function (jqXHR, textStatus, errorThrown){
261
+ jQuery('#ct_error_message').show();
262
+ jQuery('#cleantalk_ajax_error').html(textStatus);
263
+ jQuery('#cleantalk_js_func').html('Show users');
264
+ setTimeout(ct_show_users_info(), 3000);
265
+ },
266
+ timeout: 15000
267
+ });
268
+ }
269
+ }
270
+ }
271
+ // Function to toggle dependences
272
+ function ct_toggle_depended(obj, secondary){
273
+
274
+ secondary = secondary || null;
275
+
276
+ var depended = jQuery(obj.data('depended')),
277
+ state = obj.data('state');
278
+
279
+ if(!state && !secondary){
280
+ obj.data('state', true);
281
+ depended.removeProp('disabled');
282
+ }else{
283
+ obj.data('state', false);
284
+ depended.prop('disabled', true);
285
+ depended.removeProp('checked');
286
+ if(depended.data('depended'))
287
+ ct_toggle_depended(depended, true);
288
+ }
289
+ }
290
+
291
+ // Main function of checking
292
+ function ct_start_check( continue_check ){
293
+
294
+ continue_check = continue_check || null;
295
+
296
+ if(jQuery('#ct_allow_date_range').is(':checked')){
297
+
298
+ ct_date_from = jQuery('#ct_date_range_from').val();
299
+ ct_date_till = jQuery('#ct_date_range_till').val();
300
+
301
+ if(!(ct_date_from !== '' && ct_date_till !== '')){
302
+ alert(ctUsersCheck.ct_specify_date_range);
303
+ return;
304
+ }
305
+ }
306
+
307
+ if(jQuery('#ct_accurate_check').is(':checked')){
308
+ ct_accurate_check = true;
309
+ }
310
+
311
+ //
312
+ if (
313
+ jQuery('#ct_accurate_check').is(':checked') &&
314
+ ! jQuery('#ct_allow_date_range').is(':checked')
315
+ ) {
316
+ alert(ctUsersCheck.ct_select_date_range);
317
+ return;
318
+ }
319
+
320
+ jQuery('.ct_to_hide').hide();
321
+ jQuery('#ct_working_message').show();
322
+ jQuery('#ct_preloader').show();
323
+ jQuery('#ct_pause').show();
324
+
325
+ ct_working = true;
326
+
327
+ if( continue_check ){
328
+ ct_show_users_info();
329
+ ct_send_users();
330
+ } else {
331
+ ct_clear_users();
332
+ }
333
+
334
+ }
335
+
336
+ function ct_delete_all_users( e ){
337
+
338
+ var data = {
339
+ 'action': 'ajax_delete_all_users',
340
+ 'security': ct_ajax_nonce,
341
+ 'no_cache': Math.random()
342
+ };
343
+
344
+ jQuery('.' + e.target.id).addClass('disabled');
345
+ jQuery('.spinner').css('visibility', 'visible');
346
+ jQuery.ajax({
347
+ type: "POST",
348
+ url: ajaxurl,
349
+ data: data,
350
+ success: function( msg ){
351
+ if( msg > 0 ){
352
+ jQuery('#cleantalk_users_left').html(msg);
353
+ ct_delete_all_users( e, data );
354
+ }else{
355
+ jQuery('.' + e.target.id).removeClass('disabled');
356
+ jQuery('.spinner').css('visibility', 'hidden');
357
+ location.href='users.php?page=ct_check_users';
358
+ }
359
+ },
360
+ error: function(jqXHR, textStatus, errorThrown) {
361
+ jQuery('#ct_error_message').show();
362
+ jQuery('#cleantalk_ajax_error').html(textStatus);
363
+ jQuery('#cleantalk_js_func').html('All users deleteion');
364
+ setTimeout(ct_delete_all_users( e ), 3000);
365
+ },
366
+ timeout: 25000
367
+ });
368
+ }
369
+
370
+ jQuery(document).ready(function(){
371
+
372
+ // Setting dependences
373
+
374
+ // Prev check parameters
375
+ if(ct_prev_accurate){
376
+ jQuery("#ct_accurate_check").prop('checked', true);
377
+ }
378
+ if(ct_prev_from){
379
+ jQuery("#ct_allow_date_range").prop('checked', true).data('state', true);
380
+ jQuery("#ct_date_range_from").removeProp('disabled').val(ct_prev_from);
381
+ jQuery("#ct_date_range_till").removeProp('disabled').val(ct_prev_till);
382
+ }
383
+
384
+ // Toggle dependences
385
+ jQuery("#ct_allow_date_range").on('change', function(){
386
+ document.cookie = 'ct_users_dates_from='+ jQuery('#ct_date_range_from').val() +'; path=/; samesite=lax';
387
+ document.cookie = 'ct_users_dates_till='+ jQuery('#ct_date_range_till').val() +'; path=/; samesite=lax';
388
+ if( this.checked ) {
389
+ document.cookie = 'ct_users_dates_allowed=1; path=/; samesite=lax';
390
+ jQuery('.ct_date').prop('checked', true).attr('disabled',false);
391
+ } else {
392
+ document.cookie = 'ct_users_dates_allowed=0; path=/; samesite=lax';
393
+ jQuery('.ct_date').prop('disabled', true).attr('disabled',true);
394
+ }
395
+ });
396
+
397
+ jQuery.datepicker.setDefaults(jQuery.datepicker.regional['en']);
398
+ var dates = jQuery('#ct_date_range_from, #ct_date_range_till').datepicker(
399
+ {
400
+ dateFormat: 'M d yy',
401
+ maxDate:"+0D",
402
+ changeMonth:true,
403
+ changeYear:true,
404
+ showAnim: 'slideDown',
405
+ onSelect: function(selectedDate){
406
+ var option = this.id == "ct_date_range_from" ? "minDate" : "maxDate",
407
+ instance = jQuery( this ).data( "datepicker" ),
408
+ date = jQuery.datepicker.parseDate(
409
+ instance.settings.dateFormat || jQuery.datepicker._defaults.dateFormat,
410
+ selectedDate, instance.settings);
411
+ dates.not(this).datepicker("option", option, date);
412
+ document.cookie = 'ct_users_dates_from='+ jQuery('#ct_date_range_from').val() +'; path=/; samesite=lax';
413
+ document.cookie = 'ct_users_dates_till='+ jQuery('#ct_date_range_till').val() +'; path=/; samesite=lax';
414
+ }
415
+ }
416
+ );
417
+
418
+ // Check users
419
+ jQuery("#ct_check_spam_button").click(function(){
420
+ document.cookie = 'ct_paused_users_check=0; path=/; samesite=lax';
421
+
422
+ //
423
+
424
+
425
+ ct_start_check(false);
426
+ });
427
+ jQuery("#ct_proceed_check_button").click(function(){
428
+ ct_start_check(true);
429
+ });
430
+
431
+ // Pause the check
432
+ jQuery('#ct_pause').on('click', function(){
433
+ ct_pause = true;
434
+ var ct_check = {
435
+ 'accurate': ct_accurate_check,
436
+ 'from' : ct_date_from,
437
+ 'till' : ct_date_till
438
+ };
439
+ document.cookie = 'ct_paused_users_check=' + JSON.stringify(ct_check) + '; path=/; samesite=lax';
440
+ });
441
+
442
+ //Approve button
443
+ jQuery(".cleantalk_delete_from_list_button").click(function(){
444
+ ct_id = jQuery(this).attr("data-id");
445
+
446
+ // Approving
447
+ var data = {
448
+ 'action': 'ajax_ct_approve_user',
449
+ 'security': ct_ajax_nonce,
450
+ 'id': ct_id,
451
+ 'no_cache': Math.random()
452
+ };
453
+ jQuery.ajax({
454
+ type: "POST",
455
+ url: ajaxurl,
456
+ data: data,
457
+ success: function(msg){
458
+ jQuery("#comment-"+ct_id).fadeOut('slow', function(){
459
+ jQuery("#comment-"+ct_id).remove();
460
+ });
461
+ },
462
+ });
463
+
464
+ // Positive feedback
465
+ var data = {
466
+ 'action': 'ct_feedback_user',
467
+ 'security': ct_ajax_nonce,
468
+ 'user_id': ct_id,
469
+ 'status': 'approve',
470
+ 'no_cache': Math.random()
471
+ };
472
+ jQuery.ajax({
473
+ type: "POST",
474
+ url: ajaxurl,
475
+ data: data,
476
+ success: function(msg){
477
+ if(msg == 1){
478
+ // Success
479
+ }
480
+ if(msg == 0){
481
+ // Error occurred
482
+ }
483
+ if(msg == 'no_hash'){
484
+ // No hash
485
+ }
486
+ },
487
+ error: function(jqXHR, textStatus, errorThrown) {
488
+
489
+ },
490
+ timeout: 5000
491
+ });
492
+
493
+ });
494
+
495
+ // Request to Download CSV file.
496
+ jQuery(".ct_get_csv_file").click(function( e ){
497
+ var data = {
498
+ 'action': 'ajax_ct_get_csv_file',
499
+ 'security': ct_ajax_nonce,
500
+ 'filename': ctUsersCheck.ct_csv_filename,
501
+ 'no_cache': Math.random()
502
+ };
503
+ jQuery('.' + e.target.id).addClass('disabled');
504
+ jQuery('.spinner').css('visibility', 'visible');
505
+ jQuery.ajax({
506
+ type: "POST",
507
+ url: ajaxurl,
508
+ data: data,
509
+ success: function(msg){
510
+ if( parseInt(msg) === 0 ) {
511
+ alert(ctUsersCheck.ct_bad_csv);
512
+ } else {
513
+ var url = URL.createObjectURL(new Blob([msg]));
514
+
515
+ var dummy = document.createElement('a');
516
+ dummy.href = url;
517
+ dummy.download = ctUsersCheck.ct_csv_filename + '.csv';
518
+
519
+ document.body.appendChild(dummy);
520
+ dummy.click();
521
+ }
522
+ jQuery('.' + e.target.id).removeClass('disabled');
523
+ jQuery('.spinner').css('visibility', 'hidden');
524
+ }
525
+ });
526
+ });
527
+
528
+ // Delete inserted users
529
+ jQuery(".ct_insert_users").click(function( e ){
530
+ ct_insert_users();
531
+ });
532
+
533
+ // Insert users
534
+ jQuery(".ct_insert_users__delete").click(function( e ){
535
+ ct_insert_users( true );
536
+ });
537
+
538
+ // Delete all spam users
539
+ jQuery(".ct_delete_all_users").click(function( e ){
540
+
541
+ if ( ! confirm( ctUsersCheck.ct_confirm_deletion_all ) )
542
+ return false;
543
+
544
+ ct_delete_all_users( e );
545
+
546
+ });
547
+
548
+ function ct_insert_users(delete_accounts){
549
+
550
+ delete_accounts = delete_accounts || null;
551
+
552
+ var data = {
553
+ 'action': 'ajax_insert_users',
554
+ 'security': ct_ajax_nonce,
555
+ 'no_cache': Math.random()
556
+ };
557
+
558
+ if(delete_accounts)
559
+ data['delete'] = true;
560
+
561
+ jQuery.ajax({
562
+ type: "POST",
563
+ url: ajaxurl,
564
+ data: data,
565
+ success: function(msg){
566
+ if(delete_accounts)
567
+ alert('Deleted ' + msg + ' users');
568
+ else
569
+ alert('Inserted ' + msg + ' users');
570
+ }
571
+ });
572
+ }
573
+
574
+
575
+ /**
576
+ * Checked ct_accurate_check
577
+ */
578
+ jQuery('#ct_accurate_check').change(function () {
579
+ if(this.checked) {
580
+ jQuery('#ct_allow_date_range').prop('checked', true);
581
+ jQuery('.ct_date').prop('checked', true).attr('disabled',false);
582
+ }
583
+ });
584
+ });
585
+
586
+ /**
587
+ * Get cookie by name
588
+ * @param name
589
+ * @returns {string|undefined}
590
+ */
591
+ function getCookie(name) {
592
+ let matches = document.cookie.match(new RegExp(
593
+ "(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
594
+ ));
595
+ return matches ? decodeURIComponent(matches[1]) : undefined;
596
+ }
js/src/cleantalk-users-editscreen.js ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ function ct_is_email(str){
2
+ return str.search(/.*@.*\..*/);
3
+ }
4
+ function ct_is_ip(str){
5
+ return str.search(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/);
6
+ }
7
+
8
+ jQuery(document).ready(function(){
9
+
10
+
11
+ if(parseInt(ctUsersScreen.ct_show_check_links)) {
12
+
13
+ /* Shows link to blacklists near every email and IP address */
14
+ jQuery('.column-email a').each(function(){
15
+ var ct_curr_str = jQuery(this).html();
16
+ if( ct_is_email(ct_curr_str) !== -1 ){
17
+ jQuery(this).after('&nbsp;<a href="https://cleantalk.org/blacklists/'+ct_curr_str+'" target="_blank" title="https://cleantalk.org/blacklists/'+ct_curr_str+'" class="ct_link_new_tab"><img src="'+ctUsersScreen.ct_img_src_new_tab+'"></a>');
18
+ }
19
+ });
20
+
21
+ /* Show checked ico near avatar */
22
+ jQuery('.username.column-username').each(function(){
23
+
24
+ var apbct_checking_el = jQuery(this).siblings('.apbct_status').children('span');
25
+ var apbct_checking_status = apbct_checking_el.attr('id');
26
+ var apbct_checking_status_text = apbct_checking_el.text();
27
+
28
+ var apbct_add_text_element = jQuery('<span>', {
29
+ text : apbct_checking_status_text
30
+ });
31
+ var apbct_add_ico_ok = jQuery('<i>', {
32
+ class : 'apbct-icon-ok'
33
+ });
34
+ var apbct_add_ico_cancel = jQuery('<i>', {
35
+ class : 'apbct-icon-cancel',
36
+ css : {
37
+ color : 'red'
38
+ }
39
+ });
40
+
41
+ if( apbct_checking_status ==='apbct_not_checked' ) {
42
+ jQuery(this).children('.row-actions').before(apbct_add_ico_ok).before(apbct_add_text_element);
43
+ }
44
+ if( apbct_checking_status ==='apbct_checked_not_spam' ) {
45
+ apbct_add_ico_ok.attr('style', 'color:green;');
46
+ jQuery(this).children('.row-actions').before(apbct_add_ico_ok).before(apbct_add_text_element);
47
+ }
48
+ if( apbct_checking_status ==='apbct_checked_spam' ) {
49
+ jQuery(this).children('.row-actions').before(apbct_add_ico_cancel).before(apbct_add_text_element);
50
+ }
51
+
52
+ });
53
+
54
+ }
55
+
56
+ });
lib/Cleantalk/ApbctWP/FindSpam/ListTable/Comments.php CHANGED
@@ -224,12 +224,13 @@ class Comments extends \Cleantalk\ApbctWP\CleantalkListTable
224
  wp_die('nonce error');
225
  }
226
 
 
227
  if ( 'trash' === $action ) {
228
- $this->moveToTrash(Post::get('spamids'));
229
  }
230
 
231
  if ( 'spam' === $action ) {
232
- $this->moveToSpam(Post::get('spamids'));
233
  }
234
  }
235
 
@@ -369,7 +370,8 @@ class Comments extends \Cleantalk\ApbctWP\CleantalkListTable
369
 
370
  protected function removeLogs($ids)
371
  {
372
- $ids_string = implode(', ', $ids);
 
373
  global $wpdb;
374
 
375
  $wpdb->query(
224
  wp_die('nonce error');
225
  }
226
 
227
+ $spam_ids = wp_parse_id_list(Post::get('spamids'));
228
  if ( 'trash' === $action ) {
229
+ $this->moveToTrash($spam_ids);
230
  }
231
 
232
  if ( 'spam' === $action ) {
233
+ $this->moveToSpam($spam_ids);
234
  }
235
  }
236
 
370
 
371
  protected function removeLogs($ids)
372
  {
373
+ $spam_ids = wp_parse_id_list($ids);
374
+ $ids_string = implode(', ', $spam_ids);
375
  global $wpdb;
376
 
377
  $wpdb->query(
lib/Cleantalk/ApbctWP/FindSpam/ListTable/CommentsLogs.php CHANGED
@@ -57,7 +57,8 @@ class CommentsLogs extends Comments
57
  wp_die('nonce error');
58
  }
59
 
60
- $this->removeLogs(Post::get('spamids'));
 
61
  }
62
 
63
  public function no_items() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
57
  wp_die('nonce error');
58
  }
59
 
60
+ $spam_ids = wp_parse_id_list(Post::get('spamids'));
61
+ $this->removeLogs($spam_ids);
62
  }
63
 
64
  public function no_items() // phpcs:ignore PSR1.Methods.CamelCapsMethodName.NotCamelCaps
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: spam, antispam, anti-spam, comments, firewall
4
  Requires at least: 3.0
5
  Tested up to: 6.0
6
  Requires PHP: 5.6
7
- Stable tag: 5.185
8
  License: GPLv2
9
 
10
  Spam protection, anti-spam, firewall, premium plugin. No spam comments & users, no spam contact form & WooCommerce anti-spam.
@@ -602,6 +602,10 @@ If your website has forms that send data to external sources, you can enable opt
602
 
603
  == Changelog ==
604
 
 
 
 
 
605
  = 5.185 Sep 22 2022 =
606
  #### NoCookie data collection, new admin notices style, external forms logic improved and many minor issues fixed.
607
  * New. NoCookie data collection.
4
  Requires at least: 3.0
5
  Tested up to: 6.0
6
  Requires PHP: 5.6
7
+ Stable tag: 5.185.1
8
  License: GPLv2
9
 
10
  Spam protection, anti-spam, firewall, premium plugin. No spam comments & users, no spam contact form & WooCommerce anti-spam.
602
 
603
  == Changelog ==
604
 
605
+ = 5.185.1 Sep 28 2022 =
606
+ #### Fixed a security issues.
607
+ * Fix. Fixed a security issues.
608
+
609
  = 5.185 Sep 22 2022 =
610
  #### NoCookie data collection, new admin notices style, external forms logic improved and many minor issues fixed.
611
  * New. NoCookie data collection.