Form builder to get in touch with visitors, grow your email list and collect payments — Happyforms - Version 1.2

Version Description

Download this release

Release Info

Developer thethemefoundry
Plugin Icon 128x128 Form builder to get in touch with visitors, grow your email list and collect payments — Happyforms
Version 1.2
Comparing to
See all releases

Code changes from version 1.0 to 1.2

Files changed (62) hide show
  1. assets/css/admin.css +67 -25
  2. assets/css/customize.css +141 -7
  3. assets/css/frontend.css +573 -133
  4. assets/js/customize.js +232 -58
  5. assets/js/frontend.js +25 -34
  6. assets/js/frontend/address.js +212 -0
  7. assets/js/frontend/scale.js +56 -0
  8. assets/js/happyforms.js +19 -10
  9. assets/js/parts/part-address.js +108 -0
  10. assets/js/parts/part-country.js +0 -68
  11. assets/js/parts/part-date.js +67 -20
  12. assets/js/parts/part-legal.js +49 -0
  13. assets/js/parts/part-number.js +6 -54
  14. assets/js/parts/part-phone.js +130 -0
  15. assets/js/parts/part-placeholder.js +1 -1
  16. assets/js/parts/part-radio.js +14 -1
  17. assets/js/parts/part-scale.js +134 -0
  18. assets/js/parts/part-title.js +33 -0
  19. assets/js/preview.js +52 -7
  20. assets/svg/happyforms-logo.svg +0 -1
  21. assets/svg/icons/phone.svg +1 -0
  22. assets/svg/icons/scale.svg +1 -0
  23. happyforms.php +2 -2
  24. inc/classes/class-form-controller.php +52 -15
  25. inc/classes/class-form-part-library.php +82 -11
  26. inc/classes/class-form-styles.php +50 -37
  27. inc/classes/class-happyforms-plugin.php +46 -51
  28. inc/classes/class-message-admin.php +169 -31
  29. inc/classes/class-message-controller.php +68 -0
  30. inc/classes/class-message-notices.php +2 -2
  31. inc/classes/class-tracking.php +2 -2
  32. inc/classes/class-wp-customize-form-manager.php +8 -2
  33. inc/classes/parts/class-part-address.php +384 -0
  34. inc/classes/parts/class-part-checkbox.php +69 -43
  35. inc/classes/parts/class-part-country.php +0 -282
  36. inc/classes/parts/class-part-date.php +202 -82
  37. inc/classes/parts/class-part-email.php +76 -47
  38. inc/classes/parts/class-part-legal.php +201 -0
  39. inc/classes/parts/class-part-multi-line-text.php +51 -30
  40. inc/classes/parts/class-part-number.php +98 -338
  41. inc/classes/parts/class-part-phone.php +640 -0
  42. inc/classes/parts/class-part-placeholder.php +17 -5
  43. inc/classes/parts/class-part-radio.php +95 -49
  44. inc/classes/parts/class-part-rating.php +51 -30
  45. inc/classes/parts/class-part-scale.php +372 -0
  46. inc/classes/parts/class-part-select.php +72 -51
  47. inc/classes/parts/class-part-single-line-text.php +51 -30
  48. inc/classes/parts/class-part-title.php +286 -0
  49. inc/classes/parts/class-part-website-url.php +51 -30
  50. inc/helpers/helper-activation.php +2 -0
  51. inc/helpers/helper-form-templates.php +101 -9
  52. inc/helpers/helper-misc.php +316 -0
  53. inc/helpers/helper-validation.php +20 -0
  54. inc/templates/admin-message-edit.php +29 -0
  55. inc/{admin/page-tracking.php → templates/admin-tracking.php} +2 -2
  56. inc/templates/customize-form-build.php +11 -3
  57. inc/templates/customize-form-style.php +98 -67
  58. inc/templates/frontend-form.php +1 -1
  59. inc/templates/preview-form-edit.php +19 -3
  60. inc/templates/preview-form-new.php +18 -2
  61. inc/templates/preview-inline.css +8 -1
  62. readme.txt +28 -1
assets/css/admin.css CHANGED
@@ -3,25 +3,6 @@
3
  * Admin menus
4
  *
5
  */
6
-
7
- /*
8
- #toplevel_page_happyforms ul.wp-submenu li:nth-child(5) a,
9
- #wp-admin-bar-happyforms-upgrade a {
10
- color: #f56e28 !important;
11
- }
12
-
13
- #toplevel_page_happyforms ul.wp-submenu li:nth-child(5) a:after,
14
- #wp-admin-bar-happyforms-upgrade a:after {
15
- content: '\f504';
16
- font-family: dashicons;
17
- font-size: 16px;
18
- vertical-align: bottom;
19
- display: inline-block;
20
- margin-left: 3px;
21
- -webkit-font-smoothing: antialiased;
22
- }
23
- */
24
-
25
  #toplevel_page_happyforms ul.wp-submenu li:nth-child(5) {
26
  display: none;
27
  }
@@ -36,11 +17,11 @@
36
  }
37
 
38
  i.mce-i-happyforms-form-picker:before, i.mce-i-happyforms-form-picker:before {
39
- content: ' ';
40
  display: block;
41
  width: 20px;
42
  height: 20px;
43
- background: url(../svg/happyforms-logo.svg);
44
  background-size: cover;
45
  background-position: center;
46
  }
@@ -84,7 +65,7 @@ tr.type-happyform:hover .happyforms-shortcode-col a.happyforms-shortcode-clipboa
84
 
85
  /**
86
  *
87
- * Messages admin screen
88
  *
89
  */
90
  tr.happyforms-message-unread {
@@ -95,6 +76,61 @@ tr.happyforms-message-unread {
95
  display: none;
96
  }
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  /**
99
  *
100
  * Automatic updates notice
@@ -173,7 +209,13 @@ p.welcome-panel-footer a:active {
173
  color: #0073aa;
174
  }
175
 
176
- #available-widgets-list div[id*='widget-tpl-happpyforms_widget-'] .widget-title:before {
177
- content: '';
178
- background: url(data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzM2IDMzNiI+PGRlZnM+PHN0eWxlPi5jbHMtMXtpc29sYXRpb246aXNvbGF0ZTt9LmNscy0ye2ZpbGw6IzU1NWQ2Njt9PC9zdHlsZT48L2RlZnM+PHRpdGxlPmhhcHB5Zm9ybXMtbG9nbzwvdGl0bGU+PGltYWdlIGlkPSJMYXllcl8wIiBkYXRhLW5hbWU9IkxheWVyIDAiIGNsYXNzPSJjbHMtMSIgd2lkdGg9Ijk0IiBoZWlnaHQ9IjkwIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgxMjAgMTIyKSIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFGNEFBQUJhQ0FZQUFBQXhRK0Y0QUFBQUNYQklXWE1BQUFzU0FBQUxFZ0hTM1g3OEFBQUEza2xFUVZSNFh1M1FvUUhBSUJEQXdOTDlkMzVHUUVITW5ZN0ttcG1QOS81VHdCM0dSNHlQR0I4eFBtSjh4UGlJOFJIakk4WkhqSThZSHpFK1luekUrSWp4RWVNanhrZU1qeGdmTVQ1aWZNVDRpUEVSNHlQR1I0eVBHQjh4UG1KOHhQaUk4UkhqSThaSGpJOFlIekUrWW56RStJanhFZU1qeGtlTWp4Z2ZNVDVpZk1UNGlQRVI0eVBHUjR5UEdCOHhQbUo4eFBpSThSSGpJOFpIakk4WUh6RStZbnpFK0lqeEVlTWp4a2VNanhnZk1UNWlmTVQ0aVBFUjR5UEdSNHlQR0I4eFBtSjh4UGlJOFJIakk4WkhqSThZSHpFK1luekUrSWp4RWVNakcwRnJBN0cxVVRReEFBQUFBRWxGVGtTdVFtQ0MiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik05OC43OCwyMTdsMCwwLS4yMS0uMTZaIi8+PHBhdGggY2xhc3M9ImNscy0yIiBkPSJNOTkuMTMsMjE3LjQ2Yy45MSwxLC42LjU1LjExLDBsLS4zLS4zMS0uMDctLjA2LS4wOS0uMDdDOTguOSwyMTcuMTcsOTksMjE3LjMyLDk5LjEzLDIxNy40NloiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0xNTMuNTQsMjM3LjhoMFoiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0yMjkuMjQsMjEwLjEybDAsMEMyMjguNTUsMjEwLjc4LDIyNy45NCwyMTEuNDIsMjI5LjI0LDIxMC4xMloiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0zMzIuNjEsMTgyLjI3LDMwMy40Miw3My4zNGgwQTk4LjkxLDk4LjkxLDAsMCwwLDE4Mi4yNywzLjRMNzMuMzQsMzIuNThoMEE5OC45Miw5OC45MiwwLDAsMCwzLjQsMTUzLjc0TDMyLjU4LDI2Mi42NmgwYTk4LjkyLDk4LjkyLDAsMCwwLDEyMS4xNSw2OS45NWwxMDguOTMtMjkuMTloMEE5OC45Miw5OC45MiwwLDAsMCwzMzIuNjEsMTgyLjI3Wk0xODIuOCwxMDYuODFhMTkuOCwxOS44LDAsMCwxLDYuNy05LjA5LDI1LjM3LDI1LjM3LDAsMCwxLDQtNC4yOGMxMC4xOC04LjcsMjcuNjItNS41NSwzNC4zMyw2YTI3LjYyLDI3LjYyLDAsMCwxLDIuNjEsMjFBMjYsMjYsMCwwLDEsMjE2LjIyLDEzOGMtMTIuMzYsNS45Mi0yOS42MSwxLjU4LTM1LjA4LTExLjczQTIxLjM1LDIxLjM1LDAsMCwxLDE4Mi44LDEwNi44MVpNMTA2LjM5LDk1YTI1LjM3LDI1LjM3LDAsMCwxLDQtNC4yOGMxMC4xOC04LjcsMjcuNjMtNS41NSwzNC4zMyw2YTI3LjU4LDI3LjU4LDAsMCwxLDIuNjEsMjFjLTIuMDksNy44OC02Ljc4LDE0LTE0LjE5LDE3LjUtMTIuMzYsNS45My0yOS42MSwxLjU5LTM1LjA4LTExLjcyYTIxLjM1LDIxLjM1LDAsMCwxLDEuNjYtMTkuNDVBMTkuOCwxOS44LDAsMCwxLDEwNi4zOSw5NVptMTgyLjc1LDU2LjQ2Yy0yLjE2LDIzLjIyLTExLjUsNDUuNjMtMjUuNDEsNjQuMjVBMTI5LjY4LDEyOS42OCwwLDAsMSwyMTQsMjU1LjY1Yy0yMC40OCw5LjQ1LTQzLjIzLDEyLjgtNjUuNjIsMTEuNDRhMTM0LjUyLDEzNC41MiwwLDAsMS0zMy02LjU5Yy0xMS4xMi0zLjU3LTIyLjA5LTguODgtMzEuMDgtMTYuNDJDNjMuOTQsMjI3LDUyLjM1LDIwMC44NCw0Ny43NiwxNzUuMTcsNDYuMjksMTY3LDUzLjczLDE2MCw2MS4xNiwxNTlhMTUuMTcsMTUuMTcsMCwwLDEsMTAuNzMsMy4yM2MzLjI1LDIuNjIsNC43Niw2LjE4LDUuNDgsMTAuMThhNDcuMzQsNDcuMzQsMCwwLDEsMSw1bC41NCwycTEuMjMsNC4zNywyLjc5LDguNjMsMS42Niw0LjUxLDMuNzEsOC44N2MuNjYsMS40MSwxLjM4LDIuNzksMi4wNyw0LjE5LjM0LjU4LjY3LDEuMTcsMSwxLjc0QTkzLjk0LDkzLjk0LDAsMCwwLDk4Ljc1LDIxN2wuMTIuMS4wNy4wNi4zLjMxYy4yNi4yNy41MS41Ny43My43NywxLjA5LDEsMi4yMSwyLDMuMzgsM3MyLjMxLDEuODQsMy41MiwyLjdsMS44NCwxLjI0YTk5LjA5LDk5LjA5LDAsMCwwLDEzLjE0LDYuMmMxLjQ2LjU1LDIuOTMsMS4wNyw0LjQxLDEuNTcuNTYuMTgsNCwxLjQyLDEuNjUuNTRzMS41OS40MiwyLjExLjU2YzEsLjI3LDIuMDYuNTIsMy4wOS43NmExMjEuNjgsMTIxLjY4LDAsMCwwLDE0LjMyLDIuNDVjMi4yOC4yNSw0LjU2LjQsNi44NS41NWwxLjA4LDBjMS4yMSwwLDIuNDIsMCwzLjYzLDBhMTIyLjExLDEyMi4xMSwwLDAsMCwxNC0xYzIuNTUtLjMzLDUuMDktLjc1LDcuNjEtMS4yNC44Mi0uMTYsMS42My0uMzQsMi40NC0uNTJsMS4yLS4zQTExOS4wOSwxMTkuMDksMCwwLDAsMTk4LDIzMC4xOXEzLjM4LTEuMzUsNi42NS0yLjkxYzEuMDktLjUyLDIuMTgtMS4wNSwzLjI1LTEuNjFsLjI0LS4xMmExMzkuNzIsMTM5LjcyLDAsMCwwLDIxLjM1LTE1LjcxYy4yLS4yMS40LS40MS42MS0uNjEuNzgtLjgsMS41Ni0xLjYxLDIuMzMtMi40NCwxLjQ0LTEuNTQsMi44My0zLjEzLDQuMTgtNC43NGExMTcuNjQsMTE3LjY0LDAsMCwwLDgtMTAuODRjLjY4LTEsMi40Mi00LjczLjQ5LS42OS40Ny0xLDEuMTUtMS45NCwxLjY5LTIuOTFxMS41Ni0yLjc2LDIuOTUtNS41OWExMTUsMTE1LDAsMCwwLDUuMS0xMmMuNDItMS4xOS44My0yLjM4LDEuMjEtMy41NywwLS4xMi4wNy0uMjUuMTItLjQxcS44NC0zLDEuNTItNi4xM2ExMTAuNTQsMTEwLjU0LDAsMCwwLDIuMDUtMTMuMzFjLjc2LTguMjcsOS42LTEzLjE0LDE3LjExLTEyLjIyQzI4NS4yOSwxMzUuNCwyODkuODYsMTQzLjc2LDI4OS4xNCwxNTEuNDlaIi8+PC9zdmc+);
 
 
 
 
 
 
179
  }
3
  * Admin menus
4
  *
5
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  #toplevel_page_happyforms ul.wp-submenu li:nth-child(5) {
7
  display: none;
8
  }
17
  }
18
 
19
  i.mce-i-happyforms-form-picker:before, i.mce-i-happyforms-form-picker:before {
20
+ content: '\f130';
21
  display: block;
22
  width: 20px;
23
  height: 20px;
24
+ font: 400 20px/1 dashicons;
25
  background-size: cover;
26
  background-position: center;
27
  }
65
 
66
  /**
67
  *
68
+ * Messages admin table screen
69
  *
70
  */
71
  tr.happyforms-message-unread {
76
  display: none;
77
  }
78
 
79
+ /**
80
+ *
81
+ * Message edit screen
82
+ *
83
+ */
84
+ body.post-type-happyforms-message #post-body {
85
+ margin-left: -10px;
86
+ }
87
+
88
+ table.happyforms-message-data-table {
89
+ margin-top: 0;
90
+ box-shadow: 0 1px 1px rgba(0,0,0,0.04);
91
+ background: #fff;
92
+ border: 1px solid #e5e5e5;
93
+ }
94
+
95
+ .happyforms-message-data-table th {
96
+ padding: 20px 15px;
97
+ }
98
+
99
+ #happyforms-message-details .inside {
100
+ padding: 0;
101
+ }
102
+
103
+ #happyforms-message-details .inside .happyforms-message-form .logo {
104
+ color: #82878c;
105
+ }
106
+
107
+ #happyforms-message-details .misc-pub-trash:before {
108
+ font: normal 20px/1 dashicons;
109
+ speak: none;
110
+ display: inline-block;
111
+ margin-left: -1px;
112
+ padding-right: 3px;
113
+ vertical-align: top;
114
+ -webkit-font-smoothing: antialiased;
115
+ -moz-osx-font-smoothing: grayscale;
116
+ content: "\f182";
117
+ color: #82878c;
118
+ }
119
+
120
+ #happyforms-message-details .misc-pub-trash a {
121
+ text-decoration: none;
122
+ color: #a00;
123
+ }
124
+
125
+ p.happyforms-message-nav {
126
+ text-align: right;
127
+ }
128
+
129
+ p.happyforms-message-nav span.divider:first-child,
130
+ p.happyforms-message-nav span.divider:last-child {
131
+ display: none;
132
+ }
133
+
134
  /**
135
  *
136
  * Automatic updates notice
209
  color: #0073aa;
210
  }
211
 
212
+ #available-widgets div[id*='widget-tpl-happyforms_widget-'] .widget-title:before {
213
+ content: '\f130';
214
+ }
215
+
216
+ .happyforms-editor-button span.dashicons {
217
+ position: relative;
218
+ top: 4px;
219
+ padding-right: 5px;
220
+ color: #888;
221
  }
assets/css/customize.css CHANGED
@@ -1,3 +1,12 @@
 
 
 
 
 
 
 
 
 
1
  /**
2
  *
3
  * Header actions
@@ -86,6 +95,10 @@
86
  margin: 0;
87
  }
88
 
 
 
 
 
89
  .happyforms-step-description p.description {
90
  margin: 0 0 30px;
91
  }
@@ -263,8 +276,9 @@ a.happyforms-form-part-remove:hover {
263
  .happyforms-parts-placeholder {
264
  display: block;
265
  border: 2px dashed #a1a1a1;
266
- padding: 30px;
267
  box-sizing: border-box;
 
268
  }
269
 
270
  .happyforms-stack-view.has-parts .happyforms-parts-placeholder {
@@ -272,15 +286,28 @@ a.happyforms-form-part-remove:hover {
272
  }
273
 
274
  .happyforms-parts-placeholder img {
275
- margin-bottom: 20px;
 
276
  }
277
 
278
  .happyforms-parts-placeholder p {
279
- display: table-cell;
280
- vertical-align: middle;
281
  font-size: 14px;
282
- color: #7a7a7a;
283
- text-align: center;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  }
285
 
286
  ul.happyforms-form-widgets {
@@ -544,6 +571,18 @@ ul.happyforms-parts-list li[data-part-type="country"] .happyforms-parts-list-ite
544
  background-image: url(../svg/icons/country.svg);
545
  }
546
 
 
 
 
 
 
 
 
 
 
 
 
 
547
  ul.happyforms-parts-list li[data-part-type="placeholder"] .happyforms-parts-list-item-title:before {
548
  background-image: url(../svg/icons/placeholder.svg);
549
  }
@@ -552,6 +591,14 @@ ul.happyforms-parts-list li[data-part-type="rating"] .happyforms-parts-list-item
552
  background-image: url(../svg/icons/rating.svg);
553
  }
554
 
 
 
 
 
 
 
 
 
555
  ul.happyforms-parts-list .happyforms-parts-list-item-title h3 {
556
  margin: 0;
557
  padding: 0 0 5px;
@@ -576,8 +623,85 @@ ul.happyforms-parts-list .happyforms-parts-list-item-description {
576
  display: block;
577
  }
578
 
579
- .happyforms-style-controls .customize-control {
 
 
 
 
 
 
580
  margin-bottom: 20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
581
  }
582
 
583
  /* Tinymce control styles */
@@ -656,4 +780,14 @@ li.customize-control .happyforms-buttonset-container .ui-state-hover {
656
  li.customize-control .happyforms-buttonset-container .ui-state-active,
657
  li.customize-control .happyforms-buttonset-container .ui-state-active.ui-state-hover {
658
  background-color: #fff;
 
 
 
 
 
 
 
 
 
 
659
  }
1
+ /**
2
+ *
3
+ * Customizer-wide
4
+ *
5
+ */
6
+ .wp-full-overlay {
7
+ z-index: 1000;
8
+ }
9
+
10
  /**
11
  *
12
  * Header actions
95
  margin: 0;
96
  }
97
 
98
+ p.description a {
99
+ font-style: normal;
100
+ }
101
+
102
  .happyforms-step-description p.description {
103
  margin: 0 0 30px;
104
  }
276
  .happyforms-parts-placeholder {
277
  display: block;
278
  border: 2px dashed #a1a1a1;
279
+ padding: 30px 30px 40px;
280
  box-sizing: border-box;
281
+ text-align: center;
282
  }
283
 
284
  .happyforms-stack-view.has-parts .happyforms-parts-placeholder {
286
  }
287
 
288
  .happyforms-parts-placeholder img {
289
+ margin-top: 30px;
290
+ width: 90%;
291
  }
292
 
293
  .happyforms-parts-placeholder p {
 
 
294
  font-size: 14px;
295
+ color: #444;
296
+ margin: 0;
297
+ }
298
+
299
+ .happyforms-parts-placeholder p:last-of-type {
300
+ margin-bottom: 30px;
301
+ }
302
+
303
+ .happyforms-parts-placeholder__placeholder {
304
+ margin-bottom: 20px;
305
+ padding: 20px;
306
+ border: 2px dashed #a1a1a1;
307
+ }
308
+
309
+ .happyforms-parts-placeholder__placeholder:last-child {
310
+ margin-bottom: 0;
311
  }
312
 
313
  ul.happyforms-form-widgets {
571
  background-image: url(../svg/icons/country.svg);
572
  }
573
 
574
+ ul.happyforms-parts-list li[data-part-type="address"] .happyforms-parts-list-item-title:before {
575
+ background-image: url(../svg/icons/country.svg);
576
+ }
577
+
578
+ ul.happyforms-parts-list li[data-part-type="title"] .happyforms-parts-list-item-title:before {
579
+ background-image: url(../svg/icons/title.svg);
580
+ }
581
+
582
+ ul.happyforms-parts-list li[data-part-type="legal"] .happyforms-parts-list-item-title:before {
583
+ background-image: url(../svg/icons/legal.svg);
584
+ }
585
+
586
  ul.happyforms-parts-list li[data-part-type="placeholder"] .happyforms-parts-list-item-title:before {
587
  background-image: url(../svg/icons/placeholder.svg);
588
  }
591
  background-image: url(../svg/icons/rating.svg);
592
  }
593
 
594
+ ul.happyforms-parts-list li[data-part-type="scale"] .happyforms-parts-list-item-title:before {
595
+ background-image: url(../svg/icons/scale.svg);
596
+ }
597
+
598
+ ul.happyforms-parts-list li[data-part-type="phone"] .happyforms-parts-list-item-title:before {
599
+ background-image: url(../svg/icons/phone.svg);
600
+ }
601
+
602
  ul.happyforms-parts-list .happyforms-parts-list-item-title h3 {
603
  margin: 0;
604
  padding: 0 0 5px;
623
  display: block;
624
  }
625
 
626
+ ul.happyforms-style-controls {
627
+ position: relative;
628
+ float: left;
629
+ width: 100%;
630
+ }
631
+
632
+ ul.happyforms-style-controls .customize-control {
633
  margin-bottom: 20px;
634
+ padding: 0 12px;
635
+ box-sizing: border-box;
636
+ }
637
+
638
+ /* Style view */
639
+ .happyforms-stack-view.happyforms-style-view {
640
+ padding: 0;
641
+ overflow-x: hidden;
642
+ top: 0;
643
+ bottom: 0;
644
+ }
645
+
646
+ ul.happyforms-style-controls .customize-control.happyforms-divider-control {
647
+ margin-bottom: 0;
648
+ padding: 0;
649
+ }
650
+
651
+ ul.happyforms-style-controls .customize-control.happyforms-divider-control:first-child {
652
+ margin-top: 15px;
653
+ border-top: 1px solid #ddd;
654
+ }
655
+
656
+ .happyforms-style-controls-group {
657
+ position: absolute;
658
+ top: 0;
659
+ left: 300px;
660
+ width: 100%;
661
+ }
662
+
663
+ .happyforms-style-controls-group .accordion-section-title {
664
+ padding: 10px 10px 11px 14px;
665
+ }
666
+
667
+ .happyforms-style-controls-group.inactive {
668
+ left: 700px;
669
+ height: 0;
670
+ overflow: hidden;
671
+ }
672
+
673
+ .control-section h3.accordion-section-title {
674
+ padding-right: 30px;
675
+ color: #555d66;
676
+ background-color: #fff;
677
+ border-bottom: 1px solid #ddd;
678
+ border-left: 4px solid #fff;
679
+ transition: .15s color ease-in-out, .15s background-color ease-in-out, .15s border-color ease-in-out;
680
+ font-size: 14px;
681
+ cursor: pointer;
682
+ }
683
+
684
+ .control-section h3.accordion-section-title:after {
685
+ content: "\f345" !important;
686
+ font: normal 20px/1 dashicons;
687
+ speak: none;
688
+ display: block;
689
+ -webkit-font-smoothing: antialiased;
690
+ -moz-osx-font-smoothing: grayscale;
691
+ text-decoration: none !important;
692
+ position: absolute;
693
+ top: 12px;
694
+ right: 10px;
695
+ z-index: 1;
696
+ color: #a0a5aa;
697
+ }
698
+
699
+ .control-section h3.accordion-section-title:hover {
700
+ border-left-color: #0073aa;
701
+ }
702
+
703
+ .control-section h3.accordion-section-title:hover:after {
704
+ color: #0073aa;
705
  }
706
 
707
  /* Tinymce control styles */
780
  li.customize-control .happyforms-buttonset-container .ui-state-active,
781
  li.customize-control .happyforms-buttonset-container .ui-state-active.ui-state-hover {
782
  background-color: #fff;
783
+ }
784
+
785
+ .happyforms-parts-expand-collapse-wrap {
786
+ float: right;
787
+ font-weight: normal;
788
+ font-size: 11px;
789
+ }
790
+
791
+ .happyforms-parts-expand-collapse-wrap .expand-collapse-all {
792
+ display: none;
793
  }
assets/css/frontend.css CHANGED
@@ -1,23 +1,3 @@
1
- /* admin bar */
2
-
3
- /*
4
- #toplevel_page_happyforms ul.wp-submenu li:nth-child(5) a,
5
- #wp-admin-bar-happyforms-upgrade a {
6
- color: #f56e28 !important;
7
- }
8
-
9
- #toplevel_page_happyforms ul.wp-submenu li:nth-child(5) a:after,
10
- #wp-admin-bar-happyforms-upgrade a:after {
11
- content: '\f504';
12
- font-family: dashicons;
13
- font-size: 16px;
14
- vertical-align: bottom;
15
- display: inline-block;
16
- margin-left: 3px;
17
- -webkit-font-smoothing: antialiased;
18
- }
19
- */
20
-
21
  #wp-admin-bar-happyforms .ab-icon svg {
22
  width: 20px;
23
  margin-top: 2px;
@@ -27,7 +7,7 @@
27
  fill: #00b9eb;
28
  }
29
 
30
- /* happyforms */
31
  .happyforms-container form,
32
  .happyforms-form form {
33
  max-width: 100%;
@@ -40,8 +20,7 @@
40
  flex-flow: row wrap;
41
  align-items: flex-start;
42
  max-width: 100%;
43
- padding: 2.5% 0;
44
- overflow: hidden;
45
  }
46
 
47
  .happyforms-form h3.happyforms-form__title {
@@ -56,16 +35,19 @@
56
  margin-top: 25px;
57
  }
58
 
59
- .happyforms-part__label {
60
- cursor: pointer;
61
- }
62
-
63
- .happyforms-part--label-above .happyforms-part__label--confirmation {
64
- margin-top: 10px;
65
  }
66
 
67
- .happyforms-required {
68
- color: #c00;
 
 
 
 
 
 
 
69
  }
70
 
71
  .happyforms-part {
@@ -85,38 +67,47 @@
85
  }
86
  }
87
 
88
- .happyforms-part__description {
89
- display: block;
90
- margin-bottom: 5px;
91
- font-size: 14px;
92
- font-style: italic;
93
- }
94
-
95
- .happyforms-part .widget .customize-partial-edit-shortcut, .customize-partial-edit-shortcut {
96
- top: 0;
97
- }
98
-
99
  .happyforms-part__label {
100
- display: block;
101
- margin-bottom: 3px;
 
102
  font-size: 16px;
103
  }
104
 
105
  .happyforms-part__label .label {
106
- font-weight: normal;
107
  color: #000;
108
  }
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  .happyforms-part input[type=text],
111
  .happyforms-part input[type=email],
112
  .happyforms-part input[type=tel],
113
  .happyforms-part input[type=number],
 
114
  .happyforms-part textarea {
115
- width: 100%;
116
- padding: inherit 5px;
117
- border-width: 2px;
118
  border-style: solid;
119
- border-color: #000;
 
 
120
  font-size: 16px;
121
  background-color: #fff;
122
  color: #000;
@@ -130,11 +121,140 @@
130
  .happyforms-part input[type=tel]:focus,
131
  .happyforms-part input[type=number]:focus,
132
  .happyforms-part textarea:focus {
133
- border-width: 2px;
134
  border-style: solid;
135
- border-color: #000;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
 
 
138
  .happyforms-part ::-webkit-input-placeholder {
139
  font-weight: normal;
140
  font-style: normal;
@@ -165,8 +285,22 @@
165
  align-content: flex-end;
166
  }
167
 
168
- .happyforms-part--label-below .happyforms-part__label {
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  width: 100%;
 
170
  }
171
 
172
  .happyforms-part--label-left .happyforms-part__label {
@@ -174,10 +308,15 @@
174
  width: 25%;
175
  }
176
 
177
- .happyforms-part--label-left .happyforms-part__el,
178
  .happyforms-part--label-left input.happyforms-part__el,
179
- .happyforms-part--label-left select.happyforms-part__el,
180
- .happyforms-part--label-left textarea.happyforms-part__el {
 
 
 
 
 
 
181
  float: right;
182
  width: 75%;
183
  }
@@ -208,33 +347,212 @@
208
  margin-bottom: 0;
209
  }
210
 
211
- .happyforms-part--select select {
 
 
 
 
212
  width: 100%;
213
- height: 42px;
214
- border-width: 2px;
 
215
  border-style: solid;
216
- border-color: #000;
 
217
  font-size: 16px;
218
  }
219
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
  .happyforms-part .option-label {
221
- display: inline;
 
 
 
222
  padding: 0 5px 5px 0;
223
  font-size: 16px;
224
  }
225
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
226
  .happyforms-part.display-type--block .option-label {
227
  display: block;
228
  }
229
 
 
 
 
 
230
  .happyforms-part .happyforms-message-notices {
231
- padding: 0;
232
  }
233
 
234
  .happyforms-part .happyforms-message-notices h2 {
235
  font-size: 14px;
236
  }
237
 
 
 
 
 
 
 
238
  .happyforms-part--rating .happyforms-rating-item-wrap {
239
  float: left;
240
  margin-right: 5px;
@@ -245,7 +563,8 @@
245
  }
246
 
247
  .happyforms-part--rating .happyforms-star {
248
- width: 25px;
 
249
  }
250
 
251
  .happyforms-part--rating .happyforms-star__label {
@@ -296,6 +615,12 @@
296
  color: #ccc;
297
  }
298
 
 
 
 
 
 
 
299
  .happyforms-part--submit {
300
  width: 100%;
301
  margin-bottom: 0;
@@ -307,9 +632,10 @@ button[type=submit][disabled].happyforms-button--submit:hover,
307
  input[type=submit].happyforms-button--submit,
308
  input[type=submit][disabled].happyforms-button--submit,
309
  input[type=submit][disabled].happyforms-button--submit:hover {
310
- padding: 16px 40px;
311
- border-radius: 2px;
312
  border-style: solid;
 
313
  font-weight: normal;
314
  font-style: normal;
315
  font-size: 18px;
@@ -321,72 +647,24 @@ input[type=submit][disabled].happyforms-button--submit:hover {
321
  transition-timing-function: ease-in;
322
  }
323
 
 
 
 
 
 
 
 
 
324
  button[type=submit].happyforms-button--submit:hover,
325
  input[type=submit].happyforms-button--submit:hover {
326
- background-color: #999;
 
 
327
  text-transform: none;
328
  }
329
 
330
- .happyforms-date-picker {
331
- font-size: 12px;
332
- background-color: #fff;
333
- }
334
-
335
- .happyforms-date-picker .ui-datepicker-header {
336
- position: relative;
337
- padding: 10px 0;
338
- border: 2px solid #000;
339
- border-bottom: 0;
340
- background-color: #efefef;
341
- }
342
-
343
- .happyforms-date-picker .ui-datepicker-header .ui-datepicker-prev,
344
- .happyforms-date-picker .ui-datepicker-header .ui-datepicker-next {
345
- cursor: pointer;
346
- position: absolute;
347
- top: 0;
348
- left: 3px;
349
- padding: 12px 10px;
350
- display: block;
351
- font-weight: bold;
352
- color: #000;
353
- }
354
-
355
- .happyforms-date-picker .ui-datepicker-header .ui-datepicker-next {
356
- left: auto;
357
- right: 3px;
358
- }
359
-
360
- .happyforms-date-picker .ui-datepicker-title {
361
- font-weight: bold;
362
- font-size: 14px;
363
- text-align: center;
364
- }
365
-
366
- #ui-datepicker-div.happyforms-date-picker {
367
- max-width: 250px;
368
- }
369
-
370
- .happyforms-date-picker table.ui-datepicker-calendar {
371
- margin-top: 0;
372
- margin-bottom: 0;
373
- border: 2px solid #000;
374
- }
375
-
376
- .happyforms-date-picker .ui-datepicker-calendar a {
377
- display: block;
378
- width: 100%;
379
- height: 100%;
380
- text-align: center;
381
- color: #3070d1;
382
- text-decoration: none;
383
- }
384
-
385
- .happyforms-message-notices {
386
- padding: 0 1%;
387
- }
388
-
389
  .happyforms-message-notice h2 {
 
390
  margin-bottom: 0;
391
  font-weight: bold;
392
  font-size: 14px !important;
@@ -394,9 +672,10 @@ input[type=submit].happyforms-button--submit:hover {
394
  }
395
 
396
  .happyforms-message-notice.error h2 {
 
397
  margin-bottom: 5px;
398
  padding: 0;
399
- color: #d3422c;
400
  font-weight: normal;
401
  }
402
 
@@ -423,7 +702,7 @@ input[type=submit].happyforms-button--submit:hover {
423
  }
424
 
425
  .happyforms-message-notice.error-submission {
426
- border-color: #d3422c;
427
  }
428
 
429
  .happyforms-credits {
@@ -436,13 +715,174 @@ input[type=submit].happyforms-button--submit:hover {
436
  clear: both;
437
  }
438
 
439
- .happyforms-visuallyhidden {
 
 
 
 
 
440
  position: absolute;
441
- border: 0;
442
- clip: rect(0 0 0 0);
443
- width: 1px;
444
- height: 1px;
445
- margin: -1px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
446
  padding: 0;
447
- overflow: hidden;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
448
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  #wp-admin-bar-happyforms .ab-icon svg {
2
  width: 20px;
3
  margin-top: 2px;
7
  fill: #00b9eb;
8
  }
9
 
10
+ /* happyforms - general */
11
  .happyforms-container form,
12
  .happyforms-form form {
13
  max-width: 100%;
20
  flex-flow: row wrap;
21
  align-items: flex-start;
22
  max-width: 100%;
23
+ padding: 7.5% 0;
 
24
  }
25
 
26
  .happyforms-form h3.happyforms-form__title {
35
  margin-top: 25px;
36
  }
37
 
38
+ .happyforms-required {
39
+ color: #ff7550;
 
 
 
 
40
  }
41
 
42
+ .happyforms-visuallyhidden {
43
+ position: absolute;
44
+ border: 0;
45
+ clip: rect(0 0 0 0);
46
+ width: 1px;
47
+ height: 1px;
48
+ margin: -1px;
49
+ padding: 0;
50
+ overflow: hidden;
51
  }
52
 
53
  .happyforms-part {
67
  }
68
  }
69
 
 
 
 
 
 
 
 
 
 
 
 
70
  .happyforms-part__label {
71
+ display: inline-block;
72
+ cursor: pointer;
73
+ margin-bottom: 20px;
74
  font-size: 16px;
75
  }
76
 
77
  .happyforms-part__label .label {
78
+ font-weight: bold;
79
  color: #000;
80
  }
81
 
82
+ .happyforms-part--label-above .happyforms-part__label--confirmation {
83
+ margin-top: 10px;
84
+ }
85
+
86
+ .happyforms-part--label-below .happyforms-part__label {
87
+ order: 2;
88
+ width: 100%;
89
+ margin-bottom: 5px;
90
+ }
91
+
92
+ .happyforms-part__description {
93
+ display: block;
94
+ margin: 5px 0 0;
95
+ font-size: 14px;
96
+ }
97
+
98
  .happyforms-part input[type=text],
99
  .happyforms-part input[type=email],
100
  .happyforms-part input[type=tel],
101
  .happyforms-part input[type=number],
102
+ .happyforms-part input[type=range],
103
  .happyforms-part textarea {
104
+ width: calc(100% - 10px);
105
+ padding: 10px;
106
+ border-width: 1px;
107
  border-style: solid;
108
+ border-color: #dbdbdb;
109
+ border-radius: 6px;
110
+ font-style: normal;
111
  font-size: 16px;
112
  background-color: #fff;
113
  color: #000;
121
  .happyforms-part input[type=tel]:focus,
122
  .happyforms-part input[type=number]:focus,
123
  .happyforms-part textarea:focus {
124
+ border-width: 1px;
125
  border-style: solid;
126
+ border-color: #555;
127
+ }
128
+
129
+ .happyforms-part.happyforms-part--error input[type=text],
130
+ .happyforms-part.happyforms-part--error input[type=email],
131
+ .happyforms-part.happyforms-part--error input[type=tel],
132
+ .happyforms-part.happyforms-part--error input[type=number],
133
+ .happyforms-part.happyforms-part--error input[type=range],
134
+ .happyforms-part.happyforms-part--error textarea {
135
+ border-color: #ff7550;
136
+ }
137
+
138
+ /* range part */
139
+ .happyforms-part input[type=range] {
140
+ -webkit-appearance: none;
141
+ padding: 0;
142
+ border: 0;
143
+ width: 100%;
144
+ }
145
+
146
+ .happyforms-part input[type=range]:focus {
147
+ border: 0;
148
+ outline: 0;
149
+ }
150
+
151
+ .happyforms-part input[type=range]::-webkit-slider-runnable-track {
152
+ width: 100%;
153
+ height: 1px;
154
+ cursor: pointer;
155
+ animate: 0.2s;
156
+ box-shadow: none;
157
+ background: #000000;
158
+ }
159
+
160
+ .happyforms-part input[type=range]::-webkit-slider-thumb {
161
+ -webkit-appearance: none;
162
+ width: 20px;
163
+ height: 20px;
164
+ margin-top: -10px;
165
+ border: 1px solid #000000;
166
+ border-radius: 50%;
167
+ box-shadow: none;
168
+ background: #000000;
169
+ cursor: pointer;
170
+ }
171
+
172
+ .happyforms-part input[type=range]:focus::-webkit-slider-runnable-track {
173
+ background: #000000;
174
+ }
175
+
176
+ .happyforms-part input[type=range]::-moz-range-track {
177
+ width: 100%;
178
+ height: 1px;
179
+ cursor: pointer;
180
+ animate: 0.2s;
181
+ box-shadow: none;
182
+ background: #000000;
183
+ }
184
+
185
+ .happyforms-part input[type=range]::-moz-range-thumb {
186
+ width: 20px;
187
+ height: 20px;
188
+ margin-top: -10px;
189
+ border: 1px solid #000000;
190
+ border-radius: 50%;
191
+ box-shadow: none;
192
+ background: #000000;
193
+ cursor: pointer;
194
+ }
195
+
196
+ .happyforms-part input[type=range]::-ms-track {
197
+ width: 100%;
198
+ height: 1px;
199
+ cursor: pointer;
200
+ animate: 0.2s;
201
+ box-shadow: none;
202
+ background: #000000;
203
+ }
204
+
205
+ .happyforms-part input[type=range]::-ms-fill-lower {
206
+ background: #000000;
207
+ border: 0;
208
+ box-shadow: none;
209
+ }
210
+
211
+ .happyforms-part input[type=range]::-ms-fill-upper {
212
+ background: #000000;
213
+ border: 0;
214
+ box-shadow: none;
215
+ }
216
+
217
+ .happyforms-part input[type=range]::-ms-thumb {
218
+ width: 20px;
219
+ height: 20px;
220
+ margin-top: -10px;
221
+ border: 1px solid #000000;
222
+ border-radius: 50%;
223
+ box-shadow: none;
224
+ background: #000000;
225
+ cursor: pointer;
226
+ }
227
+
228
+ .happyforms-part input[type=range]:focus::-ms-fill-lower {
229
+ background: #000000;
230
+ }
231
+
232
+ .happyforms-part input[type=range]:focus::-ms-fill-upper {
233
+ background: #000000;
234
+ }
235
+
236
+ .happyforms-part--scale output {
237
+ display: block;
238
+ position: relative;
239
+ width: 30px;
240
+ text-align: center;
241
+ color: #d0d0d0;
242
+ }
243
+
244
+ .happyforms-part--scale__labels {
245
+ position: relative;
246
+ width: 100%;
247
+ }
248
+
249
+ .happyforms-part--scale__labels .label-min {
250
+ float: left;
251
+ }
252
+
253
+ .happyforms-part--scale__labels .label-max {
254
+ float: right;
255
  }
256
 
257
+ /* part placeholders */
258
  .happyforms-part ::-webkit-input-placeholder {
259
  font-weight: normal;
260
  font-style: normal;
285
  align-content: flex-end;
286
  }
287
 
288
+ .happyforms-part--label-below input,
289
+ .happyforms-part--label-below textarea,
290
+ .happyforms-part--label-below select,
291
+ .happyforms-part--label-below .happyforms-part__select-wrap,
292
+ .happyforms-part--label-below .happyforms-part__el {
293
+ order: 3;
294
+ }
295
+
296
+ .happyforms-part--label-below .happyforms-part__description {
297
+ order: 1;
298
+ margin-top: 0;
299
+ }
300
+
301
+ .happyforms-part--label-below.happyforms-part--date .happyforms-part__el {
302
  width: 100%;
303
+ order: 2;
304
  }
305
 
306
  .happyforms-part--label-left .happyforms-part__label {
308
  width: 25%;
309
  }
310
 
 
311
  .happyforms-part--label-left input.happyforms-part__el,
312
+ .happyforms-part--label-left textarea.happyforms-part__el,
313
+ .happyforms-part--label-left .happyforms-part__select-wrap {
314
+ float: right;
315
+ width: 75%;
316
+ }
317
+
318
+ .happyforms-part--label-left .happyforms-part__description {
319
+ clear: both;
320
  float: right;
321
  width: 75%;
322
  }
347
  margin-bottom: 0;
348
  }
349
 
350
+ .happyforms-part--select select, .happyforms-part--date select {
351
+ position: relative;
352
+ -webkit-appearance: none;
353
+ -moz-appearance: none;
354
+ appearance: none;
355
  width: 100%;
356
+ padding: 10px;
357
+ border-radius: 6px;
358
+ border-width: 0;
359
  border-style: solid;
360
+ border-color: #b2b2b2;
361
+ background-color: #f4f4f4;
362
  font-size: 16px;
363
  }
364
 
365
+ .happyforms-part--date select {
366
+ width: calc(100% - 10px);
367
+ }
368
+
369
+ .happyforms-part-date--date .happyforms-part-date__time-input {
370
+ display: none;
371
+ }
372
+
373
+ .happyforms-part-date--time .happyforms-part-date__date-input {
374
+ display: none;
375
+ }
376
+
377
+ .happyforms-part-date--datetime.happyforms-part--width-half .happyforms-part__el,
378
+ .happyforms-part-date--datetime.happyforms-part--width-third .happyforms-part__el {
379
+ flex-wrap: wrap;
380
+ }
381
+
382
+ .happyforms-part-date--datetime.happyforms-part--width-half .happyforms-part__select-wrap,
383
+ .happyforms-part-date--datetime.happyforms-part--width-third .happyforms-part__select-wrap {
384
+ min-width: 33.333%;
385
+ margin-bottom: 15px;
386
+ }
387
+
388
+ .happyforms-part__select-wrap {
389
+ position: relative;
390
+ flex: 1;
391
+ padding: 0 10px 0 0;
392
+ }
393
+
394
+ .happyforms-part__select-wrap:after {
395
+ content: '';
396
+ position: absolute;
397
+ top: 22%;
398
+ right: 15px;
399
+ z-index: 999;
400
+ display: block;
401
+ width: 25px;
402
+ height: 25px;
403
+ font-size: 22px;
404
+ color: #000;
405
+ fill: #000;
406
+ stroke: #000;
407
+ background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgdmlld0JveD0iMCAwIDE4IDE4Ij48cGF0aCBkPSJNNSA4bDQgNCA0LTR6Ii8+PC9zdmc+);
408
+ background-size: cover;
409
+ background-repeat: no-repeat;
410
+ }
411
+
412
+ .happyforms-part--date .happyforms-part__select-wrap:after {
413
+ top: calc(46% - 12px);
414
+ right: 25px;
415
+ }
416
+
417
+ .happyforms-part--date .happyforms-part__select-wrap:last-child:after {
418
+ right: 15px;
419
+ }
420
+
421
+ .happyforms-part--select select:focus, .happyforms-part--date select:focus {
422
+ outline-width: 1px;
423
+ outline-color: #000000;
424
+ }
425
+
426
+ .happyforms-part--date .happyforms-part__el {
427
+ display: flex;
428
+ }
429
+
430
+ .happyforms-part__select-wrap:last-child {
431
+ padding-right: 0;
432
+ }
433
+
434
  .happyforms-part .option-label {
435
+ position: relative;
436
+ cursor: pointer;
437
+ display: inline-block;
438
+ margin-bottom: 10px;
439
  padding: 0 5px 5px 0;
440
  font-size: 16px;
441
  }
442
 
443
+ .happyforms-part--radio .option-label {
444
+ margin-right: 20px;
445
+ padding: 7px 30px;
446
+ }
447
+
448
+ .happyforms-part--radio .option-label .border {
449
+ position: absolute;
450
+ top: 0;
451
+ left: 0;
452
+ width: 100%;
453
+ height: 100%;
454
+ border-radius: 6px;
455
+ border: 1px solid #dbdbdb;
456
+ }
457
+
458
+ .happyforms-part--radio .option-label input,
459
+ .happyforms-part--checkbox .option-label input {
460
+ position: absolute;
461
+ visibility: hidden;
462
+ }
463
+
464
+ .happyforms-part--radio input:checked ~ .border,
465
+ .happyforms-part--radio .option-label:hover .border {
466
+ border-color: #000;
467
+ }
468
+
469
+ .happyforms-part--radio .option-label input:focus {
470
+ outline: 0;
471
+ }
472
+
473
+ .happyforms-part--radio .option-label .label,
474
+ .happyforms-part--checkbox .option-label .label {
475
+ display: inline-block;
476
+ margin-right: 15px;
477
+ padding: 0 10px 0 20px;
478
+ }
479
+
480
+ .happyforms-part-option {
481
+ margin-bottom: 15px;
482
+ }
483
+
484
+ .happyforms-part-option__description {
485
+ display: block;
486
+ width: 100%;
487
+ max-width: 400px;
488
+ margin-top: 3px;
489
+ margin-right: 20px;
490
+ font-size: 12px;
491
+ }
492
+
493
+ .happyforms-part--radio.display-type--block .happyforms-part-option__description {
494
+ max-width: none;
495
+ }
496
+
497
+ .happyforms-part--radio .happyforms-part__el {
498
+ display: flex;
499
+ }
500
+
501
+ .happyforms-part--radio .checkmark,
502
+ .happyforms-part--checkbox .checkmark {
503
+ position: relative;
504
+ top: 4px;
505
+ display: inline-block;
506
+ width: 20px;
507
+ height: 20px;
508
+ border-radius: 50%;
509
+ border: 1px solid #dbdbdb;
510
+ }
511
+
512
+ .happyforms-part--checkbox .checkmark {
513
+ border-radius: 0;
514
+ }
515
+
516
+ .happyforms-part.display-type--block .checkmark {
517
+ margin-right: 5px;
518
+ }
519
+
520
+ .happyforms-part--radio input:checked + .checkmark,
521
+ .happyforms-part--checkbox input:checked + .checkmark {
522
+ border-color: #000;
523
+ background-color: #000;
524
+ background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAVCAYAAABVAo5cAAAA7UlEQVRIS7XUbRHCMAwG4DcSQAKTgAWQABaQgAW8IGFIAAlgYRJeLru2t6+un8vPNtfn0jYRbBQkdwBOIvIcErKFR/II4G3O7kRkb53q4ASzjkOrgh7MoQCaamAAs+itChiJKVpeYQJ2FpFXUYWpmJY4Akm2ALR/riLyW2uZHGwEkvwCOAyQxofmYg5cwKw7Q0uwHiSpE0Engy8cWopZkBHjrTE5eu2h6H+jL0krvAN4hE6J3F/Fhm9YAw1i019agkZhS32Yg0ZjM1AXEt80CVsEE9BkzAtGoFnYKmjQi2kZna8anZmzn8g2maX9AawIfKa8qZx5AAAAAElFTkSuQmCC);
525
+ background-size: 12px auto;
526
+ background-repeat: no-repeat;
527
+ background-position: center center;
528
+ }
529
+
530
+ .happyforms-part.display-type--block .happyforms-part__el {
531
+ display: block;
532
+ }
533
+
534
  .happyforms-part.display-type--block .option-label {
535
  display: block;
536
  }
537
 
538
+ .happyforms-part.display-type--block .option-label .label {
539
+ padding-left: 0;
540
+ }
541
+
542
  .happyforms-part .happyforms-message-notices {
543
+ padding: 0 1%;
544
  }
545
 
546
  .happyforms-part .happyforms-message-notices h2 {
547
  font-size: 14px;
548
  }
549
 
550
+ .happyforms-part .happyforms-error + input,
551
+ .happyforms-part .happyforms-error + textarea {
552
+ border: 2px solid #ff7550;
553
+ }
554
+
555
+ /* rating part */
556
  .happyforms-part--rating .happyforms-rating-item-wrap {
557
  float: left;
558
  margin-right: 5px;
563
  }
564
 
565
  .happyforms-part--rating .happyforms-star {
566
+ width: 35px;
567
+ height: 35px;
568
  }
569
 
570
  .happyforms-part--rating .happyforms-star__label {
615
  color: #ccc;
616
  }
617
 
618
+ .happyforms-part--legal span {
619
+ margin-left: 5px;
620
+ font-weight: normal;
621
+ font-size: 14px;
622
+ }
623
+
624
  .happyforms-part--submit {
625
  width: 100%;
626
  margin-bottom: 0;
632
  input[type=submit].happyforms-button--submit,
633
  input[type=submit][disabled].happyforms-button--submit,
634
  input[type=submit][disabled].happyforms-button--submit:hover {
635
+ padding: 17px 50px;
636
+ border-radius: 6px;
637
  border-style: solid;
638
+ border-color: #00c280;
639
  font-weight: normal;
640
  font-style: normal;
641
  font-size: 18px;
647
  transition-timing-function: ease-in;
648
  }
649
 
650
+ button[type=submit][disabled].happyforms-button--submit,
651
+ button[type=submit][disabled].happyforms-button--submit:hover,
652
+ input[type=submit][disabled].happyforms-button--submit,
653
+ input[type=submit][disabled].happyforms-button--submit:hover {
654
+ cursor: default;
655
+ opacity: 0.5;
656
+ }
657
+
658
  button[type=submit].happyforms-button--submit:hover,
659
  input[type=submit].happyforms-button--submit:hover {
660
+ border-radius: 6px;
661
+ border-color: #555;
662
+ background-color: #555;
663
  text-transform: none;
664
  }
665
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
666
  .happyforms-message-notice h2 {
667
+ margin-top: 0;
668
  margin-bottom: 0;
669
  font-weight: bold;
670
  font-size: 14px !important;
672
  }
673
 
674
  .happyforms-message-notice.error h2 {
675
+ margin-top: 0;
676
  margin-bottom: 5px;
677
  padding: 0;
678
+ color: #ff7550;
679
  font-weight: normal;
680
  }
681
 
702
  }
703
 
704
  .happyforms-message-notice.error-submission {
705
+ border-color: #ff7550;
706
  }
707
 
708
  .happyforms-credits {
715
  clear: both;
716
  }
717
 
718
+ /* part tooltips */
719
+ .happyforms-part__tooltip {
720
+ display: inline-block;
721
+ }
722
+
723
+ .happyforms-part__tooltip .happyforms-part__description {
724
  position: absolute;
725
+ z-index: 999;
726
+ top: 0;
727
+ right: 18px;
728
+ opacity: 0;
729
+ width: auto;
730
+ visibility: hidden;
731
+ padding: 10px 15px;
732
+ border: 1px solid #dbdbdb;
733
+ border-radius: 6px;
734
+ font-weight: normal;
735
+ color: #000;
736
+ text-align: center;
737
+ background-color: #fff;
738
+ transition: opacity 0.2s;
739
+ }
740
+
741
+ .happyforms-part--multi-line-text .happyforms-part__tooltip .happyforms-part__description {
742
+ top: 25%;
743
+ }
744
+
745
+ .happyforms-part--date .happyforms-part__tooltip .happyforms-part__description,
746
+ .happyforms-part--select .happyforms-part__tooltip .happyforms-part__description,
747
+ .happyforms-part--rating .happyforms-part__tooltip .happyforms-part__description,
748
+ .happyforms-part--scale .happyforms-part__tooltip .happyforms-part__description {
749
+ top: -50px;
750
+ }
751
+
752
+ .happyforms-part__tooltip .happyforms-part__description:before {
753
+ content: '';
754
+ position: absolute;
755
+ top: 100%;
756
+ right: 12px;
757
+ width: 0;
758
+ height: 0;
759
+ border: 8px solid transparent;
760
+ border-top-color: #dbdbdb;
761
+ }
762
+
763
+ .happyforms-part__tooltip .happyforms-part__description:after {
764
+ content: '';
765
+ position: absolute;
766
+ top: calc(100% - 1px);
767
+ right: 13px;
768
+ width: 0;
769
+ height: 0;
770
+ border: 7px solid transparent;
771
+ border-top-color: #fff;
772
+ }
773
+
774
+ .happyforms-tooltip__trigger {
775
+ position: absolute;
776
+ top: 52%;
777
+ right: 30px;
778
+ cursor: pointer;
779
+ display: inline-block;
780
+ width: 18px;
781
+ height: 18px;
782
+ border-radius: 50%;
783
+ font-style: normal;
784
+ font-size: 11px;
785
+ color: #fff;
786
+ text-align: center;
787
+ background-color: #000;
788
+ }
789
+
790
+ .happyforms-part__tooltip:hover .happyforms-part__description {
791
+ visibility: visible;
792
+ opacity: 1;
793
+ }
794
+
795
+ .happyforms-part--date .happyforms-tooltip__trigger,
796
+ .happyforms-part--select .happyforms-tooltip__trigger,
797
+ .happyforms-part--rating .happyforms-tooltip__trigger,
798
+ .happyforms-part--scale .happyforms-tooltip__trigger {
799
+ top: 5px;
800
+ }
801
+
802
+ /* Address part */
803
+ .happyforms-part--address.happyforms-part--address-country-city .happyforms-part__el-wrap {
804
+ display: flex;
805
+ }
806
+
807
+ .happyforms-part--address .happyforms-part__el {
808
+ position: relative;
809
+ }
810
+
811
+ .happyforms-part--address.happyforms-part--address-country-city .happyforms-part__el {
812
+ flex: 1;
813
+ }
814
+
815
+ div.happyforms-part__el--address--results,
816
+ div.happyforms-part__el--address--results-country {
817
  padding: 0;
818
+ margin: 2px 0 0;
819
+ position: absolute;
820
+ z-index: 9999;
821
+ list-style-type: none;
822
+ width: calc(100% - 10px);
823
+ display: none;
824
+ }
825
+
826
+ div.happyforms-part__el--address--results-autocomplete:after {
827
+ content: "";
828
+ padding: 5px 10px;
829
+ height: 16px;
830
+ box-sizing: content-box;
831
+ text-align: right;
832
+ display: block;
833
+ background-image: url(https://maps.gstatic.com/mapfiles/api-3/images/powered-by-google-on-white3.png);
834
+ background-position: calc(100% - 10px) center;
835
+ background-repeat: no-repeat;
836
+ background-size: 120px 14px;
837
+ border-width: 1px;
838
+ border-style: solid;
839
+ border-color: #dbdbdb;
840
+ border-top: none;
841
+ }
842
+
843
+ div.happyforms-part__el--address--results div {
844
+ padding: 10px;
845
+ border-style: solid;
846
+ border-color: #dbdbdb;
847
+ border-width: 1px;
848
+ font-size: 16px;
849
+ cursor: pointer;
850
+ background-color: white;
851
+ }
852
+
853
+ div.happyforms-part__el--address--results div ~ div {
854
+ border-top: none;
855
+ }
856
+
857
+ div.happyforms-part__el--address--results div:only-child {
858
+ border-radius: 6px;
859
+ }
860
+
861
+ div.happyforms-part__el--address--results > div:not(:first-child):not(:last-child):not(:only-child),
862
+ div.happyforms-part__el--address--results-complete > div:last-child {
863
+ border-radius: 0 !important;
864
+ }
865
+
866
+ div.happyforms-part__el--address--results div:first-child:not(:only-child),
867
+ div.happyforms-part__el--address--results-country div:first-child:not(:only-child) {
868
+ border-width: 1px;
869
+ border-style: solid;
870
+ border-color: #dbdbdb;
871
+ border-top-left-radius: 6px;
872
+ border-top-right-radius: 6px;
873
+ border-bottom-left-radius: 0px !important;
874
+ border-bottom-right-radius: 0px !important;
875
+ }
876
+
877
+ div.happyforms-part__el--address--results:after,
878
+ div.happyforms-part__el--address--results-country div:last-child:not(:only-child) {
879
+ border-top-left-radius: 0px !important;
880
+ border-top-right-radius: 0px !important;
881
+ border-bottom-left-radius: 6px;
882
+ border-bottom-right-radius: 6px;
883
+ }
884
+
885
+ div.happyforms-part__el--address--results div:hover,
886
+ div.happyforms-part__el--address--results-country div:hover {
887
+ background-color: #dbdbdb;
888
  }
assets/js/customize.js CHANGED
@@ -218,7 +218,7 @@
218
  $partWidget.find( '.toggle-indicator' ).click();
219
  }
220
 
221
- $partWidget.find( 'input[data-bind="' + data.field_name + '"]' ).focus();
222
  } else {
223
  var $input = $('[name='+ data.field_name +']');
224
 
@@ -434,6 +434,7 @@
434
  events: {
435
  'keyup #happyforms-form-name': 'onNameChange',
436
  'change #happyforms-form-name': 'onNameChange',
 
437
  },
438
 
439
  drawer: null,
@@ -500,14 +501,42 @@
500
  }
501
  },
502
 
503
- onPartAdd: function( type ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
504
  var self = this;
505
  var partModel = PartFactory.model(
506
  { type: type },
507
  { collection: this.model.get( 'parts' ) },
508
  );
509
 
510
- this.model.get( 'parts' ).add( partModel );
511
  this.model.trigger( 'change', this.model );
512
 
513
  var request = wp.ajax.post( 'happyforms-form-part-added', {
@@ -535,8 +564,8 @@
535
  } );
536
  },
537
 
538
- onPartModelAdd: function( partModel ) {
539
- this.addViewPart( partModel, true );
540
  },
541
 
542
  onPartModelRemove: function( partModel ) {
@@ -575,20 +604,14 @@
575
  }
576
  },
577
 
578
- addViewPart: function( partModel, click ) {
579
- if (typeof click === 'undefined') {
580
- click = false;
581
- }
582
-
583
  var settings = happyForms.parts.findWhere( { type: partModel.get( 'type' ) } );
584
 
585
- settings.click = click;
586
-
587
- var partView = PartFactory.view( {
588
  type: settings.get( 'type' ),
589
  model: partModel,
590
- settings: settings
591
- } );
592
 
593
  var partViewModel = new Backbone.Model( {
594
  id: partModel.id,
@@ -602,11 +625,17 @@
602
  var partView = viewModel.get( 'view' );
603
  $( '.happyforms-form-widgets', this.$el ).append( partView.render().$el );
604
  partView.trigger( 'ready' );
 
 
605
  },
606
 
607
  onPartViewRemove: function( viewModel ) {
608
  var partView = viewModel.get( 'view' );
609
  partView.remove();
 
 
 
 
610
  },
611
 
612
  onPartSortStop: function( e, ui ) {
@@ -671,7 +700,7 @@
671
 
672
  onListItemClick: function( e ) {
673
  var type = $( e.currentTarget ).data( 'part-type' );
674
- happyForms.trigger( 'part-add', type );
675
  },
676
 
677
  onPartSearch: function( e ) {
@@ -706,7 +735,8 @@
706
  'keyup [data-bind]': 'onInputChange',
707
  'change [data-bind]': 'onInputChange',
708
  'mouseover': 'onMouseOver',
709
- 'mouseout': 'onMouseOut'
 
710
  },
711
 
712
  initialize: function( options ) {
@@ -719,7 +749,15 @@
719
  this.listenTo(this.model, 'change:required', this.onRequiredCheckboxChange);
720
  this.listenTo(this.model, 'change:placeholder', this.onPlaceholderChange);
721
  this.listenTo(this.model, 'change:description', this.onDescriptionChange);
 
722
  this.listenTo(this.model, 'change:label_placement', this.onLabelPlacementChange);
 
 
 
 
 
 
 
723
  },
724
 
725
  render: function() {
@@ -731,17 +769,11 @@
731
  return this;
732
  },
733
 
734
- ready: function() {
735
- if (typeof this.settings.click !== 'undefined' && this.settings.click) {
736
- this.expandToggle();
737
- }
738
- },
739
-
740
  /**
741
  * Trigger a previewer event on mouse over.
742
- *
743
  * @since 1.0.0.
744
- *
745
  * @return void
746
  */
747
  onMouseOver: function() {
@@ -752,9 +784,9 @@
752
 
753
  /**
754
  * Trigger a previewer event on mouse out.
755
- *
756
  * @since 1.0.0.
757
- *
758
  * @return void
759
  */
760
  onMouseOut: function() {
@@ -765,9 +797,9 @@
765
 
766
  /**
767
  * Send changed label value to previewer.
768
- *
769
  * @since 1.0.0.
770
- *
771
  * @return void
772
  */
773
  onPartLabelChange: function() {
@@ -782,14 +814,28 @@
782
 
783
  /**
784
  * Send data about changed part width to previewer.
785
- *
786
  * @since 1.0.0.
787
- *
788
  * @return void
789
  */
790
- onPartWidthChange: function() {
791
  var width = this.model.get( 'width' );
792
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
  var eventData = {
794
  part_id: this.model.id,
795
  selector: 'self',
@@ -801,9 +847,9 @@
801
 
802
  /**
803
  * Trigger a previewer event on change of the "This is a required field" checkbox.
804
- *
805
  * @since 1.0.0.
806
- *
807
  * @return void
808
  */
809
  onRequiredCheckboxChange: function() {
@@ -826,9 +872,9 @@
826
 
827
  /**
828
  * Slide toggle part view in the customize pane.
829
- *
830
  * @since 1.0.0.
831
- *
832
  * @return void
833
  */
834
  expandToggle: function() {
@@ -840,12 +886,42 @@
840
  },
841
 
842
  /**
843
- * Call expandToggle method on toggle indicator click or 'Close' button click of the part view in Customize pane.
844
  *
845
- * @since 1.0.0.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
846
  *
847
  * @return void
848
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
849
  onWidgetToggle: function( e ) {
850
  e.preventDefault();
851
  this.expandToggle();
@@ -853,9 +929,9 @@
853
 
854
  /**
855
  * Remove part model from collection on "Delete" button click.
856
- *
857
  * @since 1.0.0.
858
- *
859
  * @return void
860
  */
861
  onPartRemoveClick: function( e ) {
@@ -866,9 +942,9 @@
866
 
867
  /**
868
  * Update model with the changed data. Triggered on change event of inputs in the part view.
869
- *
870
  * @since 1.0.0.
871
- *
872
  * @return void
873
  */
874
  onInputChange: function( e ) {
@@ -889,9 +965,9 @@
889
 
890
  /**
891
  * Send changed placeholder value to previewer.
892
- *
893
  * @since 1.0.0.
894
- *
895
  * @return void
896
  */
897
  onPlaceholderChange: function() {
@@ -908,12 +984,18 @@
908
 
909
  /**
910
  * Send changed description value to previewer.
911
- *
912
  * @since 1.0.0.
913
- *
914
  * @return void
915
  */
916
  onDescriptionChange: function() {
 
 
 
 
 
 
917
  var eventData = {
918
  part_id: this.model.id,
919
  selector: '.happyforms-part__description',
@@ -923,14 +1005,65 @@
923
  api.previewer.trigger('happyforms-part-dom-update', eventData);
924
  },
925
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926
  /**
927
  * Send data about changed label placement value to previewer.
928
- *
929
  * @since 1.0.0.
930
- *
931
  * @return void
932
  */
933
- onLabelPlacementChange: function() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
934
  var eventData = {
935
  part_id: this.model.id,
936
  selector: 'self',
@@ -949,6 +1082,23 @@
949
  });
950
 
951
  api.previewer.trigger('happyforms-part-dom-update', addData);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
952
  }
953
  } );
954
 
@@ -982,7 +1132,7 @@
982
 
983
  var editorSettings = {
984
  tinymce: {
985
- toolbar1: 'bold,italic,bullist,numlist,hr',
986
  setup: this.onEditorInit.bind( this ),
987
  },
988
  };
@@ -1088,6 +1238,8 @@
1088
  template: '#happyforms-form-style-template',
1089
 
1090
  events: {
 
 
1091
  'change input[type=checkbox]': 'onCheckboxChange',
1092
  'keyup #hf_style_required_text': 'onRequiredTextChange',
1093
  'change #hf_style_disable_button_until_required_filled': 'onDisableButtonChange',
@@ -1113,6 +1265,28 @@
1113
  this.initButtonSet();
1114
  },
1115
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1116
  initButtonSet: function() {
1117
  $('.happyforms-buttonset-container').buttonset();
1118
  },
@@ -1183,20 +1357,20 @@
1183
 
1184
  onCheckboxChange: function( e ) {
1185
  var $el = $( e.target );
1186
- var value = $el.is(':checked') ? 1 : 0;
1187
 
1188
- this.model.set( $el.attr('data-attribute'), value );
1189
 
1190
  if (happyForms.previewLoaded) {
1191
- api.previewer.trigger('happyforms-style-update', this.model);
1192
  }
1193
  },
1194
 
1195
  onDisableButtonChange: function(e) {
1196
- var $el = $(e.target);
1197
- var value = $el.is(':checked') ? 1 : 0;
1198
 
1199
- this.model.set($el.attr('data-attribute'), value);
1200
 
1201
  if (happyForms.previewLoaded) {
1202
  var eventData = {
@@ -1227,8 +1401,8 @@
1227
  api.previewer.trigger( 'happyforms-part-dom-update', eventData );
1228
  },
1229
 
1230
- onInputChange: function(e) {
1231
- var $el = $(e.target);
1232
  var value = $el.val();
1233
 
1234
  this.model.set( $el.attr('data-attribute'), value );
218
  $partWidget.find( '.toggle-indicator' ).click();
219
  }
220
 
221
+ $partWidget.find( 'input[data-bind=label]' ).focus();
222
  } else {
223
  var $input = $('[name='+ data.field_name +']');
224
 
434
  events: {
435
  'keyup #happyforms-form-name': 'onNameChange',
436
  'change #happyforms-form-name': 'onNameChange',
437
+ 'click .expand-collapse-all': 'onExpandCollapseAllClick'
438
  },
439
 
440
  drawer: null,
501
  }
502
  },
503
 
504
+ onExpandCollapseAllClick: function(e) {
505
+ e.preventDefault();
506
+
507
+ var $button = $(e.target);
508
+
509
+ this.partViews.each(function (model) {
510
+ if ($button.hasClass('expand')) {
511
+ model.get('view').trigger('widget-expand');
512
+ } else {
513
+ model.get('view').trigger('widget-collapse');
514
+ }
515
+ });
516
+
517
+ if ($button.hasClass('expand')) {
518
+ $button.text($button.data('collapse-text')).removeClass('expand').addClass('collapse');
519
+ } else {
520
+ $button.text($button.data('expand-text')).removeClass('collapse').addClass('expand');
521
+ }
522
+ },
523
+
524
+ showExpandCollapseButton: function() {
525
+ this.$el.find('.expand-collapse-all').show();
526
+ },
527
+
528
+ hideExpandCollapseButton: function () {
529
+ this.$el.find('.expand-collapse-all').hide();
530
+ },
531
+
532
+ onPartAdd: function( type, options ) {
533
  var self = this;
534
  var partModel = PartFactory.model(
535
  { type: type },
536
  { collection: this.model.get( 'parts' ) },
537
  );
538
 
539
+ this.model.get( 'parts' ).add( partModel, options );
540
  this.model.trigger( 'change', this.model );
541
 
542
  var request = wp.ajax.post( 'happyforms-form-part-added', {
564
  } );
565
  },
566
 
567
+ onPartModelAdd: function( partModel, partsCollection, options ) {
568
+ this.addViewPart( partModel, options );
569
  },
570
 
571
  onPartModelRemove: function( partModel ) {
604
  }
605
  },
606
 
607
+ addViewPart: function( partModel, options ) {
 
 
 
 
608
  var settings = happyForms.parts.findWhere( { type: partModel.get( 'type' ) } );
609
 
610
+ var partView = PartFactory.view( _.extend( {
 
 
611
  type: settings.get( 'type' ),
612
  model: partModel,
613
+ settings: settings,
614
+ }, options ) );
615
 
616
  var partViewModel = new Backbone.Model( {
617
  id: partModel.id,
625
  var partView = viewModel.get( 'view' );
626
  $( '.happyforms-form-widgets', this.$el ).append( partView.render().$el );
627
  partView.trigger( 'ready' );
628
+
629
+ this.showExpandCollapseButton();
630
  },
631
 
632
  onPartViewRemove: function( viewModel ) {
633
  var partView = viewModel.get( 'view' );
634
  partView.remove();
635
+
636
+ if (!this.partViews.length) {
637
+ this.hideExpandCollapseButton();
638
+ }
639
  },
640
 
641
  onPartSortStop: function( e, ui ) {
700
 
701
  onListItemClick: function( e ) {
702
  var type = $( e.currentTarget ).data( 'part-type' );
703
+ happyForms.trigger( 'part-add', type, { expand: true } );
704
  },
705
 
706
  onPartSearch: function( e ) {
735
  'keyup [data-bind]': 'onInputChange',
736
  'change [data-bind]': 'onInputChange',
737
  'mouseover': 'onMouseOver',
738
+ 'mouseout': 'onMouseOut',
739
+ 'change .apply-all-check': 'applyOptionGlobally'
740
  },
741
 
742
  initialize: function( options ) {
749
  this.listenTo(this.model, 'change:required', this.onRequiredCheckboxChange);
750
  this.listenTo(this.model, 'change:placeholder', this.onPlaceholderChange);
751
  this.listenTo(this.model, 'change:description', this.onDescriptionChange);
752
+ this.listenTo(this.model, 'change:tooltip_description', this.onTooltipDescriptionChange);
753
  this.listenTo(this.model, 'change:label_placement', this.onLabelPlacementChange);
754
+
755
+ this.listenTo(this, 'widget-expand', this.expand);
756
+ this.listenTo(this, 'widget-collapse', this.collapse);
757
+
758
+ if ( options.expand ) {
759
+ this.listenTo( this, 'ready', this.expandToggle );
760
+ }
761
  },
762
 
763
  render: function() {
769
  return this;
770
  },
771
 
 
 
 
 
 
 
772
  /**
773
  * Trigger a previewer event on mouse over.
774
+ *
775
  * @since 1.0.0.
776
+ *
777
  * @return void
778
  */
779
  onMouseOver: function() {
784
 
785
  /**
786
  * Trigger a previewer event on mouse out.
787
+ *
788
  * @since 1.0.0.
789
+ *
790
  * @return void
791
  */
792
  onMouseOut: function() {
797
 
798
  /**
799
  * Send changed label value to previewer.
800
+ *
801
  * @since 1.0.0.
802
+ *
803
  * @return void
804
  */
805
  onPartLabelChange: function() {
814
 
815
  /**
816
  * Send data about changed part width to previewer.
817
+ *
818
  * @since 1.0.0.
819
+ *
820
  * @return void
821
  */
822
+ onPartWidthChange: function(model, value, options) {
823
  var width = this.model.get( 'width' );
824
 
825
+ var $select = this.$el.find('[data-bind=width]');
826
+
827
+ if ($select.val() !== width) {
828
+ $select.val(width);
829
+ }
830
+
831
+ if (!options.skipGlobalReveal) {
832
+ var $globalWrap = this.$el.find('.width-options');
833
+ // reset global checkbox
834
+ $globalWrap.find('input').prop('checked', false);
835
+ // fade in the global checkbox wrapper
836
+ $globalWrap.fadeIn();
837
+ }
838
+
839
  var eventData = {
840
  part_id: this.model.id,
841
  selector: 'self',
847
 
848
  /**
849
  * Trigger a previewer event on change of the "This is a required field" checkbox.
850
+ *
851
  * @since 1.0.0.
852
+ *
853
  * @return void
854
  */
855
  onRequiredCheckboxChange: function() {
872
 
873
  /**
874
  * Slide toggle part view in the customize pane.
875
+ *
876
  * @since 1.0.0.
877
+ *
878
  * @return void
879
  */
880
  expandToggle: function() {
886
  },
887
 
888
  /**
889
+ * Expand part view.
890
  *
891
+ * @since 1.1.0.
892
+ *
893
+ * @return void
894
+ */
895
+ expand: function() {
896
+ var $el = this.$el;
897
+
898
+ $el.find('.happyforms-widget-content').slideDown(function() {
899
+ $el.addClass('happyforms-widget-expanded');
900
+ });
901
+ },
902
+
903
+ /**
904
+ * Collapse part view.
905
+ *
906
+ * @since 1.1.0.
907
  *
908
  * @return void
909
  */
910
+ collapse: function() {
911
+ var $el = this.$el;
912
+
913
+ $el.find('.happyforms-widget-content').slideUp(function () {
914
+ $el.removeClass('happyforms-widget-expanded');
915
+ });
916
+ },
917
+
918
+ /**
919
+ * Call expandToggle method on toggle indicator click or 'Close' button click of the part view in Customize pane.
920
+ *
921
+ * @since 1.0.0.
922
+ *
923
+ * @return void
924
+ */
925
  onWidgetToggle: function( e ) {
926
  e.preventDefault();
927
  this.expandToggle();
929
 
930
  /**
931
  * Remove part model from collection on "Delete" button click.
932
+ *
933
  * @since 1.0.0.
934
+ *
935
  * @return void
936
  */
937
  onPartRemoveClick: function( e ) {
942
 
943
  /**
944
  * Update model with the changed data. Triggered on change event of inputs in the part view.
945
+ *
946
  * @since 1.0.0.
947
+ *
948
  * @return void
949
  */
950
  onInputChange: function( e ) {
965
 
966
  /**
967
  * Send changed placeholder value to previewer.
968
+ *
969
  * @since 1.0.0.
970
+ *
971
  * @return void
972
  */
973
  onPlaceholderChange: function() {
984
 
985
  /**
986
  * Send changed description value to previewer.
987
+ *
988
  * @since 1.0.0.
989
+ *
990
  * @return void
991
  */
992
  onDescriptionChange: function() {
993
+ if (this.model.get('description').length) {
994
+ this.$el.find('.tooltip-description-wrap').fadeIn();
995
+ } else {
996
+ this.$el.find('.tooltip-description-wrap').hide();
997
+ }
998
+
999
  var eventData = {
1000
  part_id: this.model.id,
1001
  selector: '.happyforms-part__description',
1005
  api.previewer.trigger('happyforms-part-dom-update', eventData);
1006
  },
1007
 
1008
+ /**
1009
+ * Trigger a previewer event on tooltip description checkbox change.
1010
+ *
1011
+ * @since 1.1.0.
1012
+ *
1013
+ * @return void
1014
+ */
1015
+ onTooltipDescriptionChange: function() {
1016
+ var tooltipDisplayValue = 'none';
1017
+ var descriptionDisplayValue = 'block';
1018
+
1019
+ if (this.model.get('tooltip_description') === 1) {
1020
+ tooltipDisplayValue = 'inline-block';
1021
+ descriptionDisplayValue = 'none';
1022
+ }
1023
+
1024
+ var descriptionEventData = {
1025
+ part_id: this.model.id,
1026
+ selector: '.happyforms-tooltip + .happyforms-part__description',
1027
+ css: {
1028
+ display: descriptionDisplayValue
1029
+ }
1030
+ };
1031
+
1032
+ api.previewer.trigger('happyforms-part-dom-update', descriptionEventData);
1033
+
1034
+ var tooltipEventData = {
1035
+ part_id: this.model.id,
1036
+ selector: '.happyforms-part__tooltip',
1037
+ css: {
1038
+ display: tooltipDisplayValue
1039
+ }
1040
+ };
1041
+
1042
+ api.previewer.trigger('happyforms-part-dom-update', tooltipEventData);
1043
+ },
1044
+
1045
  /**
1046
  * Send data about changed label placement value to previewer.
1047
+ *
1048
  * @since 1.0.0.
1049
+ *
1050
  * @return void
1051
  */
1052
+ onLabelPlacementChange: function(model, value, options) {
1053
+ var $select = this.$el.find('[data-bind=label_placement]');
1054
+
1055
+ if ($select.val() !== this.model.get('label_placement')) {
1056
+ $select.val(this.model.get('label_placement'));
1057
+ }
1058
+
1059
+ if (!options.skipGlobalReveal) {
1060
+ var $globalWrap = this.$el.find('.label_placement-options');
1061
+ // reset global checkbox
1062
+ $globalWrap.find('input').prop('checked', false);
1063
+ // fade in the global checkbox wrapper
1064
+ $globalWrap.fadeIn();
1065
+ }
1066
+
1067
  var eventData = {
1068
  part_id: this.model.id,
1069
  selector: 'self',
1082
  });
1083
 
1084
  api.previewer.trigger('happyforms-part-dom-update', addData);
1085
+ },
1086
+
1087
+ applyOptionGlobally: function(e) {
1088
+ var $input = $(e.target);
1089
+ var model = this.model;
1090
+ var modelAttribute = $input.attr('data-apply-to');
1091
+ var newValue = this.model.get(modelAttribute);
1092
+
1093
+ _(happyForms.form.get('parts').models).each(function (partModel) {
1094
+ if (partModel.id !== model.id) {
1095
+ if ($input.is(':checked')) {
1096
+ partModel.set(modelAttribute, newValue, { skipGlobalReveal: true });
1097
+ } else {
1098
+ partModel.set(modelAttribute, partModel.previousAttributes()[modelAttribute], { skipGlobalReveal: true });
1099
+ }
1100
+ }
1101
+ });
1102
  }
1103
  } );
1104
 
1132
 
1133
  var editorSettings = {
1134
  tinymce: {
1135
+ toolbar1: 'bold,italic,bullist,numlist,link,hr',
1136
  setup: this.onEditorInit.bind( this ),
1137
  },
1138
  };
1238
  template: '#happyforms-form-style-template',
1239
 
1240
  events: {
1241
+ 'click h3.accordion-section-title': 'onGroupClick',
1242
+ 'click .customize-panel-back': 'onGroupBackClick',
1243
  'change input[type=checkbox]': 'onCheckboxChange',
1244
  'keyup #hf_style_required_text': 'onRequiredTextChange',
1245
  'change #hf_style_disable_button_until_required_filled': 'onDisableButtonChange',
1265
  this.initButtonSet();
1266
  },
1267
 
1268
+ onGroupClick: function( e ) {
1269
+ e.preventDefault();
1270
+
1271
+ $( '.happyforms-style-controls-group', this.$el ).addClass( 'inactive' );
1272
+
1273
+ $( e.target ).next().removeClass( 'inactive' );
1274
+
1275
+ $( '.happyforms-style-controls', this.$el ).animate( {
1276
+ left: '-300px',
1277
+ }, 200 );
1278
+ },
1279
+
1280
+ onGroupBackClick: function( e ) {
1281
+ e.preventDefault();
1282
+
1283
+ $( '.happyforms-style-controls', this.$el ).animate( {
1284
+ left: '0px',
1285
+ }, 200, function() {
1286
+ $( '.happyforms-style-controls-group', this.$el ).addClass( 'inactive' );
1287
+ } );
1288
+ },
1289
+
1290
  initButtonSet: function() {
1291
  $('.happyforms-buttonset-container').buttonset();
1292
  },
1357
 
1358
  onCheckboxChange: function( e ) {
1359
  var $el = $( e.target );
1360
+ var value = $el.is( ':checked' ) ? 1 : 0;
1361
 
1362
+ this.model.set( $el.attr( 'data-attribute' ), value );
1363
 
1364
  if (happyForms.previewLoaded) {
1365
+ api.previewer.trigger( 'happyforms-style-update', this.model );
1366
  }
1367
  },
1368
 
1369
  onDisableButtonChange: function(e) {
1370
+ var $el = $( e.target );
1371
+ var value = $el.is( ':checked' ) ? 1 : 0;
1372
 
1373
+ this.model.set( $el.attr( 'data-attribute' ), value );
1374
 
1375
  if (happyForms.previewLoaded) {
1376
  var eventData = {
1401
  api.previewer.trigger( 'happyforms-part-dom-update', eventData );
1402
  },
1403
 
1404
+ onInputChange: function( e ) {
1405
+ var $el = $( e.target );
1406
  var value = $el.val();
1407
 
1408
  this.model.set( $el.attr('data-attribute'), value );
assets/js/frontend.js CHANGED
@@ -32,44 +32,18 @@ jQuery(function($) {
32
  }
33
  });
34
  }
35
-
36
- if (maskType === 'date') {
37
- var datePattern = $this.data('format').split('/');
38
-
39
- for (var i = 0; i < datePattern.length; i++) {
40
- datePattern[i] = datePattern[i].replace(/(.)(?=\1)/g, "");
41
-
42
- if (datePattern[i] === 'y') {
43
- datePattern[i] = 'Y';
44
- }
45
- }
46
-
47
- var cleave = new Cleave($this, {
48
- date: true,
49
- datePattern: datePattern,
50
- delimiter: '/'
51
- });
52
- }
53
- });
54
-
55
- $('.happyforms-datepicker').each(function() {
56
- var $this = $(this);
57
-
58
- $this.datepicker({
59
- dateFormat: $this.data('format'),
60
- changeYear: ($this.data('change-year') === 1),
61
- changeMonth: ($this.data('change-month') === 1),
62
- nextText: '>',
63
- prevText: '<',
64
- beforeShow: function() {
65
- $('#ui-datepicker-div').addClass('happyforms-date-picker');
66
- }
67
- });
68
  });
69
 
70
  $('.happyforms-form').each(function() {
71
  var $this = $(this);
72
  var $submitButton = $this.find('.happyforms-button--submit');
 
 
 
 
 
 
 
73
 
74
  if ($submitButton.is(':disabled')) {
75
  $this.find('*[required]').on('keyup change', function() {
@@ -82,6 +56,18 @@ jQuery(function($) {
82
  });
83
 
84
  if (valid) {
 
 
 
 
 
 
 
 
 
 
 
 
85
  $submitButton.removeAttr('disabled');
86
  } else {
87
  $submitButton.attr('disabled', 'disabled');
@@ -92,6 +78,7 @@ jQuery(function($) {
92
 
93
  $('.happyforms-part').each(function() {
94
  var $this = $(this);
 
95
  if ($this.find('input[type=checkbox][required]')) {
96
  $this.find('input[type=checkbox]').on('change', function(e) {
97
  if ($(this).is(':checked')) {
@@ -102,6 +89,10 @@ jQuery(function($) {
102
  }
103
  });
104
 
 
 
 
 
105
  $('.happyforms-confirmation-input').on('keyup', function() {
106
  var $this = $(this);
107
  var $validatedInput = $('[name='+ $this.data('confirmation-of') + ']');
@@ -120,4 +111,4 @@ jQuery(function($) {
120
  $this.parent().find('.happyforms-message-notices').hide();
121
  }
122
  });
123
- });
32
  }
33
  });
34
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  });
36
 
37
  $('.happyforms-form').each(function() {
38
  var $this = $(this);
39
  var $submitButton = $this.find('.happyforms-button--submit');
40
+ var hasLegal = false;
41
+ var $legalPart = $this.find('.happyforms-part--legal input');
42
+
43
+ if ($legalPart.length) {
44
+ hasLegal = true;
45
+ $submitButton.attr('disabled', 'disabled');
46
+ }
47
 
48
  if ($submitButton.is(':disabled')) {
49
  $this.find('*[required]').on('keyup change', function() {
56
  });
57
 
58
  if (valid) {
59
+ if (hasLegal) {
60
+ if ($legalPart.is(':checked')) {
61
+ $submitButton.removeAttr('disabled');
62
+ }
63
+ }
64
+ } else {
65
+ $submitButton.attr('disabled', 'disabled');
66
+ }
67
+ });
68
+
69
+ $legalPart.on('change', function() {
70
+ if ($(this).is(':checked')) {
71
  $submitButton.removeAttr('disabled');
72
  } else {
73
  $submitButton.attr('disabled', 'disabled');
78
 
79
  $('.happyforms-part').each(function() {
80
  var $this = $(this);
81
+
82
  if ($this.find('input[type=checkbox][required]')) {
83
  $this.find('input[type=checkbox]').on('change', function(e) {
84
  if ($(this).is(':checked')) {
89
  }
90
  });
91
 
92
+ if (typeof happyFormsScale === 'function') {
93
+ $('.happyforms-part--scale input[type=range]').happyFormsScale();
94
+ }
95
+
96
  $('.happyforms-confirmation-input').on('keyup', function() {
97
  var $this = $(this);
98
  var $validatedInput = $('[name='+ $this.data('confirmation-of') + ']');
111
  $this.parent().find('.happyforms-message-notices').hide();
112
  }
113
  });
114
+ });
assets/js/frontend/address.js ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ( function ( $, countries ) {
2
+
3
+ var pluginName = 'happyFormsAddress';
4
+ var defaults = {
5
+ libraryUrl: 'https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=places',
6
+ };
7
+ var googleAPIRequested = false;
8
+ var googleAPILoaded = false;
9
+
10
+ function Plugin( el, options ) {
11
+ this.el = el;
12
+ this.$el = $( this.el );
13
+ this.$value = $( '[type=hidden]', this.$el );
14
+
15
+ this.options = $.extend( {
16
+ apiKey: this.$el.attr( 'data-google-apikey' ),
17
+ mode: this.$el.attr( 'data-mode' ),
18
+ }, defaults, options );
19
+
20
+ this._defaults = defaults;
21
+ this._name = pluginName;
22
+
23
+ this.init();
24
+ }
25
+
26
+ Plugin.prototype = {
27
+ init: function() {
28
+ if ( ! this.options.apiKey ) {
29
+ return;
30
+ }
31
+
32
+ var libraryUrl = this.options.libraryUrl.replace(
33
+ 'YOUR_API_KEY',
34
+ this.options.apiKey
35
+ );
36
+
37
+ var self = this;
38
+ var $script = $( '#happyforms-google-autocomplete' );
39
+ googleAPIRequested = $script.length !== 0
40
+
41
+ if ( ! googleAPIRequested ) {
42
+ $script = $( '<script>' ).prop( {
43
+ id: 'happyforms-google-autocomplete',
44
+ type: 'text/javascript',
45
+ src: libraryUrl
46
+ } );
47
+ }
48
+
49
+ if ( ! googleAPILoaded ) {
50
+ $script.on( 'load', function() {
51
+ googleAPILoaded = true;
52
+ self.setup();
53
+ } );
54
+ } else {
55
+ self.setup();
56
+ }
57
+
58
+ if ( ! googleAPIRequested ) {
59
+ document.head.appendChild( $script[ 0 ] );
60
+ }
61
+ },
62
+
63
+ setup: function() {
64
+ this.service = new google.maps.places.AutocompleteService();
65
+
66
+ switch( this.options.mode ) {
67
+ case 'autocomplete': this.setupCompleteMode(); break;
68
+ case 'country': this.setupCountryMode(); break;
69
+ case 'country-city': this.setupCountryCityMode(); break;
70
+ }
71
+ },
72
+
73
+ setupCompleteMode: function() {
74
+ var self = this;
75
+ var $address = $( '.happyforms-part__el--address-autocomplete', this.$el );
76
+ var $results = $( '.happyforms-part__el--address--results-autocomplete', this.$el );
77
+
78
+ $address.keyup( function() {
79
+ var value = $address.val();
80
+
81
+ $results.empty();
82
+
83
+ if ( ! value ) {
84
+ return;
85
+ }
86
+
87
+ self.service.getQueryPredictions( {
88
+ input: value,
89
+ types: ['address']
90
+ }, function( results ) {
91
+ $.each( results, function( i, e ) {
92
+ $results.append( $( '<div>' ).text( e.description ) );
93
+ } );
94
+
95
+ $results.show();
96
+
97
+ $( document ).one( 'click', function() {
98
+ $results.hide();
99
+ } );
100
+ } );
101
+ } );
102
+
103
+ $results.click( 'div', function( e ) {
104
+ e.stopPropagation();
105
+
106
+ var value = $( e.target ).text()
107
+ self.$value.val( value );
108
+ $address.val( value );
109
+ $results.hide();
110
+ } );
111
+ },
112
+
113
+ setupCountryMode: function() {
114
+ var self = this;
115
+ var $country = $( '.happyforms-part__el--address-country', this.$el );
116
+ var $results = $( '.happyforms-part__el--address--results-country', this.$el );
117
+
118
+ $country.keyup( function() {
119
+ var value = $country.val();
120
+ $results.empty();
121
+
122
+ if ( ! value ) {
123
+ return;
124
+ }
125
+
126
+ var results = countries.filter( function( name ) {
127
+ return name.toLowerCase().indexOf( value.toLowerCase() ) >= 0;
128
+ } );
129
+
130
+ $.each( results, function( i, e ) {
131
+ $results.append( $( '<div>' ).text( e ) );
132
+ } );
133
+
134
+ $results.show();
135
+
136
+ $( document ).one( 'click', function() {
137
+ $results.hide();
138
+ } );
139
+ } );
140
+
141
+ $results.click( 'li', function( e ) {
142
+ e.stopPropagation();
143
+
144
+ var value = $( e.target ).text()
145
+ self.$value.val( value );
146
+ $country.val( value );
147
+ $results.hide();
148
+ } );
149
+ },
150
+
151
+ setupCountryCityMode: function() {
152
+ var self = this;
153
+ var $country = $( '.happyforms-part__el--address-country', this.$el );
154
+ var $city = $( '.happyforms-part__el--address-city', this.$el );
155
+ var $countryResults = $( '.happyforms-part__el--address--results-country', this.$el );
156
+ var address = [];
157
+
158
+ $country.keyup( function() {
159
+ var value = $country.val();
160
+ $countryResults.empty();
161
+
162
+ if ( ! value ) {
163
+ return;
164
+ }
165
+
166
+ var results = countries.filter( function( name ) {
167
+ return name.toLowerCase().indexOf( value.toLowerCase() ) >= 0;
168
+ } );
169
+
170
+ $.each( results, function( i, e ) {
171
+ $countryResults.append( $( '<div>' ).text( e ) );
172
+ } );
173
+
174
+ $countryResults.show();
175
+
176
+ $( document ).one( 'click', function() {
177
+ $countryResults.hide();
178
+ } );
179
+ } );
180
+
181
+ $city.keyup( function() {
182
+ var value = $city.val();
183
+ address[1] = value;
184
+ self.$value.val( address.join( ', ' ) );
185
+ } );
186
+
187
+ $countryResults.click( 'li', function( e ) {
188
+ e.stopPropagation();
189
+
190
+ var value = $( e.target ).text()
191
+ address[0] = value;
192
+ $country.val( value );
193
+ $countryResults.hide();
194
+ self.$value.val( address.join( ', ' ) );
195
+ } );
196
+ }
197
+ }
198
+
199
+ $.fn[pluginName] = function ( options ) {
200
+ return this.each(function () {
201
+ $.data( this, 'plugin_' + pluginName, new Plugin( this, options ) );
202
+ } );
203
+ }
204
+
205
+ /*
206
+ * Initialize address instances
207
+ */
208
+ $( '.happyforms-part--address' ).each( function( i, el ) {
209
+ $( el ).happyFormsAddress();
210
+ } )
211
+
212
+ } )( jQuery, _happyFormsCountries );
assets/js/frontend/scale.js ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($) {
2
+
3
+ var pluginName = 'happyFormsScale';
4
+ var defaults = {};
5
+
6
+ function Plugin(el, options) {
7
+ this.el = el;
8
+ this.$el = $(this.el);
9
+ this.$output = this.$el.nextAll('output');
10
+
11
+ this._defaults = defaults;
12
+ this._name = pluginName;
13
+
14
+ this.init();
15
+ }
16
+
17
+ Plugin.prototype = {
18
+ init: function () {
19
+ var self = this;
20
+
21
+ this.bindEvents();
22
+ },
23
+
24
+ bindEvents: function() {
25
+ var self = this;
26
+
27
+ this.$el.on('input', function () {
28
+ var rangeWidth = self.$el.width();
29
+ var outputPosition = (self.$el.val() / self.$el.attr('max')) * 100 - ((self.$output.width() / 2) / rangeWidth) * 100;
30
+
31
+ if (outputPosition > 50) {
32
+ outputPosition = outputPosition - 0.6;
33
+ } else {
34
+ outputPosition = outputPosition + 0.3;
35
+ }
36
+
37
+ self.$output.text(self.$el.val()).css({
38
+ left: outputPosition + '%'
39
+ });
40
+ });
41
+
42
+ self.$el.trigger('input');
43
+ }
44
+ }
45
+
46
+ $.fn[pluginName] = function (options) {
47
+ return this.each(function () {
48
+ $.data(this, 'plugin_' + pluginName, new Plugin(this, options));
49
+ });
50
+ }
51
+
52
+ $('.happyforms-part--scale input').each(function (i, el) {
53
+ $(el).happyFormsScale();
54
+ })
55
+
56
+ })(jQuery);
assets/js/happyforms.js CHANGED
@@ -1,13 +1,5 @@
1
  ( function( $ ) {
2
- $( '#automatic-updates input[type="submit"]' ).click( function( e ) {
3
- e.preventDefault();
4
-
5
- var $form = $( '#automatic-updates' );
6
- $( '[name="_wpnonce"]' ).remove();
7
- $( '[name="automatic-updates-nonce"]' ).attr( 'name', '_wpnonce' );
8
- $form.submit();
9
- } );
10
-
11
  $( '.notice:not(.one-time)' ).on( 'click', '.notice-dismiss', function( e ) {
12
  e.preventDefault();
13
 
@@ -22,5 +14,22 @@
22
  nonce: nonce
23
  }
24
  );
25
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  } )( jQuery );
1
  ( function( $ ) {
2
+ // Dismissible notices
 
 
 
 
 
 
 
 
3
  $( '.notice:not(.one-time)' ).on( 'click', '.notice-dismiss', function( e ) {
4
  e.preventDefault();
5
 
14
  nonce: nonce
15
  }
16
  );
17
+ } );
18
+
19
+ // Messages edit screen
20
+ $( 'form#post' ).on( 'click', '#happyforms-message-status-toggle', function( e ) {
21
+ e.preventDefault();
22
+
23
+ var $target = $( e.target );
24
+ var $form = $( 'form#post' );
25
+ var $field = $form.find( '[name="message-status"]' );
26
+
27
+ if ( 1 == $field.val() ) {
28
+ $field.val( 0 );
29
+ } else {
30
+ $field.val( 1 );
31
+ }
32
+
33
+ $form.submit();
34
+ } );
35
  } )( jQuery );
assets/js/parts/part-address.js ADDED
@@ -0,0 +1,108 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ( function( $, _, Backbone, api, settings ) {
2
+
3
+ var AddressModel = happyForms.classes.models.Part.extend( {
4
+ defaults: function() {
5
+ return _.extend(
6
+ {},
7
+ settings.formParts.address.defaults,
8
+ _.result( happyForms.classes.models.Part.prototype, 'defaults' ),
9
+ );
10
+ },
11
+ } );
12
+
13
+ var AddressView = happyForms.classes.views.Part.extend( {
14
+ template: '#happyforms-address-template',
15
+
16
+ events: _.extend( {}, happyForms.classes.views.Part.prototype.events, {
17
+ 'change [data-bind=apikey]': 'onApiKeyChange',
18
+ 'change [data-bind=mode]': 'onModeChange',
19
+ } ),
20
+
21
+ initialize: function() {
22
+ happyForms.classes.views.Part.prototype.initialize.apply( this, arguments );
23
+
24
+ this.listenTo( this, 'ready', this.toggleApiKey );
25
+ },
26
+
27
+ toggleApiKey: function() {
28
+ if ( 'autocomplete' === this.model.get( 'mode' ) ) {
29
+ $( '.address-apikey', this.$el ).show();
30
+ } else {
31
+ $( '.address-apikey', this.$el ).hide();
32
+ }
33
+ },
34
+
35
+ onApiKeyChange: function( e ) {
36
+ var eventData = {
37
+ part_id: this.model.id,
38
+ selector: '[data-google-apikey]',
39
+ attributes: {
40
+ 'data-google-apikey': this.model.get( 'apikey' )
41
+ },
42
+ };
43
+
44
+ api.previewer.trigger( 'happyforms-part-dom-update', eventData );
45
+ },
46
+
47
+ onModeChange: function( e ) {
48
+ var self = this;
49
+
50
+ this.toggleApiKey();
51
+
52
+ var request = wp.ajax.post( 'happyforms-form-part-added', {
53
+ 'happyforms-nonce': api.settings.nonce.happyforms,
54
+ happyforms: 1,
55
+ wp_customize: 'on',
56
+ form_id: happyForms.form.id,
57
+ part: this.model.toJSON(),
58
+ } );
59
+
60
+ request.done( function( response ) {
61
+ var template = _.template( response.template );
62
+ var html = template( happyForms.form.toJSON() );
63
+ response.html = html;
64
+
65
+ if (happyForms.previewLoaded) {
66
+ api.previewer.trigger( 'happyforms-form-part-refresh', response );
67
+ } else {
68
+ happyForms.buffer.push( response );
69
+ }
70
+ } );
71
+ }
72
+ } );
73
+
74
+ happyForms.factory.model = _.wrap( happyForms.factory.model, function( func, attrs, options, BaseClass ) {
75
+ if ( 'address' === attrs.type ) {
76
+ BaseClass = AddressModel;
77
+ }
78
+
79
+ return func( attrs, options, BaseClass );
80
+ } );
81
+
82
+ happyForms.factory.view = _.wrap( happyForms.factory.view, function( func, options, BaseClass ) {
83
+ if ( 'address' === options.type ) {
84
+ BaseClass = AddressView;
85
+ }
86
+
87
+ return func( options, BaseClass );
88
+ } );
89
+
90
+ api.bind( 'ready', function() {
91
+ api.previewer.bind( 'happyforms-part-render', function( $el ) {
92
+ if ( ! $el.is( '.happyforms-part--address' ) ) {
93
+ return;
94
+ }
95
+
96
+ $el.happyFormsAddress();
97
+ } );
98
+
99
+ api.previewer.bind( 'happyforms-part-dom-updated', function( $el ) {
100
+ if ( ! $el.is( '.happyforms-part--address' ) ) {
101
+ return;
102
+ }
103
+
104
+ $el.happyFormsAddress();
105
+ } );
106
+ } );
107
+
108
+ } ) ( jQuery, _, Backbone, wp.customize, _happyFormsSettings );
assets/js/parts/part-country.js DELETED
@@ -1,68 +0,0 @@
1
- ( function( $, _, Backbone, api, settings ) {
2
-
3
- var CountryModel = happyForms.classes.models.Part.extend( {
4
- defaults: function() {
5
- return _.extend(
6
- {},
7
- settings.formParts.country.defaults,
8
- _.result( happyForms.classes.models.Part.prototype, 'defaults' ),
9
- );
10
- },
11
- } );
12
-
13
- var CountryView = happyForms.classes.views.Part.extend( {
14
- template: '#happyforms-country-template',
15
-
16
- initialize: function() {
17
- happyForms.classes.views.Part.prototype.initialize.apply(this, arguments);
18
- },
19
-
20
- events: _.extend( {}, happyForms.classes.views.Part.prototype.events, {
21
- 'change [name=default_country]': 'onDefaultCountryChange'
22
- } ),
23
-
24
- /**
25
- * Adds 'selected' attribute to a country dropdown value that was selected as default.
26
- * Triggered by 'Make this option default' checkbox.
27
- * Triggers previewer event.
28
- *
29
- * @since 1.0.0.
30
- *
31
- * @param {object} e JS event.
32
- *
33
- * @return void
34
- */
35
- onDefaultCountryChange: function(e) {
36
- var $input = $(e.target);
37
-
38
- this.model.set('default_country', $input.val());
39
-
40
- var eventData = {
41
- part_id: this.model.id,
42
- selector: 'option[value='+ $input.val() +']',
43
- attributes: {
44
- 'selected': 'true'
45
- }
46
- };
47
-
48
- api.previewer.trigger('happyforms-part-dom-update', eventData);
49
- }
50
- } );
51
-
52
- happyForms.factory.model = _.wrap( happyForms.factory.model, function( func, attrs, options, BaseClass ) {
53
- if ( 'country' === attrs.type ) {
54
- BaseClass = CountryModel;
55
- }
56
-
57
- return func( attrs, options, BaseClass );
58
- } );
59
-
60
- happyForms.factory.view = _.wrap( happyForms.factory.view, function( func, options, BaseClass ) {
61
- if ( 'country' === options.type ) {
62
- BaseClass = CountryView;
63
- }
64
-
65
- return func( options, BaseClass );
66
- } );
67
-
68
- } ) ( jQuery, _, Backbone, wp.customize, _happyFormsSettings );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
assets/js/parts/part-date.js CHANGED
@@ -13,28 +13,75 @@
13
  var DateView = happyForms.classes.views.Part.extend( {
14
  template: '#happyforms-date-template',
15
 
16
- events: _.extend( {}, happyForms.classes.views.Part.prototype.events, {
17
- 'change .datepicker-checkboxes': 'onDatePickerCheckboxChange'
18
- } ),
19
-
20
- /**
21
- * Updates model with the current value of configuration checkboxes in the Date part view.
22
- *
23
- * @since 1.0.0.
24
- *
25
- * @param {object} e JS event.
26
- *
27
- * @return void
28
- */
29
- onDatePickerCheckboxChange: function(e) {
30
- var $input = $(e.target);
31
- var attribute = $input.data('bind');
32
-
33
- if ($input.is(':checked')) {
34
- this.model.set(attribute, 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  } else {
36
- this.model.set(attribute, 0);
 
 
 
 
 
 
37
  }
 
 
 
38
  }
39
  } );
40
 
13
  var DateView = happyForms.classes.views.Part.extend( {
14
  template: '#happyforms-date-template',
15
 
16
+ initialize: function () {
17
+ happyForms.classes.views.Part.prototype.initialize.apply(this, arguments);
18
+
19
+ this.listenTo(this.model, 'change:date_type', this.onDateTypeChange);
20
+ this.listenTo(this.model, 'change:time_format', this.onTimeFormatChange);
21
+ },
22
+
23
+ onDateTypeChange: function(model, value) {
24
+ var classesToRemove = '';
25
+
26
+ if (value === 'date') {
27
+ classesToRemove = 'happyforms-part-date--datetime happyforms-part-date--time';
28
+ this.$el.find('.time-options').hide();
29
+ } else if (value === 'datetime') {
30
+ classesToRemove = 'happyforms-part-date--date happyforms-part-date--time';
31
+ this.$el.find('.time-options').show();
32
+ } else if (value === 'time') {
33
+ classesToRemove = 'happyforms-part-date--date happyforms-part-date--datetime';
34
+ this.$el.find('.time-options').show();
35
+ }
36
+
37
+ var eventData = {
38
+ part_id: model.id,
39
+ selector: 'self',
40
+ classes: classesToRemove,
41
+ classMethod: 'remove'
42
+ };
43
+
44
+ // remove classes
45
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
46
+
47
+ eventData.classes = 'happyforms-part-date--' + value;
48
+ eventData.classMethod = 'add';
49
+
50
+ // add appropriate class
51
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
52
+ },
53
+
54
+ onTimeFormatChange: function(model, value) {
55
+ var eventData = {
56
+ part_id: model.id,
57
+ selector: '.happyforms-part-date__time-input--period'
58
+ };
59
+
60
+ var eventDataHoursField = {
61
+ part_id: model.id,
62
+ selector: '.format-24'
63
+ };
64
+
65
+ if (value === '12') {
66
+ eventData['css'] = {
67
+ display: 'block'
68
+ };
69
+
70
+ eventDataHoursField['css'] = {
71
+ display: 'none'
72
+ };
73
  } else {
74
+ eventData['css'] = {
75
+ display: 'none'
76
+ };
77
+
78
+ eventDataHoursField['css'] = {
79
+ display: 'block'
80
+ };
81
  }
82
+
83
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
84
+ api.previewer.trigger('happyforms-part-dom-update', eventDataHoursField);
85
  }
86
  } );
87
 
assets/js/parts/part-legal.js ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($, _, Backbone, api, settings) {
2
+
3
+ var LegalModel = happyForms.classes.models.Part.extend({
4
+ defaults: function () {
5
+ return _.extend(
6
+ {},
7
+ settings.formParts.legal.defaults,
8
+ _.result(happyForms.classes.models.Part.prototype, 'defaults'),
9
+ );
10
+ },
11
+ });
12
+
13
+ var LegalView = happyForms.classes.views.Part.extend({
14
+ template: '#happyforms-legal-template',
15
+
16
+ initialize: function() {
17
+ happyForms.classes.views.Part.prototype.initialize.apply(this, arguments);
18
+
19
+ this.listenTo(this.model, 'change:legal_text', this.onLegalTextChange);
20
+ },
21
+
22
+ onLegalTextChange: function() {
23
+ var eventData = {
24
+ part_id: this.model.id,
25
+ selector: 'label span',
26
+ text: this.model.get('legal_text')
27
+ };
28
+
29
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
30
+ }
31
+ });
32
+
33
+ happyForms.factory.model = _.wrap(happyForms.factory.model, function (func, attrs, options, BaseClass) {
34
+ if ('legal' === attrs.type) {
35
+ BaseClass = LegalModel;
36
+ }
37
+
38
+ return func(attrs, options, BaseClass);
39
+ });
40
+
41
+ happyForms.factory.view = _.wrap(happyForms.factory.view, function (func, options, BaseClass) {
42
+ if ('legal' === options.type) {
43
+ BaseClass = LegalView;
44
+ }
45
+
46
+ return func(options, BaseClass);
47
+ });
48
+
49
+ })(jQuery, _, Backbone, wp.customize, _happyFormsSettings);
assets/js/parts/part-number.js CHANGED
@@ -15,9 +15,7 @@
15
  confirmationFieldTemplate: '#happyforms-number-confirmation-template',
16
 
17
  events: _.extend( {}, happyForms.classes.views.Part.prototype.events, {
18
- 'change [name=extra_type]': 'onExtraTypeChange',
19
  'change [name=masked]': 'onMaskedChange',
20
- 'change [name=mask_type]': 'onMaskTypeChange',
21
  'change .confirmation-checkbox': 'onConfirmationCheckboxChange'
22
  } ),
23
 
@@ -27,31 +25,6 @@
27
  this.listenTo(this.model, 'change:confirmation_field_label', this.onConfirmationLabelChange);
28
  },
29
 
30
- /**
31
- * Send updated field type value to previewer.
32
- *
33
- * @since 1.0.0.
34
- *
35
- * @param {object} e JS event.
36
- *
37
- * @return void
38
- */
39
- onExtraTypeChange: function(e) {
40
- var $select = $(e.target);
41
-
42
- this.model.set('extra_type', $select.val());
43
-
44
- var eventData = {
45
- part_id: this.model.id,
46
- selector: 'input',
47
- attributes: {
48
- 'type': this.model.get('extra_type')
49
- }
50
- };
51
-
52
- api.previewer.trigger('happyforms-part-dom-update', eventData);
53
- },
54
-
55
  /**
56
  * Toggle masked input configuration on `Mask this input` checkbox change.
57
  *
@@ -69,44 +42,23 @@
69
  if ($input.is(':checked')) {
70
  this.model.set(attribute, 1);
71
 
 
 
 
72
  // show actual mask input
73
  $maskWrapper.show();
74
  } else {
75
  this.model.set(attribute, 0);
76
 
 
 
 
77
  // empty mask input and hide
78
  $maskWrapper.find('input').val('');
79
  $maskWrapper.hide();
80
  }
81
  },
82
 
83
- /**
84
- * Show different configuration options for each mask type.
85
- * Triggered by 'Field type' select change.
86
- *
87
- * @since 1.0.0.
88
- *
89
- * @param {object} e JS event.
90
- *
91
- * @return void
92
- */
93
- onMaskTypeChange: function(e) {
94
- var $select = $(e.target);
95
- var attribute = $select.data('bind');
96
-
97
- this.model.set(attribute, $select.val());
98
-
99
- this.$el.find('.number-options').hide();
100
-
101
- if ($select.val() === 'numeric') {
102
- this.$el.find('.number-options--numeric').show();
103
- }
104
-
105
- if ($select.val() === 'phone') {
106
- this.$el.find('.number-options--phone').show();
107
- }
108
- },
109
-
110
  /**
111
  * Trigger previewer event on 'Require confirmation of the value' checkbox change.
112
  * Adds a new confirmation field to preview.
15
  confirmationFieldTemplate: '#happyforms-number-confirmation-template',
16
 
17
  events: _.extend( {}, happyForms.classes.views.Part.prototype.events, {
 
18
  'change [name=masked]': 'onMaskedChange',
 
19
  'change .confirmation-checkbox': 'onConfirmationCheckboxChange'
20
  } ),
21
 
25
  this.listenTo(this.model, 'change:confirmation_field_label', this.onConfirmationLabelChange);
26
  },
27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  /**
29
  * Toggle masked input configuration on `Mask this input` checkbox change.
30
  *
42
  if ($input.is(':checked')) {
43
  this.model.set(attribute, 1);
44
 
45
+ // hide inputs for min / max value setting
46
+ this.$el.find('.min-max-wrapper').hide();
47
+
48
  // show actual mask input
49
  $maskWrapper.show();
50
  } else {
51
  this.model.set(attribute, 0);
52
 
53
+ // show inputs for min / max value setting
54
+ this.$el.find('.min-max-wrapper').show();
55
+
56
  // empty mask input and hide
57
  $maskWrapper.find('input').val('');
58
  $maskWrapper.hide();
59
  }
60
  },
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  /**
63
  * Trigger previewer event on 'Require confirmation of the value' checkbox change.
64
  * Adds a new confirmation field to preview.
assets/js/parts/part-phone.js ADDED
@@ -0,0 +1,130 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($, _, Backbone, api, settings) {
2
+
3
+ var PhoneModel = happyForms.classes.models.Part.extend({
4
+ defaults: function () {
5
+ return _.extend(
6
+ {},
7
+ settings.formParts.phone.defaults,
8
+ _.result(happyForms.classes.models.Part.prototype, 'defaults'),
9
+ );
10
+ },
11
+ });
12
+
13
+ var PhoneView = happyForms.classes.views.Part.extend({
14
+ template: '#happyforms-phone-template',
15
+ confirmationFieldTemplate: '#happyforms-phone-confirmation-template',
16
+
17
+ events: _.extend({}, happyForms.classes.views.Part.prototype.events, {
18
+ 'change [name=masked]': 'onMaskedChange',
19
+ 'change .confirmation-checkbox': 'onConfirmationCheckboxChange'
20
+ }),
21
+
22
+ initialize: function () {
23
+ happyForms.classes.views.Part.prototype.initialize.apply(this, arguments);
24
+
25
+ this.listenTo(this.model, 'change:confirmation_field_label', this.onConfirmationLabelChange);
26
+ },
27
+
28
+ /**
29
+ * Toggle masked input configuration on `Mask this input` checkbox change.
30
+ *
31
+ * @since 1.0.0.
32
+ *
33
+ * @param {object} e JS event.
34
+ *
35
+ * @return void
36
+ */
37
+ onMaskedChange: function (e) {
38
+ var $input = $(e.target);
39
+ var attribute = $input.data('bind');
40
+ var $maskWrapper = this.$el.find('.mask-wrapper');
41
+
42
+ if ($input.is(':checked')) {
43
+ this.model.set(attribute, 1);
44
+
45
+ // show actual mask input
46
+ $maskWrapper.show();
47
+
48
+ this.$el.find('.number-options--phone').show();
49
+ } else {
50
+ this.model.set(attribute, 0);
51
+
52
+ // empty mask input and hide
53
+ $maskWrapper.find('input').val('');
54
+ $maskWrapper.hide();
55
+ }
56
+ },
57
+
58
+ /**
59
+ * Trigger previewer event on 'Require confirmation of the value' checkbox change.
60
+ * Adds a new confirmation field to preview.
61
+ *
62
+ * @since 1.0.0.
63
+ *
64
+ * @param {object} e JS event.
65
+ *
66
+ * @return void
67
+ */
68
+ onConfirmationCheckboxChange: function (e) {
69
+ if ($(e.target).is(':checked')) {
70
+ this.model.set('confirmation_field_id', this.model.get('id') + '_confirmation');
71
+
72
+ this.$el.find('.confirmation-field-setting').show();
73
+
74
+ var template = _.template($(this.confirmationFieldTemplate).html());
75
+ var html = template(this.model.toJSON());
76
+
77
+ var eventData = {
78
+ 'part_id': this.model.get('id'),
79
+ 'element': html
80
+ };
81
+
82
+ api.previewer.trigger('happyforms-sub-part-added', eventData);
83
+ } else {
84
+ this.$el.find('.confirmation-field-setting').hide();
85
+
86
+ var eventData = {
87
+ subpart_id: this.model.get('confirmation_field_id')
88
+ };
89
+
90
+ api.previewer.trigger('happyforms-sub-part-removed', eventData);
91
+ }
92
+ },
93
+
94
+ /**
95
+ * Send updated confirmation field label value to previewer.
96
+ *
97
+ * @since 1.0.0.
98
+ *
99
+ * @return void
100
+ */
101
+ onConfirmationLabelChange: function () {
102
+ var value = this.model.get('confirmation_field_label');
103
+
104
+ var eventData = {
105
+ 'part_id': this.model.get('id'),
106
+ 'selector': '.happyforms-part__label--confirmation .label',
107
+ 'text': value
108
+ };
109
+
110
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
111
+ }
112
+ });
113
+
114
+ happyForms.factory.model = _.wrap(happyForms.factory.model, function (func, attrs, options, BaseClass) {
115
+ if ('phone' === attrs.type) {
116
+ BaseClass = PhoneModel;
117
+ }
118
+
119
+ return func(attrs, options, BaseClass);
120
+ });
121
+
122
+ happyForms.factory.view = _.wrap(happyForms.factory.view, function (func, options, BaseClass) {
123
+ if ('phone' === options.type) {
124
+ BaseClass = PhoneView;
125
+ }
126
+
127
+ return func(options, BaseClass);
128
+ });
129
+
130
+ })(jQuery, _, Backbone, wp.customize, _happyFormsSettings);
assets/js/parts/part-placeholder.js CHANGED
@@ -23,7 +23,7 @@
23
  var editorId = $textarea.attr( 'id' );
24
  var editorSettings = {
25
  tinymce: {
26
- toolbar1: 'bold,italic,bullist,numlist,hr',
27
  setup: this.onEditorInit.bind( this ),
28
  },
29
  };
23
  var editorId = $textarea.attr( 'id' );
24
  var editorSettings = {
25
  tinymce: {
26
+ toolbar1: 'bold,italic,bullist,numlist,link,hr',
27
  setup: this.onEditorInit.bind( this ),
28
  },
29
  };
assets/js/parts/part-radio.js CHANGED
@@ -29,6 +29,8 @@
29
  } ),
30
 
31
  ready: function() {
 
 
32
  happyForms.classes.views.Part.prototype.ready.apply( this, arguments );
33
 
34
  _(this.model.get('options')).each(function(option) {
@@ -79,7 +81,8 @@
79
  model = new Backbone.Model({
80
  id: optionId,
81
  is_default: 0,
82
- label: ''
 
83
  });
84
  }
85
 
@@ -101,6 +104,8 @@
101
 
102
  api.previewer.trigger('happyforms-sub-part-added', eventData);
103
  }
 
 
104
  },
105
 
106
  /**
@@ -154,6 +159,10 @@
154
  this.frontendTemplate = '#happyforms-radio-option-frontend-template';
155
 
156
  this.render();
 
 
 
 
157
  },
158
 
159
  events: {
@@ -186,6 +195,10 @@
186
 
187
  this.model.set(attribute, value);
188
 
 
 
 
 
189
  if (previewSelector) {
190
  var eventData = {
191
  selector: '#' + this.model.get('id') + ' ' + previewSelector,
29
  } ),
30
 
31
  ready: function() {
32
+ var self = this;
33
+
34
  happyForms.classes.views.Part.prototype.ready.apply( this, arguments );
35
 
36
  _(this.model.get('options')).each(function(option) {
81
  model = new Backbone.Model({
82
  id: optionId,
83
  is_default: 0,
84
+ label: '',
85
+ description: ''
86
  });
87
  }
88
 
104
 
105
  api.previewer.trigger('happyforms-sub-part-added', eventData);
106
  }
107
+
108
+ view.trigger('ready');
109
  },
110
 
111
  /**
159
  this.frontendTemplate = '#happyforms-radio-option-frontend-template';
160
 
161
  this.render();
162
+
163
+ this.listenTo(this, 'ready', this.ready);
164
+
165
+ this.listenTo(this.parent.model, 'change:display_type', this.onDisplayTypeChange);
166
  },
167
 
168
  events: {
195
 
196
  this.model.set(attribute, value);
197
 
198
+ if (attribute === 'description') {
199
+ previewSelector = '+ ' + previewSelector;
200
+ }
201
+
202
  if (previewSelector) {
203
  var eventData = {
204
  selector: '#' + this.model.get('id') + ' ' + previewSelector,
assets/js/parts/part-scale.js ADDED
@@ -0,0 +1,134 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($, _, Backbone, api, settings) {
2
+
3
+ var ScaleModel = happyForms.classes.models.Part.extend({
4
+ defaults: function () {
5
+ return _.extend(
6
+ {},
7
+ settings.formParts.scale.defaults,
8
+ _.result(happyForms.classes.models.Part.prototype, 'defaults'),
9
+ );
10
+ },
11
+ });
12
+
13
+ var ScaleView = happyForms.classes.views.Part.extend({
14
+ template: '#happyforms-scale-template',
15
+
16
+ initialize: function() {
17
+ happyForms.classes.views.Part.prototype.initialize.apply(this, arguments);
18
+
19
+ this.listenTo(this.model, 'change:min_value', this.onMinValueChange);
20
+ this.listenTo(this.model, 'change:max_value', this.onMaxValueChange);
21
+ this.listenTo(this.model, 'change:step', this.onStepChange);
22
+ this.listenTo(this.model, 'change:min_label', this.onMinLabelChange);
23
+ this.listenTo(this.model, 'change:max_label', this.onMaxLabelChange);
24
+ },
25
+
26
+ onMinValueChange: function(model, value) {
27
+ var eventData = {
28
+ part_id: model.id,
29
+ selector: 'input',
30
+ attributes: {
31
+ 'min': value,
32
+ 'value': value,
33
+ }
34
+ };
35
+
36
+ if (model.get('max_value') < value) {
37
+ eventData.attributes['max'] = value + 1;
38
+ }
39
+
40
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
41
+
42
+ eventData = {
43
+ part_id: model.id,
44
+ selector: 'output',
45
+ text: value
46
+ };
47
+
48
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
49
+ },
50
+
51
+ onMaxValueChange: function(model, value) {
52
+ var eventData = {
53
+ part_id: model.id,
54
+ selector: 'input',
55
+ attributes: {
56
+ 'max': value
57
+ }
58
+ };
59
+
60
+ if (model.get('min_value') > value) {
61
+ eventData.attributes['max'] = model.get('min_value') + 1;
62
+ }
63
+
64
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
65
+ },
66
+
67
+ onStepChange: function(model, value) {
68
+ var eventData = {
69
+ part_id: model.id,
70
+ selector: 'input',
71
+ attributes: {
72
+ 'step': value
73
+ }
74
+ };
75
+
76
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
77
+ },
78
+
79
+ onMinLabelChange: function(model, value) {
80
+ var eventData = {
81
+ part_id: model.id,
82
+ selector: '.label-min',
83
+ text: value
84
+ };
85
+
86
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
87
+ },
88
+
89
+ onMaxLabelChange: function (model, value) {
90
+ var eventData = {
91
+ part_id: model.id,
92
+ selector: '.label-max',
93
+ text: value
94
+ };
95
+
96
+ api.previewer.trigger('happyforms-part-dom-update', eventData);
97
+ }
98
+ });
99
+
100
+ happyForms.factory.model = _.wrap(happyForms.factory.model, function (func, attrs, options, BaseClass) {
101
+ if ('scale' === attrs.type) {
102
+ BaseClass = ScaleModel;
103
+ }
104
+
105
+ return func(attrs, options, BaseClass);
106
+ });
107
+
108
+ happyForms.factory.view = _.wrap(happyForms.factory.view, function (func, options, BaseClass) {
109
+ if ('scale' === options.type) {
110
+ BaseClass = ScaleView;
111
+ }
112
+
113
+ return func(options, BaseClass);
114
+ });
115
+
116
+ api.bind('ready', function () {
117
+ api.previewer.bind('happyforms-part-render', function ($el) {
118
+ if (!$el.is('.happyforms-part--scale')) {
119
+ return;
120
+ }
121
+
122
+ $('input', $el).happyFormsScale();
123
+ });
124
+
125
+ api.previewer.bind('happyforms-part-dom-updated', function ($el) {
126
+ if (!$el.is('.happyforms-part--scale')) {
127
+ return;
128
+ }
129
+
130
+ $('input', $el).happyFormsScale();
131
+ });
132
+ });
133
+
134
+ })(jQuery, _, Backbone, wp.customize, _happyFormsSettings);
assets/js/parts/part-title.js ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function ($, _, Backbone, api, settings) {
2
+
3
+ var TitleModel = happyForms.classes.models.Part.extend({
4
+ defaults: function () {
5
+ return _.extend(
6
+ {},
7
+ settings.formParts.title.defaults,
8
+ _.result(happyForms.classes.models.Part.prototype, 'defaults'),
9
+ );
10
+ },
11
+ });
12
+
13
+ var TitleView = happyForms.classes.views.Part.extend({
14
+ template: '#happyforms-title-template'
15
+ });
16
+
17
+ happyForms.factory.model = _.wrap(happyForms.factory.model, function (func, attrs, options, BaseClass) {
18
+ if ('title' === attrs.type) {
19
+ BaseClass = TitleModel;
20
+ }
21
+
22
+ return func(attrs, options, BaseClass);
23
+ });
24
+
25
+ happyForms.factory.view = _.wrap(happyForms.factory.view, function (func, options, BaseClass) {
26
+ if ('title' === options.type) {
27
+ BaseClass = TitleView;
28
+ }
29
+
30
+ return func(options, BaseClass);
31
+ });
32
+
33
+ })(jQuery, _, Backbone, wp.customize, _happyFormsSettings);
assets/js/preview.js CHANGED
@@ -95,6 +95,8 @@
95
  });
96
 
97
  api.previewer.trigger( 'happyforms-preview-ready' );
 
 
98
  },
99
 
100
  addView: function(modelAttributes) {
@@ -103,6 +105,25 @@
103
  this.elements.add(model);
104
  },
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  onDOMPartUpdate: function(data) {
107
  if (!data || !data.selector) {
108
  return;
@@ -155,6 +176,16 @@
155
  $element.removeClass(data.classes);
156
  }
157
  }
 
 
 
 
 
 
 
 
 
 
158
  },
159
 
160
  onPartWidthUpdate: function(data) {
@@ -259,6 +290,7 @@
259
  }
260
 
261
  this.setElement(partHtml);
 
262
 
263
  return this;
264
  },
@@ -293,13 +325,9 @@
293
 
294
  api.bind( 'ready', function() {
295
  api.previewer.bind('ready', function() {
296
- if (api.previewer.getFrontendPreviewUrl().indexOf('happyform') === -1) {
297
- api.previewer.previewUrl('/?happyformsPlaceholder');
298
- } else {
299
- happyFormsPreview = window.happyFormsPreview = new HappyFormsPreview({
300
- el: api.previewer.preview.iframe
301
- });
302
- }
303
  });
304
 
305
  api.previewer.bind('happyforms-form-part-added', function(data) {
@@ -319,6 +347,23 @@
319
  }
320
  });
321
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
  api.previewer.bind('happyforms-form-part-removed', function(data) {
323
  if (data) {
324
  var formID = data.form_id;
95
  });
96
 
97
  api.previewer.trigger( 'happyforms-preview-ready' );
98
+
99
+ this.setPageTitle();
100
  },
101
 
102
  addView: function(modelAttributes) {
105
  this.elements.add(model);
106
  },
107
 
108
+ redrawView: function( modelAttributes ) {
109
+ var model = this.elements.find( {
110
+ elementID: modelAttributes.elementID
111
+ } );
112
+
113
+ model.set( modelAttributes );
114
+
115
+ var $previousEl = model.get( 'view' ).$el;
116
+ $previousEl.hide();
117
+ $previousEl.after( model.get( 'view' ).render().$el );
118
+ $previousEl.remove();
119
+ },
120
+
121
+ setPageTitle: function () {
122
+ var title = $('title').text();
123
+
124
+ $('title').text(title.replace('Customize:', 'Edit Form ‹'));
125
+ },
126
+
127
  onDOMPartUpdate: function(data) {
128
  if (!data || !data.selector) {
129
  return;
176
  $element.removeClass(data.classes);
177
  }
178
  }
179
+
180
+ var $updatedEl = this.$el;
181
+
182
+ if ( data.part_id ) {
183
+ $updatedEl = this.elements.findWhere( {
184
+ elementID: data.part_id
185
+ } ).get( 'view' ).$el;
186
+ }
187
+
188
+ api.previewer.trigger( 'happyforms-part-dom-updated', $updatedEl );
189
  },
190
 
191
  onPartWidthUpdate: function(data) {
290
  }
291
 
292
  this.setElement(partHtml);
293
+ api.previewer.trigger( 'happyforms-part-render', this.$el );
294
 
295
  return this;
296
  },
325
 
326
  api.bind( 'ready', function() {
327
  api.previewer.bind('ready', function() {
328
+ happyFormsPreview = window.happyFormsPreview = new HappyFormsPreview({
329
+ el: api.previewer.preview.iframe
330
+ });
 
 
 
 
331
  });
332
 
333
  api.previewer.bind('happyforms-form-part-added', function(data) {
347
  }
348
  });
349
 
350
+ api.previewer.bind('happyforms-form-part-refresh', function(data) {
351
+ if (data) {
352
+ var formID = data.form_id;
353
+ var partID = data.part_id;
354
+ var template = data.html;
355
+
356
+ var modelAttributes = {
357
+ elementID: partID,
358
+ formID: formID,
359
+ fieldName: $(template).attr('data-happyforms-field-name'),
360
+ html: template
361
+ };
362
+
363
+ happyFormsPreview.redrawView( modelAttributes );
364
+ }
365
+ });
366
+
367
  api.previewer.bind('happyforms-form-part-removed', function(data) {
368
  if (data) {
369
  var formID = data.form_id;
assets/svg/happyforms-logo.svg DELETED
@@ -1 +0,0 @@
1
- <svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 336 336"><defs><style>.cls-1{isolation:isolate;}.cls-2{fill:#555d66;}</style></defs><title>happyforms-logo</title><image id="Layer_0" data-name="Layer 0" class="cls-1" width="94" height="90" transform="translate(120 122)" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF4AAABaCAYAAAAxQ+F4AAAACXBIWXMAAAsSAAALEgHS3X78AAAA3klEQVR4Xu3QoQHAIBDAwNL9d35GQEHMnY7KmpmP9/5TwB3GR4yPGB8xPmJ8xPiI8RHjI8ZHjI8YHzE+YnzE+IjxEeMjxkeMjxgfMT5ifMT4iPER4yPGR4yPGB8xPmJ8xPiI8RHjI8ZHjI8YHzE+YnzE+IjxEeMjxkeMjxgfMT5ifMT4iPER4yPGR4yPGB8xPmJ8xPiI8RHjI8ZHjI8YHzE+YnzE+IjxEeMjxkeMjxgfMT5ifMT4iPER4yPGR4yPGB8xPmJ8xPiI8RHjI8ZHjI8YHzE+YnzE+IjxEeMjG0FrA7G1UTQxAAAAAElFTkSuQmCC"/><path class="cls-2" d="M98.78,217l0,0-.21-.16Z"/><path class="cls-2" d="M99.13,217.46c.91,1,.6.55.11,0l-.3-.31-.07-.06-.09-.07C98.9,217.17,99,217.32,99.13,217.46Z"/><path class="cls-2" d="M153.54,237.8h0Z"/><path class="cls-2" d="M229.24,210.12l0,0C228.55,210.78,227.94,211.42,229.24,210.12Z"/><path class="cls-2" d="M332.61,182.27,303.42,73.34h0A98.91,98.91,0,0,0,182.27,3.4L73.34,32.58h0A98.92,98.92,0,0,0,3.4,153.74L32.58,262.66h0a98.92,98.92,0,0,0,121.15,69.95l108.93-29.19h0A98.92,98.92,0,0,0,332.61,182.27ZM182.8,106.81a19.8,19.8,0,0,1,6.7-9.09,25.37,25.37,0,0,1,4-4.28c10.18-8.7,27.62-5.55,34.33,6a27.62,27.62,0,0,1,2.61,21A26,26,0,0,1,216.22,138c-12.36,5.92-29.61,1.58-35.08-11.73A21.35,21.35,0,0,1,182.8,106.81ZM106.39,95a25.37,25.37,0,0,1,4-4.28c10.18-8.7,27.63-5.55,34.33,6a27.58,27.58,0,0,1,2.61,21c-2.09,7.88-6.78,14-14.19,17.5-12.36,5.93-29.61,1.59-35.08-11.72a21.35,21.35,0,0,1,1.66-19.45A19.8,19.8,0,0,1,106.39,95Zm182.75,56.46c-2.16,23.22-11.5,45.63-25.41,64.25A129.68,129.68,0,0,1,214,255.65c-20.48,9.45-43.23,12.8-65.62,11.44a134.52,134.52,0,0,1-33-6.59c-11.12-3.57-22.09-8.88-31.08-16.42C63.94,227,52.35,200.84,47.76,175.17,46.29,167,53.73,160,61.16,159a15.17,15.17,0,0,1,10.73,3.23c3.25,2.62,4.76,6.18,5.48,10.18a47.34,47.34,0,0,1,1,5l.54,2q1.23,4.37,2.79,8.63,1.66,4.51,3.71,8.87c.66,1.41,1.38,2.79,2.07,4.19.34.58.67,1.17,1,1.74A93.94,93.94,0,0,0,98.75,217l.12.1.07.06.3.31c.26.27.51.57.73.77,1.09,1,2.21,2,3.38,3s2.31,1.84,3.52,2.7l1.84,1.24a99.09,99.09,0,0,0,13.14,6.2c1.46.55,2.93,1.07,4.41,1.57.56.18,4,1.42,1.65.54s1.59.42,2.11.56c1,.27,2.06.52,3.09.76a121.68,121.68,0,0,0,14.32,2.45c2.28.25,4.56.4,6.85.55l1.08,0c1.21,0,2.42,0,3.63,0a122.11,122.11,0,0,0,14-1c2.55-.33,5.09-.75,7.61-1.24.82-.16,1.63-.34,2.44-.52l1.2-.3A119.09,119.09,0,0,0,198,230.19q3.38-1.35,6.65-2.91c1.09-.52,2.18-1.05,3.25-1.61l.24-.12a139.72,139.72,0,0,0,21.35-15.71c.2-.21.4-.41.61-.61.78-.8,1.56-1.61,2.33-2.44,1.44-1.54,2.83-3.13,4.18-4.74a117.64,117.64,0,0,0,8-10.84c.68-1,2.42-4.73.49-.69.47-1,1.15-1.94,1.69-2.91q1.56-2.76,2.95-5.59a115,115,0,0,0,5.1-12c.42-1.19.83-2.38,1.21-3.57,0-.12.07-.25.12-.41q.84-3,1.52-6.13a110.54,110.54,0,0,0,2.05-13.31c.76-8.27,9.6-13.14,17.11-12.22C285.29,135.4,289.86,143.76,289.14,151.49Z"/></svg>
 
assets/svg/icons/phone.svg ADDED
@@ -0,0 +1 @@
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.cls-1{fill:none;stroke:#32373c;stroke-linecap:round;stroke-miterlimit:10;stroke-width:6px;}</style></defs><title>Asset 26</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_2-2" data-name="Layer 2"><rect class="cls-1" x="3" y="3" width="32.26" height="58" rx="2" ry="2"/><line class="cls-1" x1="3" y1="47.29" x2="35.26" y2="47.29"/><line class="cls-1" x1="3" y1="16.29" x2="35.26" y2="16.29"/></g><g id="Layer_4" data-name="Layer 4"><line class="cls-1" x1="48.11" y1="31.37" x2="61" y2="31.37"/><line class="cls-1" x1="48.4" y1="17.67" x2="60.7" y2="13.07"/><line class="cls-1" x1="48.84" y1="43.82" x2="60.27" y2="50.93"/></g></g></svg>
assets/svg/icons/scale.svg ADDED
@@ -0,0 +1 @@
 
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64"><defs><style>.cls-1{fill:none;stroke:#32373c;stroke-linecap:round;stroke-miterlimit:10;stroke-width:6px;}</style></defs><title>Asset 25</title><g id="Layer_2" data-name="Layer 2"><g id="Layer_2-2" data-name="Layer 2"><rect class="cls-1" x="3" y="3" width="58" height="58" rx="2" ry="2"/><circle class="cls-1" cx="32" cy="32" r="11.02"/><line class="cls-1" x1="20.98" y1="32" x2="3" y2="32"/><line class="cls-1" x1="43.02" y1="32" x2="61" y2="32"/></g></g></svg>
happyforms.php CHANGED
@@ -5,7 +5,7 @@
5
  * Plugin URI: https://happyforms.me
6
  * Description: Your friendly drag and drop contact form builder for creating contact forms, lead generation forms, feedback forms, quote forms, survey forms and more!
7
  * Author: The Theme Foundry
8
- * Version: 1.0
9
  * Author URI: https://thethemefoundry.com
10
  * Upgrade URI: https://thethemefoundry.com
11
  */
@@ -13,7 +13,7 @@
13
  /**
14
  * The current version of the plugin.
15
  */
16
- define( 'HAPPYFORMS_VERSION', '1.0' );
17
 
18
  if ( ! function_exists( 'happyforms_plugin_file' ) ):
19
  /**
5
  * Plugin URI: https://happyforms.me
6
  * Description: Your friendly drag and drop contact form builder for creating contact forms, lead generation forms, feedback forms, quote forms, survey forms and more!
7
  * Author: The Theme Foundry
8
+ * Version: 1.2
9
  * Author URI: https://thethemefoundry.com
10
  * Upgrade URI: https://thethemefoundry.com
11
  */
13
  /**
14
  * The current version of the plugin.
15
  */
16
+ define( 'HAPPYFORMS_VERSION', '1.2' );
17
 
18
  if ( ! function_exists( 'happyforms_plugin_file' ) ):
19
  /**
inc/classes/class-form-controller.php CHANGED
@@ -47,7 +47,9 @@ class HappyForms_Form_Controller {
47
  public function hook() {
48
  add_action( 'init', array( $this, 'register_post_type' ) );
49
  add_filter( 'single_template', array( $this, 'single_template' ) );
 
50
  add_action( 'delete_post', array( $this, 'delete_post' ) );
 
51
  }
52
 
53
  /**
@@ -138,7 +140,7 @@ class HappyForms_Form_Controller {
138
  'sanitize' => 'sanitize_text_field',
139
  ),
140
  'post_status' => array(
141
- 'default' => 'draft',
142
  'sanitize' => 'happyforms_sanitize_post_status',
143
  ),
144
  'post_type' => array(
@@ -172,7 +174,7 @@ class HappyForms_Form_Controller {
172
  'sanitize' => 'happyforms_sanitize_checkbox',
173
  ),
174
  'submit_button_label' => array(
175
- 'default' => __( 'Submit', 'happyforms' ),
176
  'sanitize' => 'sanitize_text_field',
177
  ),
178
  'form_expiration_datetime' => array(
@@ -277,7 +279,7 @@ class HappyForms_Form_Controller {
277
  $validated_data = $this->validate_data();
278
  $post_attributes = array(
279
  'post_type' => happyforms_get_form_controller()->post_type,
280
- 'post_status' => 'draft',
281
  );
282
  $post_data = array_merge( $validated_data['post'], $post_attributes );
283
  $meta_data = array( 'meta_input' => $validated_data['meta'] );
@@ -308,7 +310,7 @@ class HappyForms_Form_Controller {
308
  public function get( $post_ids = array(), $only_id = false ) {
309
  $query_params = array(
310
  'post_type' => happyforms_get_form_controller()->post_type,
311
- 'post_status' => 'any',
312
  'posts_per_page' => -1,
313
  );
314
 
@@ -464,6 +466,52 @@ class HappyForms_Form_Controller {
464
  foreach ( $messages as $message ) {
465
  wp_delete_post( $message->ID, true );
466
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467
  }
468
 
469
  /**
@@ -545,17 +593,6 @@ class HappyForms_Form_Controller {
545
  return $form_markup;
546
  }
547
 
548
- /**
549
- * Output scripts in the header of a form.
550
- *
551
- * @since 1.0
552
- *
553
- * @param array $form The form data.
554
- *
555
- * @return string
556
- */
557
- public function header_scripts( $form = array() ) {}
558
-
559
  }
560
 
561
  if ( ! function_exists( 'happyforms_get_form_controller' ) ):
47
  public function hook() {
48
  add_action( 'init', array( $this, 'register_post_type' ) );
49
  add_filter( 'single_template', array( $this, 'single_template' ) );
50
+ add_action( 'trashed_post', array( $this, 'trashed_post' ) );
51
  add_action( 'delete_post', array( $this, 'delete_post' ) );
52
+ add_action( 'untrashed_post', array( $this, 'untrashed_post' ) );
53
  }
54
 
55
  /**
140
  'sanitize' => 'sanitize_text_field',
141
  ),
142
  'post_status' => array(
143
+ 'default' => 'publish',
144
  'sanitize' => 'happyforms_sanitize_post_status',
145
  ),
146
  'post_type' => array(
174
  'sanitize' => 'happyforms_sanitize_checkbox',
175
  ),
176
  'submit_button_label' => array(
177
+ 'default' => __( 'Submit Form', 'happyforms' ),
178
  'sanitize' => 'sanitize_text_field',
179
  ),
180
  'form_expiration_datetime' => array(
279
  $validated_data = $this->validate_data();
280
  $post_attributes = array(
281
  'post_type' => happyforms_get_form_controller()->post_type,
282
+ 'post_status' => 'publish',
283
  );
284
  $post_data = array_merge( $validated_data['post'], $post_attributes );
285
  $meta_data = array( 'meta_input' => $validated_data['meta'] );
310
  public function get( $post_ids = array(), $only_id = false ) {
311
  $query_params = array(
312
  'post_type' => happyforms_get_form_controller()->post_type,
313
+ 'post_status' => 'publish',
314
  'posts_per_page' => -1,
315
  );
316
 
466
  foreach ( $messages as $message ) {
467
  wp_delete_post( $message->ID, true );
468
  }
469
+
470
+ happyforms_get_message_controller()->update_badge_transient();
471
+ }
472
+
473
+ /**
474
+ * Action: trigger an update to the unread messages badge
475
+ * when a form is trashed.
476
+ *
477
+ * @since 1.1
478
+ *
479
+ * @hooked action trashed_post
480
+ *
481
+ * @param int|string $post_id The ID of the form object.
482
+ *
483
+ * @return void
484
+ */
485
+ public function trashed_post( $post_id ) {
486
+ $post = get_post( $post_id );
487
+
488
+ if ( $this->post_type !== $post->post_type ) {
489
+ return;
490
+ }
491
+
492
+ happyforms_get_message_controller()->update_badge_transient();
493
+ }
494
+
495
+ /**
496
+ * Action: trigger an update to the unread messages badge
497
+ * when a form is restored.
498
+ *
499
+ * @since 1.1
500
+ *
501
+ * @hooked action untrashed_post
502
+ *
503
+ * @param int|string $post_id The ID of the form object.
504
+ *
505
+ * @return void
506
+ */
507
+ public function untrashed_post( $post_id ) {
508
+ $post = get_post( $post_id );
509
+
510
+ if ( $this->post_type !== $post->post_type ) {
511
+ return;
512
+ }
513
+
514
+ happyforms_get_message_controller()->update_badge_transient();
515
  }
516
 
517
  /**
593
  return $form_markup;
594
  }
595
 
 
 
 
 
 
 
 
 
 
 
 
596
  }
597
 
598
  if ( ! function_exists( 'happyforms_get_form_controller' ) ):
inc/classes/class-form-part-library.php CHANGED
@@ -13,8 +13,12 @@ class HappyForms_Form_Part_Library {
13
  'HappyForms_Part_Radio' => 'class-part-radio',
14
  'HappyForms_Part_Select' => 'class-part-select',
15
  'HappyForms_Part_Number' => 'class-part-number',
 
16
  'HappyForms_Part_Date' => 'class-part-date',
17
- 'HappyForms_Part_Country' => 'class-part-country',
 
 
 
18
  'HappyForms_Part_Rating' => 'class-part-rating',
19
  'HappyForms_Part_Placeholder' => 'class-part-placeholder',
20
  );
@@ -38,11 +42,27 @@ class HappyForms_Form_Part_Library {
38
  }
39
  }
40
 
 
 
 
 
 
 
 
41
  public function hook() {
42
  add_action( 'customize_controls_print_footer_scripts', array( $this, 'customize_templates' ) );
43
  add_action( 'customize_controls_enqueue_scripts', array( $this, 'customize_enqueue_scripts' ) );
44
  }
45
 
 
 
 
 
 
 
 
 
 
46
  public function register_part( $part ) {
47
  if ( $part instanceof HappyForms_Form_Part ) {
48
  $this->parts[ $this->hash_object( $part ) ] = $part;
@@ -51,6 +71,13 @@ class HappyForms_Form_Part_Library {
51
  }
52
  }
53
 
 
 
 
 
 
 
 
54
  public function get_parts() {
55
  $parts_data = array();
56
 
@@ -63,6 +90,15 @@ class HappyForms_Form_Part_Library {
63
  return $parts_data;
64
  }
65
 
 
 
 
 
 
 
 
 
 
66
  public function get_part( $type ) {
67
  foreach ( $this->parts as $part ) {
68
  if ( $type === $part->type ) {
@@ -73,6 +109,13 @@ class HappyForms_Form_Part_Library {
73
  return false;
74
  }
75
 
 
 
 
 
 
 
 
76
  public function customize_templates() {
77
  foreach ( $this->parts as $part ) {
78
  ?>
@@ -110,6 +153,13 @@ class HappyForms_Form_Part_Library {
110
  }
111
  }
112
 
 
 
 
 
 
 
 
113
  public function customize_enqueue_scripts() {
114
  $deps = array( 'happyforms-customize' );
115
 
@@ -132,6 +182,15 @@ class HappyForms_Form_Part_Library {
132
  return '';
133
  }
134
 
 
 
 
 
 
 
 
 
 
135
  public function validate_part( $part_data = array() ) {
136
  if ( ! isset( $part_data['type'] ) || ! isset( $part_data['id'] ) ) {
137
  $error = new WP_Error( 'part', __( 'Invalid data' ) );
@@ -156,16 +215,28 @@ class HappyForms_Form_Part_Library {
156
  );
157
 
158
  foreach ( $fields as $field_name => $field_settings ) {
159
- if ( array_key_exists( 'sanitize', $field_settings ) && is_callable( $field_settings['sanitize'] ) ) {
160
- $validation_callback = $field_settings['sanitize'];
161
- $field_value = $input_data[$field_name];
162
- $validated_data[$field_name] = call_user_func( $validation_callback, $field_value );
163
- } else {
164
- $error = new WP_Error( 'part', sprintf(
165
- __( 'Missing validation callback for field %s', 'happyforms' ),
166
- $field_name
167
- ) );
168
- return $error;
 
 
 
 
 
 
 
 
 
 
 
 
169
  }
170
  }
171
 
13
  'HappyForms_Part_Radio' => 'class-part-radio',
14
  'HappyForms_Part_Select' => 'class-part-select',
15
  'HappyForms_Part_Number' => 'class-part-number',
16
+ 'HappyForms_Part_Phone' => 'class-part-phone',
17
  'HappyForms_Part_Date' => 'class-part-date',
18
+ 'HappyForms_Part_Address' => 'class-part-address',
19
+ 'HappyForms_Part_Scale' => 'class-part-scale',
20
+ 'HappyForms_Part_Title' => 'class-part-title',
21
+ 'HappyForms_Part_Legal' => 'class-part-legal',
22
  'HappyForms_Part_Rating' => 'class-part-rating',
23
  'HappyForms_Part_Placeholder' => 'class-part-placeholder',
24
  );
42
  }
43
  }
44
 
45
+ /**
46
+ * Hook into WordPress.
47
+ *
48
+ * @since 1.0.0.
49
+ *
50
+ * @return void
51
+ */
52
  public function hook() {
53
  add_action( 'customize_controls_print_footer_scripts', array( $this, 'customize_templates' ) );
54
  add_action( 'customize_controls_enqueue_scripts', array( $this, 'customize_enqueue_scripts' ) );
55
  }
56
 
57
+ /**
58
+ * Register individual parts.
59
+ *
60
+ * @since 1.0.0.
61
+ *
62
+ * @param object $part Part object.
63
+ *
64
+ * @return void
65
+ */
66
  public function register_part( $part ) {
67
  if ( $part instanceof HappyForms_Form_Part ) {
68
  $this->parts[ $this->hash_object( $part ) ] = $part;
71
  }
72
  }
73
 
74
+ /**
75
+ * Get all form parts.
76
+ *
77
+ * @since 1.0.0.
78
+ *
79
+ * @return array Parts data.
80
+ */
81
  public function get_parts() {
82
  $parts_data = array();
83
 
90
  return $parts_data;
91
  }
92
 
93
+ /**
94
+ * Get part by type.
95
+ *
96
+ * @since 1.0.0.
97
+ *
98
+ * @param string $type Part type.
99
+ *
100
+ * @return array|bool
101
+ */
102
  public function get_part( $type ) {
103
  foreach ( $this->parts as $part ) {
104
  if ( $type === $part->type ) {
109
  return false;
110
  }
111
 
112
+ /**
113
+ * Print each part's Backbone templates for use in Customizer interface.
114
+ *
115
+ * @since 1.0.0.
116
+ *
117
+ * @return void
118
+ */
119
  public function customize_templates() {
120
  foreach ( $this->parts as $part ) {
121
  ?>
153
  }
154
  }
155
 
156
+ /**
157
+ * Call `customize_enqueue_scripts` method in all parts to add scripts to Customizer area.
158
+ *
159
+ * @since 1.0.0.
160
+ *
161
+ * @return void
162
+ */
163
  public function customize_enqueue_scripts() {
164
  $deps = array( 'happyforms-customize' );
165
 
182
  return '';
183
  }
184
 
185
+ /**
186
+ * Applies validation rules to part data passed to method.
187
+ *
188
+ * @since 1.0.0.
189
+ *
190
+ * @param array $part_data Form part data.
191
+ *
192
+ * @return array $validated_data Validated form part data.
193
+ */
194
  public function validate_part( $part_data = array() ) {
195
  if ( ! isset( $part_data['type'] ) || ! isset( $part_data['id'] ) ) {
196
  $error = new WP_Error( 'part', __( 'Invalid data' ) );
215
  );
216
 
217
  foreach ( $fields as $field_name => $field_settings ) {
218
+ if ( array_key_exists( 'sanitize', $field_settings ) ) {
219
+ $sanitize_settings = $field_settings['sanitize'];
220
+ $sanitize_settings = is_array( $sanitize_settings ) ? $sanitize_settings : array( $sanitize_settings );
221
+ $sanitize_callback = $sanitize_settings[0];
222
+ $sanitize_arguments = array_slice( $sanitize_settings, 1 );
223
+
224
+ if ( is_callable( $sanitize_callback ) ) {
225
+ $field_value = $input_data[$field_name];
226
+
227
+ if ( empty( $sanitize_arguments ) ) {
228
+ $validated_data[$field_name] = call_user_func( $sanitize_callback, $field_value );
229
+ } else {
230
+ $validated_data[$field_name] = call_user_func( $sanitize_callback, $field_value, $sanitize_arguments[0] );
231
+ }
232
+ } else {
233
+ $error = new WP_Error( 'part', sprintf(
234
+ __( 'Missing validation callback for field %s', 'happyforms' ),
235
+ $field_name
236
+ ) );
237
+
238
+ return $error;
239
+ }
240
  }
241
  }
242
 
inc/classes/class-form-styles.php CHANGED
@@ -2,8 +2,22 @@
2
 
3
  class HappyForms_Form_Styles {
4
 
 
 
 
 
 
 
 
5
  private static $instance;
6
 
 
 
 
 
 
 
 
7
  public static function instance() {
8
  if ( is_null( self::$instance ) ) {
9
  self::$instance = new self();
@@ -14,10 +28,6 @@ class HappyForms_Form_Styles {
14
  return self::$instance;
15
  }
16
 
17
- public function __construct() {
18
- $this->part_selector = '.happyforms-part > input, .happyforms-part > textarea';
19
- }
20
-
21
  /**
22
  * Hook into WordPress.
23
  *
@@ -28,14 +38,13 @@ class HappyForms_Form_Styles {
28
  public function hook() {
29
  add_filter( 'happyforms_fields', array( $this, 'add_fields' ) );
30
  add_action( 'happyforms_print_css', array( $this, 'print_css' ), 10, 1 );
31
-
32
  add_action( 'wp_ajax_happyforms_load_styles', array( $this, 'load_styles') );
33
  }
34
 
35
  /**
36
  * Get styles by key or all styles as array.
37
  *
38
- * @param string $key Style key.
39
  *
40
  * @since 1.0.0.
41
  *
@@ -45,7 +54,7 @@ class HappyForms_Form_Styles {
45
  $fields = array(
46
  'hf_form_title' => array(
47
  'type' => 'divider',
48
- 'html' => '<h2 class="group-title">' . __( 'General form styles', 'happyforms' ) . '</h2>'
49
  ),
50
  'hf_style_display_form_name' => array(
51
  'default' => 1,
@@ -62,7 +71,7 @@ class HappyForms_Form_Styles {
62
  'sanitize' => 'happyforms_sanitize_checkbox'
63
  ),
64
  'hf_style_form_font_size' => array(
65
- 'default' => 16,
66
  'type' => 'range',
67
  'min' => 8,
68
  'max' => 30,
@@ -150,7 +159,7 @@ class HappyForms_Form_Styles {
150
  ),
151
  'hf_form_parts_title' => array(
152
  'type' => 'divider',
153
- 'html' => '<h2 class="group-title">' . __( 'Form parts', 'happyforms' ) . '</h2>'
154
  ),
155
  'hf_style_hide_part_titles' => array(
156
  'default' => 0,
@@ -159,7 +168,7 @@ class HappyForms_Form_Styles {
159
  'selector' => array( '.happyforms-part__label' ),
160
  'attribute' => array( 'display' ),
161
  'value' => array(
162
- 0 => 'block',
163
  1 => 'none'
164
  )
165
  ),
@@ -167,7 +176,7 @@ class HappyForms_Form_Styles {
167
  'sanitize' => 'happyforms_sanitize_checkbox'
168
  ),
169
  'hf_style_part_label_font_weight' => array(
170
- 'default' => 'normal',
171
  'type' => 'buttonset',
172
  'options' => array(
173
  'normal' => 'Normal',
@@ -195,7 +204,7 @@ class HappyForms_Form_Styles {
195
  'sanitize' => 'sanitize_text_field'
196
  ),
197
  'hf_style_part_description_font_size' => array(
198
- 'default' => '14',
199
  'type' => 'range',
200
  'min' => 8,
201
  'max' => 30,
@@ -236,12 +245,12 @@ class HappyForms_Form_Styles {
236
  'sanitize' => 'sanitize_text_field'
237
  ),
238
  'hf_style_part_border' => array(
239
- 'default' => 2,
240
  'type' => 'range',
241
  'min' => 0,
242
  'max' => 10,
243
  'css' => array(
244
- 'selector' => array( '.happyforms-part > input, .happyforms-part > textarea, .happyforms-part > select, .happyforms-part > input:focus, .happyforms-part > textarea:focus, .happyforms-part > select:focus' ),
245
  'attribute' => array( 'border-width' ),
246
  'tpl' => '{{ value }}px'
247
  ),
@@ -249,32 +258,32 @@ class HappyForms_Form_Styles {
249
  'sanitize' => 'sanitize_text_field'
250
  ),
251
  'hf_style_part_border_color' => array(
252
- 'default' => '#000000',
253
  'type' => 'color',
254
  'css' => array(
255
- 'selector' => array( '.happyforms-part > input, .happyforms-part > textarea, .happyforms-part > select' ),
256
  'attribute' => array( 'border-color' )
257
  ),
258
  'label' => __( 'Border color', 'happyforms' ),
259
  'sanitize' => 'sanitize_text_field'
260
  ),
261
  'hf_style_part_border_color_focus' => array(
262
- 'default' => '#000000',
263
  'type' => 'color',
264
  'css' => array(
265
- 'selector' => array( '.happyforms-part > input:focus, .happyforms-part > textarea:focus, .happyforms-part > select:focus' ),
266
  'attribute' => array( 'border-color' )
267
  ),
268
  'label' => __( 'Border color focused', 'happyforms' ),
269
  'sanitize' => 'sanitize_text_field'
270
  ),
271
  'hf_style_part_border_radius' => array(
272
- 'default' => 0,
273
  'type' => 'range',
274
  'min' => 0,
275
  'max' => 20,
276
  'css' => array(
277
- 'selector' => array( '.happyforms-part > input, .happyforms-part > textarea' ),
278
  'attribute' => array( 'border-radius' ),
279
  'tpl' => '{{ value }}px'
280
  ),
@@ -285,7 +294,7 @@ class HappyForms_Form_Styles {
285
  'default' => '#ffffff',
286
  'type' => 'color',
287
  'css' => array(
288
- 'selector' => array( '.happyforms-part > input, .happyforms-part > textarea' ),
289
  'attribute' => array( 'background-color' )
290
  ),
291
  'label' => __( 'Background color', 'happyforms' ),
@@ -295,7 +304,7 @@ class HappyForms_Form_Styles {
295
  'default' => '#ffffff',
296
  'type' => 'color',
297
  'css' => array(
298
- 'selector' => array( '.happyforms-part input:focus, .happyforms-part textarea:focus' ),
299
  'attribute' => array( 'background-color' )
300
  ),
301
  'label' => __( 'Background color focused', 'happyforms' ),
@@ -309,7 +318,7 @@ class HappyForms_Form_Styles {
309
  'background-color' => 'Fade'
310
  ),
311
  'css' => array(
312
- 'selector' => array( '.happyforms-part input, .happyforms-part textarea' ),
313
  'attribute' => array( 'transition-property' )
314
  ),
315
  'label' => __( 'Smooth background change (transition)', 'happyforms' ),
@@ -397,7 +406,7 @@ class HappyForms_Form_Styles {
397
  'sanitize' => 'sanitize_text_field'
398
  ),
399
  'hf_style_required_color' => array(
400
- 'default' => '#c00',
401
  'type' => 'color',
402
  'css' => array(
403
  'selector' => array( '.happyforms-required' ),
@@ -428,7 +437,7 @@ class HappyForms_Form_Styles {
428
  ),
429
  'hf_ratings_part_title' => array(
430
  'type' => 'divider',
431
- 'html' => '<h2 class="group-title">' . __( 'Ratings', 'happyforms' ) . '</h2>'
432
  ),
433
  'hf_style_ratings_star_color' => array(
434
  'default' => '#ccc',
@@ -457,7 +466,7 @@ class HappyForms_Form_Styles {
457
  ),
458
  'hf_submit_button_title' => array(
459
  'type' => 'divider',
460
- 'html' => '<h2 class="group-title">' . __( 'Submit button', 'happyforms' ) . '</h2>'
461
  ),
462
  'hf_style_submit_button_alignment' => array(
463
  'default' => 'left',
@@ -517,7 +526,7 @@ class HappyForms_Form_Styles {
517
  'sanitize' => 'sanitize_text_field'
518
  ),
519
  'hf_style_submit_button_font_size' => array(
520
- 'default' => '18',
521
  'type' => 'range',
522
  'min' => 8,
523
  'max' => 40,
@@ -550,7 +559,7 @@ class HappyForms_Form_Styles {
550
  'sanitize' => 'sanitize_text_field'
551
  ),
552
  'hf_style_submit_button_bg_hover' => array(
553
- 'default' => '#999999',
554
  'type' => 'color',
555
  'css' => array(
556
  'selector' => array( '.happyforms-button--submit:hover' ),
@@ -597,7 +606,7 @@ class HappyForms_Form_Styles {
597
  'sanitize' => 'sanitize_text_field'
598
  ),
599
  'hf_style_submit_button_border_color_hover' => array(
600
- 'default' => '#999999',
601
  'type' => 'color',
602
  'css' => array(
603
  'selector' => array( '.happyforms-button--submit:hover' ),
@@ -607,7 +616,7 @@ class HappyForms_Form_Styles {
607
  'sanitize' => 'sanitize_text_field'
608
  ),
609
  'hf_style_submit_button_border_radius' => array(
610
- 'default' => 0,
611
  'type' => 'range',
612
  'min' => 0,
613
  'max' => 20,
@@ -620,7 +629,7 @@ class HappyForms_Form_Styles {
620
  'sanitize' => 'intval'
621
  ),
622
  'hf_style_submit_button_border_radius_hover' => array(
623
- 'default' => 0,
624
  'type' => 'range',
625
  'min' => 0,
626
  'max' => 20,
@@ -640,7 +649,7 @@ class HappyForms_Form_Styles {
640
  ),
641
  'hf_confirmation_message_title' => array(
642
  'type' => 'divider',
643
- 'html' => '<h2 class="group-title">' . __( 'Confirmation message', 'happyforms' ) . '</h2>'
644
  ),
645
  'hf_style_confirmation_message_font_size' => array(
646
  'default' => 16,
@@ -721,12 +730,14 @@ class HappyForms_Form_Styles {
721
  }
722
 
723
  /**
724
- * Add fields to form meta.
725
  *
726
  * @hooked filter happyforms_fields
727
  *
728
  * @since 1.0.0.
729
  *
 
 
730
  * @return array
731
  */
732
  public function add_fields( $fields ) {
@@ -767,10 +778,12 @@ class HappyForms_Form_Styles {
767
  /**
768
  * Parse styles from meta.
769
  *
770
- * @param array $form Form data.
771
  *
772
  * @since 1.0.0.
773
  *
 
 
774
  * @return array
775
  */
776
  public function parse_styles( $form ) {
@@ -836,10 +849,10 @@ class HappyForms_Form_Styles {
836
  /**
837
  * Print styles.
838
  *
839
- * @param array $form Form data.
840
- *
841
  * @since 1.0.0.
842
  *
 
 
843
  * @return string
844
  */
845
  public function print_css( $form ) {
@@ -869,7 +882,7 @@ class HappyForms_Form_Styles {
869
  }
870
 
871
  /**
872
- * Load styles.
873
  *
874
  * @hooked action wp_ajax_happyforms_load_styles
875
  *
2
 
3
  class HappyForms_Form_Styles {
4
 
5
+ /**
6
+ * The singleton instance.
7
+ *
8
+ * @since 1.0
9
+ *
10
+ * @var HappyForms_Form_Styles
11
+ */
12
  private static $instance;
13
 
14
+ /**
15
+ * The singleton constructor.
16
+ *
17
+ * @since 1.0
18
+ *
19
+ * @return HappyForms_Form_Styles
20
+ */
21
  public static function instance() {
22
  if ( is_null( self::$instance ) ) {
23
  self::$instance = new self();
28
  return self::$instance;
29
  }
30
 
 
 
 
 
31
  /**
32
  * Hook into WordPress.
33
  *
38
  public function hook() {
39
  add_filter( 'happyforms_fields', array( $this, 'add_fields' ) );
40
  add_action( 'happyforms_print_css', array( $this, 'print_css' ), 10, 1 );
 
41
  add_action( 'wp_ajax_happyforms_load_styles', array( $this, 'load_styles') );
42
  }
43
 
44
  /**
45
  * Get styles by key or all styles as array.
46
  *
47
+ * @param string $key Style key.
48
  *
49
  * @since 1.0.0.
50
  *
54
  $fields = array(
55
  'hf_form_title' => array(
56
  'type' => 'divider',
57
+ 'label' => __( 'General form styles', 'happyforms' )
58
  ),
59
  'hf_style_display_form_name' => array(
60
  'default' => 1,
71
  'sanitize' => 'happyforms_sanitize_checkbox'
72
  ),
73
  'hf_style_form_font_size' => array(
74
+ 'default' => 14,
75
  'type' => 'range',
76
  'min' => 8,
77
  'max' => 30,
159
  ),
160
  'hf_form_parts_title' => array(
161
  'type' => 'divider',
162
+ 'label' => __( 'Form parts', 'happyforms' ),
163
  ),
164
  'hf_style_hide_part_titles' => array(
165
  'default' => 0,
168
  'selector' => array( '.happyforms-part__label' ),
169
  'attribute' => array( 'display' ),
170
  'value' => array(
171
+ 0 => 'inline-block',
172
  1 => 'none'
173
  )
174
  ),
176
  'sanitize' => 'happyforms_sanitize_checkbox'
177
  ),
178
  'hf_style_part_label_font_weight' => array(
179
+ 'default' => 'bold',
180
  'type' => 'buttonset',
181
  'options' => array(
182
  'normal' => 'Normal',
204
  'sanitize' => 'sanitize_text_field'
205
  ),
206
  'hf_style_part_description_font_size' => array(
207
+ 'default' => '16',
208
  'type' => 'range',
209
  'min' => 8,
210
  'max' => 30,
245
  'sanitize' => 'sanitize_text_field'
246
  ),
247
  'hf_style_part_border' => array(
248
+ 'default' => 1,
249
  'type' => 'range',
250
  'min' => 0,
251
  'max' => 10,
252
  'css' => array(
253
+ 'selector' => array( '.happyforms-part input[type=text], .happyforms-part input[type=email], .happyforms-part input[type=tel], .happyforms-part input[type=number], .happyforms-part input[type=range], .happyforms -part textarea, .happyforms-part select, .happyforms-part__el--address--results > div, .happyforms-part__el--address--results:after' ),
254
  'attribute' => array( 'border-width' ),
255
  'tpl' => '{{ value }}px'
256
  ),
258
  'sanitize' => 'sanitize_text_field'
259
  ),
260
  'hf_style_part_border_color' => array(
261
+ 'default' => '#dbdbdb',
262
  'type' => 'color',
263
  'css' => array(
264
+ 'selector' => array( '.happyforms-part input[type=text], .happyforms-part input[type=email], .happyforms-part input[type=tel], .happyforms-part input[type=number], .happyforms-part input[type=range], .happyforms -part textarea, .happyforms-part select, .happyforms-part__el--address--results > div, .happyforms-part__el--address--results:after' ),
265
  'attribute' => array( 'border-color' )
266
  ),
267
  'label' => __( 'Border color', 'happyforms' ),
268
  'sanitize' => 'sanitize_text_field'
269
  ),
270
  'hf_style_part_border_color_focus' => array(
271
+ 'default' => '#555555',
272
  'type' => 'color',
273
  'css' => array(
274
+ 'selector' => array( '.happyforms-part input[type=text]:focus, .happyforms-part input[type=email]:focus, .happyforms-part input[type=tel]:focus, .happyforms-part input[type=number]:focus, .happyforms-part input[type=range]:focus, .happyforms -part textarea:focus, .happyforms-part select:focus' ),
275
  'attribute' => array( 'border-color' )
276
  ),
277
  'label' => __( 'Border color focused', 'happyforms' ),
278
  'sanitize' => 'sanitize_text_field'
279
  ),
280
  'hf_style_part_border_radius' => array(
281
+ 'default' => 6,
282
  'type' => 'range',
283
  'min' => 0,
284
  'max' => 20,
285
  'css' => array(
286
+ 'selector' => array( '.happyforms-part input[type=text], .happyforms-part input[type=email], .happyforms-part input[type=tel], .happyforms-part input[type=number], .happyforms-part input[type=range], .happyforms -part textarea, .happyforms-part select, .happyforms-part__el--address--results > div, .happyforms-part__el--address--results:after' ),
287
  'attribute' => array( 'border-radius' ),
288
  'tpl' => '{{ value }}px'
289
  ),
294
  'default' => '#ffffff',
295
  'type' => 'color',
296
  'css' => array(
297
+ 'selector' => array( '.happyforms-part input, .happyforms-part textarea, .happyforms-part__el--address--results > div, .happyforms-part__el--address--results:after' ),
298
  'attribute' => array( 'background-color' )
299
  ),
300
  'label' => __( 'Background color', 'happyforms' ),
304
  'default' => '#ffffff',
305
  'type' => 'color',
306
  'css' => array(
307
+ 'selector' => array( '.happyforms-part input:focus, .happyforms-part textarea:focus, .happyforms-part__el--address--results > div:hover' ),
308
  'attribute' => array( 'background-color' )
309
  ),
310
  'label' => __( 'Background color focused', 'happyforms' ),
318
  'background-color' => 'Fade'
319
  ),
320
  'css' => array(
321
+ 'selector' => array( '.happyforms-part input, .happyforms-part textarea, .happyforms-part__el--address--results > div' ),
322
  'attribute' => array( 'transition-property' )
323
  ),
324
  'label' => __( 'Smooth background change (transition)', 'happyforms' ),
406
  'sanitize' => 'sanitize_text_field'
407
  ),
408
  'hf_style_required_color' => array(
409
+ 'default' => '#ff7550',
410
  'type' => 'color',
411
  'css' => array(
412
  'selector' => array( '.happyforms-required' ),
437
  ),
438
  'hf_ratings_part_title' => array(
439
  'type' => 'divider',
440
+ 'label' => __( 'Ratings', 'happyforms' )
441
  ),
442
  'hf_style_ratings_star_color' => array(
443
  'default' => '#ccc',
466
  ),
467
  'hf_submit_button_title' => array(
468
  'type' => 'divider',
469
+ 'label' => __( 'Submit button', 'happyforms' )
470
  ),
471
  'hf_style_submit_button_alignment' => array(
472
  'default' => 'left',
526
  'sanitize' => 'sanitize_text_field'
527
  ),
528
  'hf_style_submit_button_font_size' => array(
529
+ 'default' => '16',
530
  'type' => 'range',
531
  'min' => 8,
532
  'max' => 40,
559
  'sanitize' => 'sanitize_text_field'
560
  ),
561
  'hf_style_submit_button_bg_hover' => array(
562
+ 'default' => '#555555',
563
  'type' => 'color',
564
  'css' => array(
565
  'selector' => array( '.happyforms-button--submit:hover' ),
606
  'sanitize' => 'sanitize_text_field'
607
  ),
608
  'hf_style_submit_button_border_color_hover' => array(
609
+ 'default' => '#555555',
610
  'type' => 'color',
611
  'css' => array(
612
  'selector' => array( '.happyforms-button--submit:hover' ),
616
  'sanitize' => 'sanitize_text_field'
617
  ),
618
  'hf_style_submit_button_border_radius' => array(
619
+ 'default' => 6,
620
  'type' => 'range',
621
  'min' => 0,
622
  'max' => 20,
629
  'sanitize' => 'intval'
630
  ),
631
  'hf_style_submit_button_border_radius_hover' => array(
632
+ 'default' => 6,
633
  'type' => 'range',
634
  'min' => 0,
635
  'max' => 20,
649
  ),
650
  'hf_confirmation_message_title' => array(
651
  'type' => 'divider',
652
+ 'label' => __( 'Confirmation message', 'happyforms' )
653
  ),
654
  'hf_style_confirmation_message_font_size' => array(
655
  'default' => 16,
730
  }
731
 
732
  /**
733
+ * Filter: add fields to form meta.
734
  *
735
  * @hooked filter happyforms_fields
736
  *
737
  * @since 1.0.0.
738
  *
739
+ * @param array $fields Current form style fields.
740
+ *
741
  * @return array
742
  */
743
  public function add_fields( $fields ) {
778
  /**
779
  * Parse styles from meta.
780
  *
781
+ * @param array $form Form data.
782
  *
783
  * @since 1.0.0.
784
  *
785
+ * @param array $form Current form data.
786
+ *
787
  * @return array
788
  */
789
  public function parse_styles( $form ) {
849
  /**
850
  * Print styles.
851
  *
 
 
852
  * @since 1.0.0.
853
  *
854
+ * @param array $form Current form data.
855
+ *
856
  * @return string
857
  */
858
  public function print_css( $form ) {
882
  }
883
 
884
  /**
885
+ * Action: load styles.
886
  *
887
  * @hooked action wp_ajax_happyforms_load_styles
888
  *
inc/classes/class-happyforms-plugin.php CHANGED
@@ -52,10 +52,7 @@ class HappyForms_Plugin {
52
  require_once( happyforms_get_include_folder() . '/classes/class-message-notices.php' );
53
  require_once( happyforms_get_include_folder() . '/helpers/helper-misc.php' );
54
  require_once( happyforms_get_include_folder() . '/classes/class-happyforms-widget.php' );
55
-
56
- if ( ! is_admin() ) {
57
- require_once( happyforms_get_include_folder() . '/helpers/helper-form-templates.php' );
58
- }
59
 
60
  // Admin hooks
61
  add_action( 'admin_menu', array( $this, 'admin_menu' ) );
@@ -64,6 +61,7 @@ class HappyForms_Plugin {
64
  add_action( 'current_screen', array( $this, 'admin_screens' ) );
65
  add_filter( 'mce_external_plugins', array( $this, 'tinymce_register_plugins' ) );
66
  add_filter( 'mce_buttons', array( $this, 'tinymce_register_button' ) );
 
67
 
68
  // Widget
69
  add_action( 'widgets_init', array( $this, 'register_widget' ) );
@@ -124,7 +122,7 @@ class HappyForms_Plugin {
124
  'manage_options',
125
  'happyforms',
126
  array( $this, 'happyforms_page_index' ),
127
- happyforms_smiley( true ),
128
  50
129
  );
130
 
@@ -144,10 +142,11 @@ class HappyForms_Plugin {
144
  happyforms_get_form_edit_link( 0 )
145
  );
146
 
 
147
  add_submenu_page(
148
  'happyforms',
149
  __( 'Messages', 'happyforms' ),
150
- __( 'Messages', 'happyforms' ),
151
  'manage_options',
152
  '/edit.php?post_type=happyforms-message'
153
  );
@@ -186,7 +185,7 @@ class HappyForms_Plugin {
186
  );
187
 
188
  wp_enqueue_script(
189
- 'happyforms-script',
190
  happyforms_get_plugin_url() . 'assets/js/happyforms.js',
191
  '',
192
  '',
@@ -196,7 +195,7 @@ class HappyForms_Plugin {
196
  $form_data = $this->get_form_data_array();
197
 
198
  wp_localize_script(
199
- 'happyforms-script',
200
  'happyFormsData',
201
  $form_data
202
  );
@@ -261,52 +260,14 @@ class HappyForms_Plugin {
261
  * @return void
262
  */
263
  public function admin_bar_menu( $wp_admin_bar ) {
264
- $smiley = sprintf(
265
- '<span class="ab-icon">%s</span>',
266
- happyforms_smiley()
267
- );
268
-
269
- $wp_admin_bar->add_node( array(
270
- 'id' => 'happyforms',
271
- 'title' => $smiley . __( 'HappyForms', 'happyforms' ),
272
- 'href' => admin_url( '/customize.php?happyforms=1' ),
273
- 'meta' => array(
274
- 'target' => '_self',
275
- 'title' => __( 'HappyForms', 'happyforms' ),
276
- 'class' => 'happyforms-admin-bar-link',
277
- ),
278
- ) );
279
-
280
- $wp_admin_bar->add_node( array(
281
- 'id' => 'happyforms-forms',
282
- 'parent' => 'happyforms',
283
- 'title' => __( 'All Forms', 'happyforms' ),
284
- 'href' => admin_url( '/edit.php?post_type=happyform' ),
285
- 'meta' => array(
286
- 'target' => '_self',
287
- 'title' => __( 'All Forms', 'happyforms' )
288
- ),
289
- ) );
290
-
291
  $wp_admin_bar->add_node( array(
292
- 'id' => 'happyforms-form-new',
293
- 'parent' => 'happyforms',
294
- 'title' => __( 'Add New', 'happyforms' ),
295
  'href' => happyforms_get_form_edit_link( 0 ),
296
  'meta' => array(
297
  'target' => '_self',
298
- 'title' => __( 'Build Form', 'happyforms' ),
299
- ),
300
- ) );
301
-
302
- $wp_admin_bar->add_node( array(
303
- 'id' => 'happyforms-messages',
304
- 'parent' => 'happyforms',
305
- 'title' => __( 'Messages', 'happyforms' ),
306
- 'href' => admin_url( '/edit.php?post_type=happyforms-message' ),
307
- 'meta' => array(
308
- 'target' => '_self',
309
- 'title' => __( 'Messages', 'happyforms' ),
310
  ),
311
  ) );
312
  }
@@ -424,12 +385,46 @@ class HappyForms_Plugin {
424
  $attrs = shortcode_parse_atts( $shortcode );
425
  $form_id = $attrs['id'];
426
  $form = $form_controller->get( $form_id );
427
- $form_controller->header_scripts( $form );
 
 
 
 
 
 
 
 
 
 
428
  }
429
  }
430
  }
431
  }
432
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
433
  /**
434
  * Action: enqueue scripts and styles
435
  * for the frontend part of the plugin.
52
  require_once( happyforms_get_include_folder() . '/classes/class-message-notices.php' );
53
  require_once( happyforms_get_include_folder() . '/helpers/helper-misc.php' );
54
  require_once( happyforms_get_include_folder() . '/classes/class-happyforms-widget.php' );
55
+ require_once( happyforms_get_include_folder() . '/helpers/helper-form-templates.php' );
 
 
 
56
 
57
  // Admin hooks
58
  add_action( 'admin_menu', array( $this, 'admin_menu' ) );
61
  add_action( 'current_screen', array( $this, 'admin_screens' ) );
62
  add_filter( 'mce_external_plugins', array( $this, 'tinymce_register_plugins' ) );
63
  add_filter( 'mce_buttons', array( $this, 'tinymce_register_button' ) );
64
+ add_filter( 'media_buttons_context', array( $this, 'insert_editor_buttons' ) );
65
 
66
  // Widget
67
  add_action( 'widgets_init', array( $this, 'register_widget' ) );
122
  'manage_options',
123
  'happyforms',
124
  array( $this, 'happyforms_page_index' ),
125
+ 'dashicons-format-status',
126
  50
127
  );
128
 
142
  happyforms_get_form_edit_link( 0 )
143
  );
144
 
145
+
146
  add_submenu_page(
147
  'happyforms',
148
  __( 'Messages', 'happyforms' ),
149
+ __( 'Messages', 'happyforms' ) . happyforms_unread_messages_badge(),
150
  'manage_options',
151
  '/edit.php?post_type=happyforms-message'
152
  );
185
  );
186
 
187
  wp_enqueue_script(
188
+ 'happyforms-admin',
189
  happyforms_get_plugin_url() . 'assets/js/happyforms.js',
190
  '',
191
  '',
195
  $form_data = $this->get_form_data_array();
196
 
197
  wp_localize_script(
198
+ 'happyforms-admin',
199
  'happyFormsData',
200
  $form_data
201
  );
260
  * @return void
261
  */
262
  public function admin_bar_menu( $wp_admin_bar ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
263
  $wp_admin_bar->add_node( array(
264
+ 'id' => 'new-content-happyforms',
265
+ 'parent' => 'new-content',
266
+ 'title' => __( 'HappyForm', 'happyforms' ),
267
  'href' => happyforms_get_form_edit_link( 0 ),
268
  'meta' => array(
269
  'target' => '_self',
270
+ 'title' => __( 'New HappyForm', 'happyforms' ),
 
 
 
 
 
 
 
 
 
 
 
271
  ),
272
  ) );
273
  }
385
  $attrs = shortcode_parse_atts( $shortcode );
386
  $form_id = $attrs['id'];
387
  $form = $form_controller->get( $form_id );
388
+
389
+ /**
390
+ * Enqueue form-specific scripts.
391
+ *
392
+ * @since 1.1
393
+ *
394
+ * @param array $form Current form data.
395
+ *
396
+ * @return void
397
+ */
398
+ do_action( 'happyforms_frontend_form_scripts', $form );
399
  }
400
  }
401
  }
402
  }
403
 
404
+ /**
405
+ * Filter: Add HappyForms button markup to a markup above content editor, next to
406
+ * Add Media button.
407
+ *
408
+ * @since 1.1.0.
409
+ *
410
+ * @hooked filter media_buttons_context
411
+ *
412
+ * @param string $context HTML markup.
413
+ *
414
+ * @return void
415
+ */
416
+ public function insert_editor_buttons( $context ) {
417
+ global $pagenow;
418
+
419
+ if ( 'post.php' !== $pagenow && 'post-new.php' !== $pagenow ) {
420
+ return $context;
421
+ }
422
+
423
+ $button_html = '<a href="#" class="button happyforms-editor-button" onclick="tinyMCE.activeEditor.editorCommands.execCommand(\'HappyForms_Form_Picker\');"><span class="dashicons dashicons-format-status"></span><span>'. __( 'Add HappyForms', 'happyforms' ) .'</span></a>';
424
+
425
+ return $context . ' ' . $button_html;
426
+ }
427
+
428
  /**
429
  * Action: enqueue scripts and styles
430
  * for the frontend part of the plugin.
inc/classes/class-message-admin.php CHANGED
@@ -76,7 +76,8 @@ class HappyForms_Message_Admin {
76
  $post_type = happyforms_get_message_controller()->post_type;
77
 
78
  add_action( 'parse_request', array( $this, 'parse_request' ) );
79
- add_action( 'admin_head', array( $this, 'admin_head' ) );
 
80
  add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
81
  add_filter( 'bulk_post_updated_messages', array( $this, 'bulk_post_updated_messages' ), 10, 2 );
82
  add_action( 'load-edit.php', array( $this, 'define_screen_settings' ) );
@@ -92,6 +93,8 @@ class HappyForms_Message_Admin {
92
  add_filter( "handle_bulk_actions-edit-{$post_type}", array( $this, 'handle_bulk_actions' ), 10, 3 );
93
  add_filter( 'post_row_actions', array( $this, 'row_actions' ), 10, 2 );
94
  add_action( 'edit_form_after_title', array( $this, 'edit_screen' ) );
 
 
95
  add_filter( 'admin_footer_text', 'happyforms_admin_footer' );
96
  }
97
 
@@ -125,19 +128,39 @@ class HappyForms_Message_Admin {
125
  *
126
  * @return void
127
  */
128
- public function admin_head() {
129
  global $pagenow;
130
  $post_type = happyforms_get_message_controller()->post_type;
131
 
132
- if ( 'edit.php' === $pagenow && $post_type === get_post_type() ) : ?>
133
  <style>
134
- fieldset:not(.screen-options) {
 
135
  display: none;
136
  }
137
  </style>
138
  <?php endif;
139
  }
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  /**
142
  * Filter: tweak the text of the message post actions admin notices.
143
  *
@@ -281,7 +304,11 @@ class HappyForms_Message_Admin {
281
  $forms = happyforms_get_form_controller()->get();
282
  $part_lists = wp_list_pluck( $forms, 'parts' );
283
  $part_counts = array_map( 'count', $part_lists );
284
- $max_column_count = min( max( $part_counts ), $this->column_count );
 
 
 
 
285
 
286
  for ( $column = 0; $column < $max_column_count; $column ++ ) {
287
  $header = "column_{$column}";
@@ -334,10 +361,6 @@ class HappyForms_Message_Admin {
334
  }
335
  break;
336
 
337
- case 'date_only':
338
- echo get_the_date( 'Y/m/d', $id );
339
- break;
340
-
341
  default:
342
  if ( $form ) {
343
  $column_index = preg_match( '/column_(\d+)?/', $column, $matches );
@@ -461,16 +484,27 @@ class HappyForms_Message_Admin {
461
  * @return void
462
  */
463
  public function parse_query( $query ) {
 
 
 
 
 
 
464
  $query_vars = &$query->query_vars;
465
  $query_vars['meta_query'] = array();
466
  $post_type = happyforms_get_message_controller()->post_type;
467
 
468
  if ( $post_type === $query->query['post_type'] ) {
469
- $query_vars['meta_query'][] = array(
470
- 'key' => 'form_id',
471
- 'value' => $this->current_form_ids,
472
- 'compare' => 'IN',
473
- );
 
 
 
 
 
474
  }
475
  }
476
 
@@ -518,13 +552,15 @@ class HappyForms_Message_Admin {
518
  switch( $action ) {
519
  case 'mark_read':
520
  foreach ( $ids as $id ) {
521
- update_post_meta( $id, 'read', true );
522
  }
 
523
  break;
524
  case 'mark_unread':
525
  foreach ( $ids as $id ) {
526
- update_post_meta( $id, 'read', false );
527
  }
 
528
  break;
529
  case 'delete':
530
  foreach ( $ids as $id ) {
@@ -625,6 +661,62 @@ class HappyForms_Message_Admin {
625
  exit();
626
  }
627
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
628
  /**
629
  * Action: output custom markup for the
630
  * Message Edit admin screen.
@@ -638,27 +730,73 @@ class HappyForms_Message_Admin {
638
  * @return void
639
  */
640
  public function edit_screen( $post ) {
 
 
641
  $message = happyforms_get_message_controller()->get( $post->ID );
642
  $form = happyforms_get_form_controller()->get( $message['form_id'] );
 
643
 
644
- if ( ! $form ) {
645
- return;
646
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
647
 
648
- foreach ( $form['parts'] as $part_data ):
649
- $part = happyforms_get_part_library()->get_part( $part_data['type'] );
650
- $part_id = $part_data['id'];
651
- $label = happyforms_get_part_label( $part_data );
652
- $value = happyforms_get_message_part_value( $message['parts'][$part_id] );
653
  ?>
654
- <p>
655
- <label for="">
656
- <strong><?php echo esc_html( $label ); ?></strong>
657
- </label><br>
658
- <span><?php echo esc_html( $value ); ?></span>
659
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
660
  <?php
661
- endforeach;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
662
  }
663
 
664
  }
76
  $post_type = happyforms_get_message_controller()->post_type;
77
 
78
  add_action( 'parse_request', array( $this, 'parse_request' ) );
79
+ add_action( 'admin_head', array( $this, 'output_styles' ) );
80
+ add_action( 'admin_head', array( $this, 'screen_title' ) );
81
  add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
82
  add_filter( 'bulk_post_updated_messages', array( $this, 'bulk_post_updated_messages' ), 10, 2 );
83
  add_action( 'load-edit.php', array( $this, 'define_screen_settings' ) );
93
  add_filter( "handle_bulk_actions-edit-{$post_type}", array( $this, 'handle_bulk_actions' ), 10, 3 );
94
  add_filter( 'post_row_actions', array( $this, 'row_actions' ), 10, 2 );
95
  add_action( 'edit_form_after_title', array( $this, 'edit_screen' ) );
96
+ add_action( 'add_meta_boxes', array( $this, 'setup_metaboxes' ) );
97
+ add_action( 'save_post', array( $this, 'save_post' ) );
98
  add_filter( 'admin_footer_text', 'happyforms_admin_footer' );
99
  }
100
 
128
  *
129
  * @return void
130
  */
131
+ public function output_styles() {
132
  global $pagenow;
133
  $post_type = happyforms_get_message_controller()->post_type;
134
 
135
+ if ( 'edit.php' === $pagenow ) : ?>
136
  <style>
137
+ fieldset:not(.screen-options),
138
+ ul.subsubsub {
139
  display: none;
140
  }
141
  </style>
142
  <?php endif;
143
  }
144
 
145
+ /**
146
+ * Action: customize the edit screen title.
147
+ *
148
+ * @since 1.0
149
+ *
150
+ * @hooked action admin_head
151
+ *
152
+ * @return void
153
+ */
154
+ public function screen_title() {
155
+ global $pagenow, $post, $title;
156
+
157
+ $post_type = happyforms_get_message_controller()->post_type;
158
+
159
+ if ( 'post.php' === $pagenow && $post_type === get_post_type() ) {
160
+ $title = __( 'View message #') . $post->ID;
161
+ }
162
+ }
163
+
164
  /**
165
  * Filter: tweak the text of the message post actions admin notices.
166
  *
304
  $forms = happyforms_get_form_controller()->get();
305
  $part_lists = wp_list_pluck( $forms, 'parts' );
306
  $part_counts = array_map( 'count', $part_lists );
307
+ $max_column_count = $this->column_count;
308
+
309
+ if ( count( $forms ) > 0 ) {
310
+ $max_column_count = min( max( $part_counts ), $this->column_count );
311
+ }
312
 
313
  for ( $column = 0; $column < $max_column_count; $column ++ ) {
314
  $header = "column_{$column}";
361
  }
362
  break;
363
 
 
 
 
 
364
  default:
365
  if ( $form ) {
366
  $column_index = preg_match( '/column_(\d+)?/', $column, $matches );
484
  * @return void
485
  */
486
  public function parse_query( $query ) {
487
+ global $pagenow;
488
+
489
+ if ( 'edit.php' !== $pagenow ) {
490
+ return;
491
+ }
492
+
493
  $query_vars = &$query->query_vars;
494
  $query_vars['meta_query'] = array();
495
  $post_type = happyforms_get_message_controller()->post_type;
496
 
497
  if ( $post_type === $query->query['post_type'] ) {
498
+ $query_vars['meta_key'] = 'form_id';
499
+
500
+ if ( count( $this->current_form_ids ) > 0 ) {
501
+ $query_vars['meta_value'] = $this->current_form_ids;
502
+ $query_vars['meta_compare'] = 'IN';
503
+ $query_vars['meta_type'] = 'NUMERIC';
504
+ } else {
505
+ $query_vars['meta_value'] = 0;
506
+ $query_vars['meta_compare'] = '=';
507
+ }
508
  }
509
  }
510
 
552
  switch( $action ) {
553
  case 'mark_read':
554
  foreach ( $ids as $id ) {
555
+ update_post_meta( $id, 'read', 1 );
556
  }
557
+ happyforms_get_message_controller()->update_badge_transient();
558
  break;
559
  case 'mark_unread':
560
  foreach ( $ids as $id ) {
561
+ update_post_meta( $id, 'read', '' );
562
  }
563
+ happyforms_get_message_controller()->update_badge_transient();
564
  break;
565
  case 'delete':
566
  foreach ( $ids as $id ) {
661
  exit();
662
  }
663
 
664
+ private function setup_message_navigation( $post_id, $form_id ) {
665
+ $post_type = happyforms_get_message_controller()->post_type;
666
+
667
+ global $happyforms_message_nav;
668
+
669
+ $posts = get_posts( array(
670
+ 'post_type' => $post_type,
671
+ 'post_status' => 'any',
672
+ 'posts_per_page' => -1,
673
+ 'orderby' => 'ID',
674
+ 'order' => 'ASC',
675
+ 'fields' => 'ids',
676
+ 'meta_query' => array(
677
+ 'relation' => 'AND',
678
+ array(
679
+ 'key' => 'form_id',
680
+ 'value' => $form_id,
681
+ ),
682
+ array(
683
+ 'key' => 'read',
684
+ 'value' => '',
685
+ ),
686
+ )
687
+ ) );
688
+
689
+ $previous_id = -1;
690
+ $next_id = -1;
691
+
692
+ // Find previous post ID
693
+ for ( $p = 0; $p < count( $posts ); $p ++ ) {
694
+ if ( $posts[$p] >= $post_id ) {
695
+ break;
696
+ }
697
+
698
+ $previous_id = $posts[$p];
699
+ }
700
+
701
+ // Find next post ID
702
+ for ( $p = 0; $p < count( $posts ); $p ++ ) {
703
+ if ( $posts[$p] > $post_id ) {
704
+ $next_id = $posts[$p];
705
+ break;
706
+ }
707
+ }
708
+
709
+ $happyforms_message_nav = array( $post_id );
710
+
711
+ if ( $previous_id ) {
712
+ array_unshift( $happyforms_message_nav, $previous_id );
713
+ }
714
+
715
+ if ( $next_id ) {
716
+ array_push( $happyforms_message_nav, $next_id );
717
+ }
718
+ }
719
+
720
  /**
721
  * Action: output custom markup for the
722
  * Message Edit admin screen.
730
  * @return void
731
  */
732
  public function edit_screen( $post ) {
733
+ global $message, $form;
734
+
735
  $message = happyforms_get_message_controller()->get( $post->ID );
736
  $form = happyforms_get_form_controller()->get( $message['form_id'] );
737
+ $this->setup_message_navigation( $post->ID, $form['ID'] );
738
 
739
+ require_once( happyforms_get_include_folder() . '/templates/admin-message-edit.php' );
740
+ }
741
+
742
+ public function setup_metaboxes( $post_type ) {
743
+ global $wp_meta_boxes;
744
+
745
+ // Clear standard metaboxes
746
+ $wp_meta_boxes[$post_type] = array();
747
+
748
+ add_meta_box(
749
+ 'happyforms-message-details',
750
+ __( 'Details' ),
751
+ array( $this, 'metabox_message_details' ),
752
+ $post_type,
753
+ 'side',
754
+ 'high'
755
+ );
756
+ }
757
 
758
+ public function metabox_message_details( $post, $metabox ) {
759
+ global $message, $form;
760
+
761
+ $message_status = get_post_meta( $post->ID, 'read', true );
 
762
  ?>
763
+ <div class="misc-pub-section happyforms-message-form">
764
+ <span>
765
+ <i class="logo dashicons dashicons-format-status"></i> <?php _e( 'Form', 'happyforms' ); ?>: <a href="<?php echo happyforms_get_form_edit_link( $form['ID'] ); ?>"><?php echo esc_html( $form['post_title'] ); ?></a>
766
+ </span>
767
+ </div>
768
+ <div class="misc-pub-section curtime misc-pub-curtime">
769
+ <span id="timestamp">
770
+ <?php _e( 'Submitted on', 'happyforms' ); ?>: <b><?php echo date_i18n( __( 'M j, Y @ H:i' ), strtotime( $post->post_date ) ); ?></b>
771
+ </span>
772
+ </div>
773
+ <div class="misc-pub-section misc-pub-visibility" id="visibility">
774
+ <input type="hidden" name="message-status" value="<?php echo ( $message_status ) ? 1 : 0; ?>">
775
+ <?php _e( 'Status', 'happyforms' ); ?>: <strong><?php echo ( $message_status ) ? __( 'Read', 'happyforms' ) : __( 'Unread', 'happyforms' ); ?></strong> <a href="#" id="happyforms-message-status-toggle"><?php echo ( $message_status ) ? __( 'Mark unread', 'happyforms' ) : __( 'Mark read', 'happyforms' ); ?></a>
776
+ </div>
777
+
778
+ <div class="misc-pub-section misc-pub-trash">
779
+ <span id="trash">
780
+ <a href="<?php echo get_delete_post_link( $post->ID, '', true ); ?>"><?php _e( 'Trash', 'happyforms' ); ?></a>
781
+ </span>
782
+ </div>
783
  <?php
784
+ }
785
+
786
+ public function save_post( $post_id ) {
787
+ if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
788
+ return;
789
+ }
790
+
791
+ if ( ! current_user_can( 'edit_post', $post_id ) ) {
792
+ return;
793
+ }
794
+
795
+ if ( isset( $_POST['message-status'] ) ) {
796
+ $value = intval( $_POST['message-status'] );
797
+ update_post_meta( $post_id, 'read', 1 === $value && 1 || '' );
798
+ happyforms_get_message_controller()->update_badge_transient();
799
+ }
800
  }
801
 
802
  }
inc/classes/class-message-controller.php CHANGED
@@ -58,6 +58,16 @@ class HappyForms_Message_Controller {
58
  */
59
  public $nonce_name = 'happyforms_message_nonce';
60
 
 
 
 
 
 
 
 
 
 
 
61
  /**
62
  * The singleton constructor.
63
  *
@@ -85,6 +95,7 @@ class HappyForms_Message_Controller {
85
  public function hook() {
86
  add_action( 'init', array( $this, 'register_post_type' ) );
87
  add_action( 'parse_request', array( $this, 'admin_post' ) );
 
88
  }
89
 
90
  /**
@@ -215,6 +226,9 @@ class HappyForms_Message_Controller {
215
  // Add a general success notice at the top
216
  $message_notices->add_message( 'form_success', $form_id );
217
 
 
 
 
218
  if ( ! empty( $form['redirect_url'] ) ) {
219
  $redirect_url = $form['redirect_url'];
220
  }
@@ -226,6 +240,27 @@ class HappyForms_Message_Controller {
226
  exit;
227
  }
228
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  /**
230
  * Verify a message nonce.
231
  *
@@ -515,6 +550,39 @@ class HappyForms_Message_Controller {
515
  return 'text/html';
516
  }
517
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  }
519
 
520
  if ( ! function_exists( 'happyforms_get_message_controller' ) ):
58
  */
59
  public $nonce_name = 'happyforms_message_nonce';
60
 
61
+ /**
62
+ * The transient key used to store
63
+ * the counter of unread messages.
64
+ *
65
+ * @since 1.1
66
+ *
67
+ * @var string
68
+ */
69
+ public $unread_transient = 'happyforms_unread_messages';
70
+
71
  /**
72
  * The singleton constructor.
73
  *
95
  public function hook() {
96
  add_action( 'init', array( $this, 'register_post_type' ) );
97
  add_action( 'parse_request', array( $this, 'admin_post' ) );
98
+ add_action( 'delete_post', array( $this, 'delete_post' ) );
99
  }
100
 
101
  /**
226
  // Add a general success notice at the top
227
  $message_notices->add_message( 'form_success', $form_id );
228
 
229
+ // Update the unread badge
230
+ $this->update_badge_transient();
231
+
232
  if ( ! empty( $form['redirect_url'] ) ) {
233
  $redirect_url = $form['redirect_url'];
234
  }
240
  exit;
241
  }
242
 
243
+ /**
244
+ * Action: update the unread badge upon message deletion.
245
+ *
246
+ * @since 1.1
247
+ *
248
+ * @hooked action delete_post
249
+ *
250
+ * @param int|string $post_id The ID of the message object.
251
+ *
252
+ * @return void
253
+ */
254
+ public function delete_post( $post_id ) {
255
+ $post = get_post( $post_id );
256
+
257
+ if ( $this->post_type !== $post->post_type ) {
258
+ return;
259
+ }
260
+
261
+ $this->update_badge_transient();
262
+ }
263
+
264
  /**
265
  * Verify a message nonce.
266
  *
550
  return 'text/html';
551
  }
552
 
553
+ /**
554
+ * Update the counter in unread messages badge.
555
+ *
556
+ * @since 1.1
557
+ *
558
+ * @return void
559
+ */
560
+ public function update_badge_transient() {
561
+ $forms = happyforms_get_form_controller()->get( array(), true );
562
+
563
+ $messages = get_posts( array(
564
+ 'post_type' => $this->post_type,
565
+ 'post_status' => 'any',
566
+ 'posts_per_page' => -1,
567
+ 'fields' => 'ids',
568
+ 'meta_query' => array( array(
569
+ 'key' => 'read',
570
+ 'value' => 1,
571
+ 'compare' => '!=',
572
+ ), array(
573
+ 'key' => 'form_id',
574
+ 'value' => $forms,
575
+ 'compare' => 'IN',
576
+ ) )
577
+ ) );
578
+
579
+ if ( count( $messages ) > 0 && count( $forms ) > 0 ) {
580
+ set_transient( $this->unread_transient, count( $messages ), 0 );
581
+ } else {
582
+ delete_transient( $this->unread_transient );
583
+ }
584
+ }
585
+
586
  }
587
 
588
  if ( ! function_exists( 'happyforms_get_message_controller' ) ):
inc/classes/class-message-notices.php CHANGED
@@ -93,7 +93,7 @@ class HappyForms_Message_Notices {
93
  * @return void
94
  */
95
  public function write() {
96
- $session_data = serialize( $this->session );
97
  setcookie( $this->cookie_name, $session_data, 0, '/' );
98
  }
99
 
@@ -109,7 +109,7 @@ class HappyForms_Message_Notices {
109
  $this->messages = array();
110
 
111
  if ( isset( $_COOKIE[ $this->cookie_name ] ) && ! empty( $_COOKIE[ $this->cookie_name ] ) ) {
112
- $this->messages = unserialize( stripslashes( $_COOKIE[ $this->cookie_name ] ) );
113
  unset( $_COOKIE[ $this->cookie_name ] );
114
  setcookie( $this->cookie_name, '', time() - 3600, '/' );
115
  }
93
  * @return void
94
  */
95
  public function write() {
96
+ $session_data = json_encode( $this->session );
97
  setcookie( $this->cookie_name, $session_data, 0, '/' );
98
  }
99
 
109
  $this->messages = array();
110
 
111
  if ( isset( $_COOKIE[ $this->cookie_name ] ) && ! empty( $_COOKIE[ $this->cookie_name ] ) ) {
112
+ $this->messages = json_decode( stripslashes( $_COOKIE[ $this->cookie_name ] ), true );
113
  unset( $_COOKIE[ $this->cookie_name ] );
114
  setcookie( $this->cookie_name, '', time() - 3600, '/' );
115
  }
inc/classes/class-tracking.php CHANGED
@@ -168,7 +168,7 @@ class HappyForms_Tracking {
168
  wp_die( __( 'Sorry, you are not allowed to access this page.', 'happyforms' ) );
169
  }
170
 
171
- require_once( happyforms_get_include_folder() . '/admin/page-tracking.php' );
172
  }
173
 
174
  /**
@@ -203,7 +203,7 @@ class HappyForms_Tracking {
203
  if ( 'success' === $template ): ?>
204
  <h2><?php _e( 'Thank you!', 'happyforms' ); ?></h2>
205
  <p class="about-description"><?php _e( 'Now let\'s go enjoy HappyForms.', 'happyforms' ); ?></p>
206
- <p><?php _e( 'You\'ve setup notifications and helped us to improve HappyForms. You\'re ready to get started with your first form.', 'happyforms' ); ?></p>
207
  <a href="<?php echo happyforms_get_form_edit_link( 0, happyforms_get_all_form_link() ); ?>" class="button button-primary button-hero" id="happyforms-tracking-proceed"><?php _e( 'Create your first form', 'happyforms' ); ?></a>
208
  <?php elseif ( 'error' === $template ): ?>
209
  <p class="about-description"><?php _e( 'Aw snap! Something went wrong.', 'happyforms' ); ?></p>
168
  wp_die( __( 'Sorry, you are not allowed to access this page.', 'happyforms' ) );
169
  }
170
 
171
+ require_once( happyforms_get_include_folder() . '/templates/admin-tracking.php' );
172
  }
173
 
174
  /**
203
  if ( 'success' === $template ): ?>
204
  <h2><?php _e( 'Thank you!', 'happyforms' ); ?></h2>
205
  <p class="about-description"><?php _e( 'Now let\'s go enjoy HappyForms.', 'happyforms' ); ?></p>
206
+ <p><?php _e( 'You\'ve set up notifications and helped us to improve HappyForms. You\'re ready to get started with your first form.', 'happyforms' ); ?></p>
207
  <a href="<?php echo happyforms_get_form_edit_link( 0, happyforms_get_all_form_link() ); ?>" class="button button-primary button-hero" id="happyforms-tracking-proceed"><?php _e( 'Create your first form', 'happyforms' ); ?></a>
208
  <?php elseif ( 'error' === $template ): ?>
209
  <p class="about-description"><?php _e( 'Aw snap! Something went wrong.', 'happyforms' ); ?></p>
inc/classes/class-wp-customize-form-manager.php CHANGED
@@ -278,10 +278,15 @@ class HappyForms_WP_Customize_Form_Manager {
278
  true
279
  );
280
 
 
 
 
 
 
281
  wp_register_script(
282
  'happyforms-preview',
283
  happyforms_get_plugin_url() . 'assets/js/preview.js',
284
- array( 'backbone', 'underscore', 'jquery' ),
285
  false,
286
  true
287
  );
@@ -301,7 +306,6 @@ class HappyForms_WP_Customize_Form_Manager {
301
  require( ABSPATH . WPINC . '/class-wp-editor.php' );
302
  }
303
 
304
- _WP_Editors::print_default_editor_scripts();
305
  wp_enqueue_editor();
306
  }
307
 
@@ -326,6 +330,8 @@ class HappyForms_WP_Customize_Form_Manager {
326
  require_once( happyforms_get_include_folder() . '/templates/customize-form-parts-drawer.php' );
327
  require_once( happyforms_get_include_folder() . '/templates/customize-form-style.php' );
328
  require_once( happyforms_get_include_folder() . '/templates/preview-form-part.php' );
 
 
329
  }
330
 
331
  }
278
  true
279
  );
280
 
281
+ $preview_deps = apply_filters(
282
+ 'happyforms_preview_dependencies',
283
+ array( 'backbone', 'underscore', 'jquery' )
284
+ );
285
+
286
  wp_register_script(
287
  'happyforms-preview',
288
  happyforms_get_plugin_url() . 'assets/js/preview.js',
289
+ $preview_deps,
290
  false,
291
  true
292
  );
306
  require( ABSPATH . WPINC . '/class-wp-editor.php' );
307
  }
308
 
 
309
  wp_enqueue_editor();
310
  }
311
 
330
  require_once( happyforms_get_include_folder() . '/templates/customize-form-parts-drawer.php' );
331
  require_once( happyforms_get_include_folder() . '/templates/customize-form-style.php' );
332
  require_once( happyforms_get_include_folder() . '/templates/preview-form-part.php' );
333
+
334
+ _WP_Editors::print_default_editor_scripts();
335
  }
336
 
337
  }
inc/classes/parts/class-part-address.php ADDED
@@ -0,0 +1,384 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class HappyForms_Part_Address extends HappyForms_Form_Part {
4
+
5
+ public $type = 'address';
6
+ public $template_id = 'happyforms-address-template';
7
+
8
+ public function __construct() {
9
+ $this->label = __( 'Address', 'happyforms' );
10
+ $this->description = __( 'For geographical locations. Includes Google Maps intergration.', 'happyforms' );
11
+
12
+ add_filter( 'happyforms_preview_dependencies', array( $this, 'preview_dependencies' ) );
13
+ add_action( 'happyforms_frontend_form_scripts', array( $this, 'frontend_enqueue_scripts' ) );
14
+ }
15
+
16
+ /**
17
+ * Get all part meta fields defaults.
18
+ *
19
+ * @since 1.0.0.
20
+ *
21
+ * @return array
22
+ */
23
+ public function get_customize_fields() {
24
+ return array(
25
+ 'type' => array(
26
+ 'default' => $this->type,
27
+ 'sanitize' => 'sanitize_text_field',
28
+ ),
29
+ 'label' => array(
30
+ 'default' => __( 'Address', 'happyforms' ),
31
+ 'sanitize' => 'sanitize_text_field',
32
+ ),
33
+ 'label_placement' => array(
34
+ 'default' => 'above',
35
+ 'sanitize' => 'sanitize_text_field'
36
+ ),
37
+ 'description' => array(
38
+ 'default' => '',
39
+ 'sanitize' => 'sanitize_text_field'
40
+ ),
41
+ 'tooltip_description' => array(
42
+ 'default' => 0,
43
+ 'sanitize' => 'happyforms_sanitize_checkbox'
44
+ ),
45
+ 'placeholder' => array(
46
+ 'default' => '',
47
+ 'sanitize' => 'sanitize_text_field',
48
+ ),
49
+ 'width' => array(
50
+ 'default' => 'full',
51
+ 'sanitize' => 'sanitize_key'
52
+ ),
53
+ 'css_class' => array(
54
+ 'default' => '',
55
+ 'sanitize' => 'sanitize_text_field'
56
+ ),
57
+ 'required' => array(
58
+ 'default' => 1,
59
+ 'sanitize' => 'happyforms_sanitize_checkbox',
60
+ ),
61
+ 'apikey' => array(
62
+ 'default' => '',
63
+ 'sanitize' => 'sanitize_text_field',
64
+ ),
65
+ 'mode' => array(
66
+ 'default' => 'simple',
67
+ 'sanitize' => array(
68
+ 'happyforms_sanitize_choice',
69
+ array( 'simple', 'autocomplete', 'country', 'country-city' ),
70
+ ),
71
+ ),
72
+ );
73
+ }
74
+
75
+ /**
76
+ * Get template for part item in customize pane.
77
+ *
78
+ * @since 1.0.0.
79
+ *
80
+ * @return string
81
+ */
82
+ public function customize_template() {
83
+ ?>
84
+ <p>
85
+ <label for="<%= instance.id %>_title"><?php _e( 'Title', 'happyforms' ); ?></label>
86
+ <input type="text" id="<%= instance.id %>_title" class="widefat title" value="<%= instance.label %>" data-bind="label" />
87
+ </p>
88
+ <p>
89
+ <label for="<%= instance.id %>_label_placement"><?php _e( 'Title placement', 'happyforms' ); ?></label>
90
+ <select id="<%= instance.id %>_label_placement" data-bind="label_placement">
91
+ <option value="above"<%= (instance.label_placement == 'above') ? ' selected' : '' %>><?php _e( 'Above', 'happyforms' ); ?></option>
92
+ <option value="left"<%= (instance.label_placement == 'left') ? ' selected' : '' %>><?php _e( 'Left', 'happyforms' ); ?></option>
93
+ <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
94
+ </select>
95
+ </p>
96
+ <p class="label_placement-options" style="display: none">
97
+ <label>
98
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
99
+ </label>
100
+ </p>
101
+ <p>
102
+ <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
103
+ <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
104
+ </p>
105
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
106
+ <label>
107
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
108
+ </label>
109
+ </p>
110
+ <p>
111
+ <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
112
+ <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
113
+ </p>
114
+ <p>
115
+ <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
116
+ <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
117
+ <option value="full"<%= (instance.width == 'full') ? ' selected' : '' %>><?php _e( 'Full', 'happyforms' ); ?></option>
118
+ <option value="half"<%= (instance.width == 'half') ? ' selected' : '' %>><?php _e( 'Half', 'happyforms' ); ?></option>
119
+ <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
120
+ </select>
121
+ </p>
122
+ <p>
123
+ <label for="<%= instance.id %>_mode"><?php _e( 'Mode', 'happyforms' ); ?></label>
124
+ <select id="<%= instance.id %>_mode" name="mode" data-bind="mode" class="widefat">
125
+ <option value="simple"<%= (instance.mode == 'simple') ? ' selected' : '' %>><?php _e( 'Full', 'happyforms' ); ?></option>
126
+ <option value="autocomplete"<%= (instance.mode == 'autocomplete') ? ' selected' : '' %>><?php _e( 'Full with autocomplete', 'happyforms' ); ?></option>
127
+ <option value="country-city"<%= (instance.mode == 'country-city') ? ' selected' : '' %>><?php _e( 'Country and city', 'happyforms' ); ?></option>
128
+ <option value="country"<%= (instance.mode == 'country') ? ' selected' : '' %>><?php _e( 'Country only', 'happyforms' ); ?></option>
129
+ </select>
130
+ </p>
131
+ <div class="address-apikey">
132
+ <p>
133
+ <label for="<%= instance.id %>_apikey"><?php _e( 'Google API Key', 'happyforms' ); ?></label>
134
+ <input type="text" id="<%= instance.id %>_apikey class="widefat title" value="<%= instance.apikey %>" data-bind="apikey" />
135
+ </p>
136
+ <p class="description">
137
+ Autocomplete mode uses the Google Places API to populate results. <a href="https://developers.google.com/places/web-service/get-api-key" target="_blank"><?php _e( 'Get a key for Google Places API Web Service', 'happyforms' ); ?></a>
138
+ </p>
139
+ </div>
140
+ <p>
141
+ <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
142
+ <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
143
+ </p>
144
+ <p>
145
+ <label>
146
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.required ) { %>checked="checked"<% } %> data-bind="required" /> <?php _e( 'This is a required field', 'happyforms' ); ?>
147
+ </label>
148
+ </p>
149
+ <?php
150
+ }
151
+
152
+ /**
153
+ * Get front end part template with parsed data.
154
+ *
155
+ * @since 1.0.0.
156
+ *
157
+ * @param array $part_data Form part data.
158
+ * @param array $form_data Form (post) data.
159
+ *
160
+ * @return string Markup for the form part.
161
+ */
162
+ public function frontend_template( $part_data = array(), $form_data = array() ) {
163
+ $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
164
+ $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
165
+ $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
166
+
167
+ $classes = array( 'happyforms-part--address' );
168
+
169
+ if ( $part_data['width'] ) {
170
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] );
171
+ }
172
+
173
+ if ( $part_data['label_placement'] ) {
174
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] );
175
+ }
176
+
177
+ if ( ! empty( $part_data['css_class'] ) ) {
178
+ $classes[] = $part_data['css_class'];
179
+ }
180
+
181
+ if ( $part_data['mode'] && 'country-city' === $part_data['mode'] ) {
182
+ $classes[] = 'happyforms-part--address-country-city';
183
+ }
184
+
185
+ $classes = implode( ' ', $classes );
186
+ ?>
187
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-google-apikey="<?php echo esc_attr( $part_data['apikey'] ); ?>" data-mode="<?php echo esc_attr( $part_data['mode'] ); ?>">
188
+ <div class="happyforms-part__wrap">
189
+ <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
190
+ <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
191
+ <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
192
+ <span class="happyforms-required"> <?php echo $required_text; ?></span>
193
+ <?php endif; ?>
194
+ <?php happyforms_print_part_description( $part_data ); ?>
195
+ </label>
196
+ <?php if ( 'simple' === $part_data['mode'] ) : ?>
197
+ <div class="happyforms-part__el-wrap">
198
+ <div class="happyforms-part__el">
199
+ <input class="happyforms-part__el--text-input happyforms-part__el--address" type="text" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> />
200
+ </div>
201
+ </div>
202
+ <?php elseif ( 'autocomplete' === $part_data['mode'] ) : ?>
203
+ <div class="happyforms-part__el-wrap">
204
+ <div class="happyforms-part__el">
205
+ <input class="happyforms-part__el--text-input happyforms-part__el--address-autocomplete" type="text" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> autocomplete="off" />
206
+ <div class="happyforms-part__el--address--results happyforms-part__el--address--results-autocomplete"></div>
207
+ </div>
208
+ </div>
209
+ <?php elseif ( 'country' === $part_data['mode'] ) : ?>
210
+ <div class="happyforms-part__el-wrap">
211
+ <div class="happyforms-part__el">
212
+ <input class="happyforms-part__el--text-input happyforms-part__el--address-country" type="text" placeholder="<?php _e( 'Country', 'happyforms' ); ?>" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> autocomplete="off" />
213
+ <div class="happyforms-part__el--address--results happyforms-part__el--address--results-country"></div>
214
+ </div>
215
+ </div>
216
+ <?php else: ?>
217
+ <div class="happyforms-part__el-wrap">
218
+ <div class="happyforms-part__el">
219
+ <input class="happyforms-part__el--text-input happyforms-part__el--address-country" type="text" placeholder="<?php _e( 'Country', 'happyforms' ); ?>" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> autocomplete="off" />
220
+ <div class="happyforms-part__el--address--results happyforms-part__el--address--results-country"></div>
221
+ </div>
222
+ <div class="happyforms-part__el">
223
+ <input class="happyforms-part__el happyforms-part__el--text-input happyforms-part__el--address-city" type="text" placeholder="<?php _e( 'City', 'happyforms' ); ?>" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> />
224
+ </div>
225
+ </div>
226
+ <?php endif; ?>
227
+ <input type="hidden" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" id="<?php echo esc_attr( $html_id ); ?>">
228
+ <?php
229
+ if ( $form_data ) :
230
+ happyforms_message_notices( $form_data, $part_data['id'] );
231
+ endif;
232
+ ?>
233
+ </div>
234
+ </div>
235
+ <?php
236
+ }
237
+
238
+ /**
239
+ * Get all possible messages definitions.
240
+ *
241
+ * @since 1.0.0.
242
+ *
243
+ * @return array Associative array, specifying message type and copy.
244
+ */
245
+ public function get_message_definitions() {
246
+ return array(
247
+ 'missing_required_field' => array(
248
+ 'type' => 'error',
249
+ 'message' => __( 'This field is required.', 'happyforms' ),
250
+ ),
251
+ );
252
+ }
253
+
254
+ /**
255
+ * Sanitize submitted value before storing it.
256
+ *
257
+ * @since 1.0.0.
258
+ *
259
+ * @param array $part_data Form part data.
260
+ *
261
+ * @return string
262
+ */
263
+ public function sanitize_value( $part_data = array() ) {
264
+ $sanitized_value = $this->get_default_value();
265
+ $part_id = $part_data['id'];
266
+
267
+ if ( isset( $_REQUEST[$part_id] ) ) {
268
+ $sanitized_value = sanitize_text_field( $_REQUEST[$part_id] );
269
+ }
270
+
271
+ return $sanitized_value;
272
+ }
273
+
274
+ /**
275
+ * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
276
+ *
277
+ * @since 1.0.0.
278
+ *
279
+ * @param array $part_data Form part data.
280
+ * @param string $value Submitted value.
281
+ *
282
+ * @return string|object
283
+ */
284
+ public function validate_value( $part_data, $value ) {
285
+ $part_id = $part_data['id'];
286
+ $validated_value = $value;
287
+
288
+ if ( 1 === $part_data['required'] && empty( $validated_value ) ) {
289
+ $validated_value = new WP_Error( $part_id, 'missing_required_field' );
290
+ }
291
+
292
+ return $validated_value;
293
+ }
294
+
295
+ /**
296
+ * Enqueue scripts in customizer area.
297
+ *
298
+ * @since 1.0.0.
299
+ *
300
+ * @param array List of dependencies.
301
+ *
302
+ * @return void
303
+ */
304
+ public function customize_enqueue_scripts( $deps = array() ) {
305
+ wp_enqueue_script(
306
+ 'part-address',
307
+ happyforms_get_plugin_url() . 'assets/js/parts/part-address.js',
308
+ $deps,
309
+ false,
310
+ true
311
+ );
312
+ }
313
+
314
+ /**
315
+ * Filter: dependencies for the preview screen.
316
+ *
317
+ * @since 1.0.0.
318
+ *
319
+ * @hooked filter happyforms_preview_dependencies
320
+ *
321
+ * @param array List of dependencies.
322
+ *
323
+ * @return array
324
+ */
325
+ public function preview_dependencies( $deps = array() ) {
326
+ wp_register_script(
327
+ 'happyforms-part-address',
328
+ happyforms_get_plugin_url() . 'assets/js/frontend/address.js',
329
+ array( 'jquery', 'jquery-ui-autocomplete' ),
330
+ false,
331
+ true
332
+ );
333
+
334
+ wp_localize_script(
335
+ 'happyforms-part-address',
336
+ '_happyFormsCountries',
337
+ happyforms_get_countries()
338
+ );
339
+
340
+ array_push( $deps, 'happyforms-part-address' );
341
+
342
+ return $deps;
343
+ }
344
+
345
+ /**
346
+ * Action: enqueue additional scripts on the frontend.
347
+ *
348
+ * @since 1.0.0.
349
+ *
350
+ * @hooked action happyforms_frontend_form_scripts
351
+ *
352
+ * @param array List of dependencies.
353
+ *
354
+ * @return array
355
+ */
356
+ public function frontend_enqueue_scripts( $form = array() ) {
357
+ $form_controller = happyforms_get_form_controller();
358
+
359
+ if ( empty( $form ) ) {
360
+ return;
361
+ }
362
+
363
+ if ( empty( $form_controller->get_first_part_by_type( $form, $this->type ) ) ) {
364
+ return;
365
+ }
366
+
367
+ wp_register_script(
368
+ 'happyforms-part-address',
369
+ happyforms_get_plugin_url() . 'assets/js/frontend/address.js',
370
+ array( 'jquery', 'jquery-ui-autocomplete' ),
371
+ false,
372
+ true
373
+ );
374
+
375
+ wp_localize_script(
376
+ 'happyforms-part-address',
377
+ '_happyFormsCountries',
378
+ happyforms_get_countries()
379
+ );
380
+
381
+ wp_enqueue_script( 'happyforms-part-address' );
382
+ }
383
+
384
+ }
inc/classes/parts/class-part-checkbox.php CHANGED
@@ -14,9 +14,9 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
14
 
15
  /**
16
  * Get all part meta fields defaults.
17
- *
18
  * @since 1.0.0.
19
- *
20
  * @return array
21
  */
22
  public function get_customize_fields() {
@@ -37,6 +37,10 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
37
  'default' => '',
38
  'sanitize' => 'sanitize_text_field'
39
  ),
 
 
 
 
40
  'width' => array(
41
  'default' => 'full',
42
  'sanitize' => 'sanitize_key'
@@ -62,9 +66,9 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
62
 
63
  /**
64
  * Get part option (sub-part) defaults.
65
- *
66
  * @since 1.0.0.
67
- *
68
  * @return array
69
  */
70
  public function get_option_defaults() {
@@ -76,9 +80,9 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
76
 
77
  /**
78
  * Get template for part item in customize pane.
79
- *
80
  * @since 1.0.0.
81
- *
82
  * @return string
83
  */
84
  public function customize_template() {
@@ -95,10 +99,20 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
95
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
96
  </select>
97
  </p>
 
 
 
 
 
98
  <p>
99
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
100
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
101
  </p>
 
 
 
 
 
102
  <p>
103
  <label for="<%= instance.id %>_display_type"><?php _e( 'Display options', 'happyforms' ); ?></label>
104
  <select id="<%= instance.id %>_display_type" name="display_type" data-bind="display_type" class="widefat">
@@ -114,6 +128,11 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
114
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
115
  </select>
116
  </p>
 
 
 
 
 
117
  <p>
118
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
119
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -137,9 +156,9 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
137
 
138
  /**
139
  * Get template for option / sub-part item in customize pane.
140
- *
141
  * @since 1.0.0.
142
- *
143
  * @return string
144
  */
145
  public function customize_item_template() {
@@ -161,42 +180,39 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
161
 
162
  /**
163
  * Get front end part template with parsed data.
164
- *
165
  * @since 1.0.0.
166
- *
167
  * @param array $part_data Form part data.
168
  * @param array $form_data Form (post) data.
169
- *
170
  * @return string Markup for the form part.
171
  */
172
  public function frontend_template( $part_data = array(), $form_data = array() ) {
173
  $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
174
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
175
 
176
- $classes = ' ';
177
 
178
  if ( $part_data['width'] ) {
179
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
180
  }
181
 
182
  if ( $part_data['display_type'] == 'block') {
183
- $classes .= 'display-type--block ';
184
  }
185
 
186
  if ( $part_data['label_placement'] ) {
187
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
188
  }
189
 
190
  if ( !empty( $part_data['css_class'] ) ) {
191
- $classes .= $part_data['css_class'];
192
  }
 
 
193
  ?>
194
- <div class="happyforms-part happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
195
- <?php
196
- if ( $form_data ) :
197
- happyforms_message_notices( $form_data, $part_data['id'] );
198
- endif;
199
- ?>
200
  <div class="happyforms-part__wrap">
201
  <label class="happyforms-part__label">
202
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
@@ -204,7 +220,6 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
204
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
205
  <?php endif; ?>
206
  </label>
207
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
208
  <div class="happyforms-part__el">
209
  <?php
210
  if ( isset( $part_data['options'] ) ) {
@@ -213,11 +228,17 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
213
  foreach( $options as $option ) {
214
  $option = wp_parse_args( $option, $this->get_option_defaults() );
215
 
216
- $this->frontend_item_template( $part_data, $option, $part_data['required'] );
217
  }
218
  }
219
  ?>
220
  </div>
 
 
 
 
 
 
221
  </div>
222
  </div>
223
  <?php
@@ -225,45 +246,50 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
225
 
226
  /**
227
  * Get front end option (sub-part) template with parsed data.
228
- *
229
  * @since 1.0.0.
230
- *
231
  * @param array $part_data Form part data.
232
  * @param array $option Option (form sub-part) data.
233
  * @param int $requred Required field (1) or not.
234
- *
235
  * @return string Markup for the part option.
236
  */
237
- public function frontend_item_template( $part_data, $option, $required ) {
238
  ?>
239
  <label class="option-label" id="<?php echo esc_attr( $option['id'] ); ?>">
240
- <input type="checkbox" name="<?php echo esc_attr( $part_data['id'] ); ?>[]" value="<?php echo esc_attr( $option['label'] ); ?>"<?php if ( $option['is_default'] == 1 ) : ?> checked<?php endif; ?><?php if ( 1 === intval( $required ) ) : ?> required aria-required="true"<?php endif; ?>> <span class="label"><?php echo esc_attr( $option['label'] ); ?></span>
 
 
 
241
  </label>
242
  <?php
243
  }
244
 
245
  /**
246
  * Get option's Backbone template for preview purposes. Passed to previewer to create a new Backbone view.
247
- *
248
  * @since 1.0.0.
249
- *
250
  * @return string Backbone template.
251
  */
252
  public function preview_option_template() {
253
  ?>
254
  <label class="option-label" id="<%= id %>">
255
- <input type="checkbox" name="" value="<%= label %>"> <span class="label"><%= label %></span>
 
 
256
  </label>
257
  <?php
258
  }
259
 
260
  /**
261
  * Enqueue scripts in customizer area.
262
- *
263
  * @since 1.0.0.
264
- *
265
  * @param array List of dependencies.
266
- *
267
  * @return void
268
  */
269
  public function customize_enqueue_scripts( $deps = array() ) {
@@ -278,9 +304,9 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
278
 
279
  /**
280
  * Get all possible messages definitions.
281
- *
282
  * @since 1.0.0.
283
- *
284
  * @return array Associative array, specifying message type and copy.
285
  */
286
  public function get_message_definitions() {
@@ -298,11 +324,11 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
298
 
299
  /**
300
  * Sanitize submitted value before storing it.
301
- *
302
  * @since 1.0.0.
303
- *
304
  * @param array $part_data Form part data.
305
- *
306
  * @return array
307
  */
308
  public function sanitize_value( $part_data = array() ) {
@@ -322,12 +348,12 @@ class HappyForms_Part_Checkbox extends HappyForms_Form_Part {
322
 
323
  /**
324
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
325
- *
326
  * @since 1.0.0.
327
- *
328
  * @param array $part_data Form part data.
329
  * @param string $value Submitted value.
330
- *
331
  * @return string|object
332
  */
333
  public function validate_value( $part_data, $value ) {
14
 
15
  /**
16
  * Get all part meta fields defaults.
17
+ *
18
  * @since 1.0.0.
19
+ *
20
  * @return array
21
  */
22
  public function get_customize_fields() {
37
  'default' => '',
38
  'sanitize' => 'sanitize_text_field'
39
  ),
40
+ 'tooltip_description' => array(
41
+ 'default' => 0,
42
+ 'sanitize' => 'happyforms_sanitize_checkbox'
43
+ ),
44
  'width' => array(
45
  'default' => 'full',
46
  'sanitize' => 'sanitize_key'
66
 
67
  /**
68
  * Get part option (sub-part) defaults.
69
+ *
70
  * @since 1.0.0.
71
+ *
72
  * @return array
73
  */
74
  public function get_option_defaults() {
80
 
81
  /**
82
  * Get template for part item in customize pane.
83
+ *
84
  * @since 1.0.0.
85
+ *
86
  * @return string
87
  */
88
  public function customize_template() {
99
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
100
  </select>
101
  </p>
102
+ <p class="label_placement-options" style="display: none">
103
+ <label>
104
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
105
+ </label>
106
+ </p>
107
  <p>
108
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
109
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
110
  </p>
111
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
112
+ <label>
113
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
114
+ </label>
115
+ </p>
116
  <p>
117
  <label for="<%= instance.id %>_display_type"><?php _e( 'Display options', 'happyforms' ); ?></label>
118
  <select id="<%= instance.id %>_display_type" name="display_type" data-bind="display_type" class="widefat">
128
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
129
  </select>
130
  </p>
131
+ <p class="width-options" style="display: none">
132
+ <label>
133
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
134
+ </label>
135
+ </p>
136
  <p>
137
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
138
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
156
 
157
  /**
158
  * Get template for option / sub-part item in customize pane.
159
+ *
160
  * @since 1.0.0.
161
+ *
162
  * @return string
163
  */
164
  public function customize_item_template() {
180
 
181
  /**
182
  * Get front end part template with parsed data.
183
+ *
184
  * @since 1.0.0.
185
+ *
186
  * @param array $part_data Form part data.
187
  * @param array $form_data Form (post) data.
188
+ *
189
  * @return string Markup for the form part.
190
  */
191
  public function frontend_template( $part_data = array(), $form_data = array() ) {
192
  $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
193
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
194
 
195
+ $classes = array('happyforms-part--checkbox');
196
 
197
  if ( $part_data['width'] ) {
198
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
199
  }
200
 
201
  if ( $part_data['display_type'] == 'block') {
202
+ $classes[] = 'display-type--block ';
203
  }
204
 
205
  if ( $part_data['label_placement'] ) {
206
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
207
  }
208
 
209
  if ( !empty( $part_data['css_class'] ) ) {
210
+ $classes[] = $part_data['css_class'];
211
  }
212
+
213
+ $classes = implode( ' ', $classes );
214
  ?>
215
+ <div class="happyforms-part happyforms-part--checkbox happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
216
  <div class="happyforms-part__wrap">
217
  <label class="happyforms-part__label">
218
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
220
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
221
  <?php endif; ?>
222
  </label>
 
223
  <div class="happyforms-part__el">
224
  <?php
225
  if ( isset( $part_data['options'] ) ) {
228
  foreach( $options as $option ) {
229
  $option = wp_parse_args( $option, $this->get_option_defaults() );
230
 
231
+ $this->frontend_item_template( $part_data, $option, $part_data['required'], $form_data );
232
  }
233
  }
234
  ?>
235
  </div>
236
+ <?php happyforms_print_part_description( $part_data ); ?>
237
+ <?php
238
+ if ( $form_data ) :
239
+ happyforms_message_notices( $form_data, $part_data['id'] );
240
+ endif;
241
+ ?>
242
  </div>
243
  </div>
244
  <?php
246
 
247
  /**
248
  * Get front end option (sub-part) template with parsed data.
249
+ *
250
  * @since 1.0.0.
251
+ *
252
  * @param array $part_data Form part data.
253
  * @param array $option Option (form sub-part) data.
254
  * @param int $requred Required field (1) or not.
255
+ *
256
  * @return string Markup for the part option.
257
  */
258
+ public function frontend_item_template( $part_data, $option, $required, $form_data = array() ) {
259
  ?>
260
  <label class="option-label" id="<?php echo esc_attr( $option['id'] ); ?>">
261
+ <input type="checkbox" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>[]" value="<?php echo esc_attr( $option['label'] ); ?>"<?php if ( $option['is_default'] == 1 ) : ?> checked<?php endif; ?><?php if ( 1 === intval( $required ) ) : ?> required aria-required="true"<?php endif; ?>>
262
+ <span class="checkmark"></span>
263
+
264
+ <span class="label"><?php echo esc_attr( $option['label'] ); ?></span>
265
  </label>
266
  <?php
267
  }
268
 
269
  /**
270
  * Get option's Backbone template for preview purposes. Passed to previewer to create a new Backbone view.
271
+ *
272
  * @since 1.0.0.
273
+ *
274
  * @return string Backbone template.
275
  */
276
  public function preview_option_template() {
277
  ?>
278
  <label class="option-label" id="<%= id %>">
279
+ <input type="checkbox" name="" value="<%= label %>">
280
+ <span class="checkmark"></span>
281
+ <span class="label"><%= label %></span>
282
  </label>
283
  <?php
284
  }
285
 
286
  /**
287
  * Enqueue scripts in customizer area.
288
+ *
289
  * @since 1.0.0.
290
+ *
291
  * @param array List of dependencies.
292
+ *
293
  * @return void
294
  */
295
  public function customize_enqueue_scripts( $deps = array() ) {
304
 
305
  /**
306
  * Get all possible messages definitions.
307
+ *
308
  * @since 1.0.0.
309
+ *
310
  * @return array Associative array, specifying message type and copy.
311
  */
312
  public function get_message_definitions() {
324
 
325
  /**
326
  * Sanitize submitted value before storing it.
327
+ *
328
  * @since 1.0.0.
329
+ *
330
  * @param array $part_data Form part data.
331
+ *
332
  * @return array
333
  */
334
  public function sanitize_value( $part_data = array() ) {
348
 
349
  /**
350
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
351
+ *
352
  * @since 1.0.0.
353
+ *
354
  * @param array $part_data Form part data.
355
  * @param string $value Submitted value.
356
+ *
357
  * @return string|object
358
  */
359
  public function validate_value( $part_data, $value ) {
inc/classes/parts/class-part-country.php DELETED
@@ -1,282 +0,0 @@
1
- <?php
2
-
3
- class HappyForms_Part_Country extends HappyForms_Form_Part {
4
-
5
- public $type = 'country';
6
- public $template_id = 'happyforms-country-template';
7
-
8
- public function __construct() {
9
- $this->label = __( 'Country', 'happyforms' );
10
- $this->description = __( 'For selecting one country from a dropdown. Default value adjustable.', 'happyforms' );
11
- }
12
-
13
- /**
14
- * Get all part meta fields defaults.
15
- *
16
- * @since 1.0.0.
17
- *
18
- * @return array
19
- */
20
- public function get_customize_fields() {
21
- return array(
22
- 'type' => array(
23
- 'default' => $this->type,
24
- 'sanitize' => 'sanitize_text_field',
25
- ),
26
- 'label' => array(
27
- 'default' => __( 'Country', 'happyforms' ),
28
- 'sanitize' => 'sanitize_text_field',
29
- ),
30
- 'label_placement' => array(
31
- 'default' => 'above',
32
- 'sanitize' => 'sanitize_text_field'
33
- ),
34
- 'description' => array(
35
- 'default' => '',
36
- 'sanitize' => 'sanitize_text_field'
37
- ),
38
- 'width' => array(
39
- 'default' => 'full',
40
- 'sanitize' => 'sanitize_key'
41
- ),
42
- 'css_class' => array(
43
- 'default' => '',
44
- 'sanitize' => 'sanitize_text_field'
45
- ),
46
- 'placeholder' => array(
47
- 'default' => '',
48
- 'sanitize' => 'sanitize_text_field',
49
- ),
50
- 'default_country' => array(
51
- 'default' => '',
52
- 'sanitize' => 'sanitize_text_field'
53
- ),
54
- 'required' => array(
55
- 'default' => 1,
56
- 'sanitize' => 'happyforms_sanitize_checkbox',
57
- ),
58
- );
59
- }
60
-
61
- /**
62
- * Get template for part item in customize pane.
63
- *
64
- * @since 1.0.0.
65
- *
66
- * @return string
67
- */
68
- public function customize_template() {
69
- ?>
70
- <p>
71
- <label for="<%= instance.id %>_title"><?php _e( 'Title', 'happyforms' ); ?></label>
72
- <input type="text" id="<%= instance.id %>_title" class="widefat title" value="<%= instance.label %>" data-bind="label" />
73
- </p>
74
- <p>
75
- <label for="<%= instance.id %>_label_placement"><?php _e( 'Title placement', 'happyforms' ); ?></label>
76
- <select id="<%= instance.id %>_label_placement" data-bind="label_placement">
77
- <option value="above"<%= (instance.label_placement == 'above') ? ' selected' : '' %>><?php _e( 'Above', 'happyforms' ); ?></option>
78
- <option value="left"<%= (instance.label_placement == 'left') ? ' selected' : '' %>><?php _e( 'Left', 'happyforms' ); ?></option>
79
- <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
80
- </select>
81
- </p>
82
- <p>
83
- <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
84
- <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
85
- </p>
86
- <p>
87
- <label for="<%= instance.id %>_default_country"><?php _e( 'Default Country', 'happyforms' ); ?></label>
88
- <select id="<%= instance.id %>_default_country" name="default_country" data-bind="default_country" class="widefat">
89
- <option value=""><?php _e( 'None', 'happyforms' ); ?></option>
90
- <?php
91
- $countries = $this->get_countries_array();
92
-
93
- foreach ( $countries as $country ) {
94
- ?>
95
- <option value="<?php echo $country; ?>"<%= ( instance.default_country == "<?php echo $country; ?>" ) ? ' selected' : '' %>><?php echo $country; ?></option>
96
- <?php
97
- }
98
- ?>
99
- </select>
100
- </p>
101
- <p>
102
- <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
103
- <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
104
- <option value="full"<%= (instance.width == 'full') ? ' selected' : '' %>><?php _e( 'Full', 'happyforms' ); ?></option>
105
- <option value="half"<%= (instance.width == 'half') ? ' selected' : '' %>><?php _e( 'Half', 'happyforms' ); ?></option>
106
- <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
107
- </select>
108
- </p>
109
- <p>
110
- <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
111
- <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
112
- </p>
113
- <p>
114
- <label>
115
- <input type="checkbox" class="checkbox" value="1" <% if ( instance.required ) { %>checked="checked"<% } %> data-bind="required" /> <?php _e( 'This is a required field', 'happyforms' ); ?>
116
- </label>
117
- </p>
118
- <?php
119
- }
120
-
121
- /**
122
- * Get front end part template with parsed data.
123
- *
124
- * @since 1.0.0.
125
- *
126
- * @param array $part_data Form part data.
127
- * @param array $form_data Form (post) data.
128
- *
129
- * @return string Markup for the form part.
130
- */
131
- public function frontend_template( $part_data = array(), $form_data = array() ) {
132
- $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
133
- $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
134
- $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
135
-
136
- $classes = ' ';
137
-
138
- if ( $part_data['width'] ) {
139
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
140
- }
141
-
142
- if ( $part_data['label_placement'] ) {
143
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
144
- }
145
-
146
- if ( !empty( $part_data['css_class'] ) ) {
147
- $classes .= $part_data['css_class'];
148
- }
149
- ?>
150
- <div class="happyforms-part happyforms-part--select happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
151
- <?php
152
- if ( $form_data ) :
153
- happyforms_message_notices( $form_data, $part_data['id'] );
154
- endif;
155
- ?>
156
- <div class="happyforms-part__wrap">
157
- <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
158
- <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
159
- <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
160
- <span class="happyforms-required"> <?php echo $required_text; ?></span>
161
- <?php endif; ?>
162
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
163
- </label>
164
- <select id="<?php echo esc_attr( $html_id ); ?>" name="<?php echo esc_attr( $part_data['id'] ); ?>" class="happyforms-part__el" <?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
165
- <?php if ( $part_data['default_country'] == '' ) : ?>
166
- <option value="">- <?php _e( 'Select', 'happyforms' ); ?> -</option>
167
- <?php endif;
168
-
169
- $countries = $this->get_countries_array();
170
-
171
- foreach ( $countries as $country ) {
172
- $attr = '';
173
-
174
- if ( $country == $part_data['default_country'] ) {
175
- $attr = ' selected';
176
- }
177
-
178
- echo '<option value="'. $country .'"'. $attr .'>'. $country .'</option>';
179
- }
180
- ?>
181
- </select>
182
- </div>
183
- </div>
184
- <?php
185
- }
186
-
187
- /**
188
- * Get all possible messages definitions.
189
- *
190
- * @since 1.0.0.
191
- *
192
- * @return array Associative array, specifying message type and copy.
193
- */
194
- public function get_message_definitions() {
195
- return array(
196
- 'missing_required_field' => array(
197
- 'type' => 'error',
198
- 'message' => __( 'This field is required.', 'happyforms' ),
199
- ),
200
- 'invalid_country' => array(
201
- 'type' => 'error',
202
- 'message' => __( 'Country doesn\'t match entries listed in dropdown', 'happyforms' )
203
- )
204
- );
205
- }
206
-
207
- /**
208
- * Sanitize submitted value before storing it.
209
- *
210
- * @since 1.0.0.
211
- *
212
- * @param array $part_data Form part data.
213
- *
214
- * @return string
215
- */
216
- public function sanitize_value( $part_data = array() ) {
217
- $sanitized_value = $this->get_default_value();
218
- $part_id = $part_data['id'];
219
-
220
- if ( isset( $_REQUEST[$part_id] ) ) {
221
- $sanitized_value = sanitize_text_field( $_REQUEST[$part_id] );
222
- }
223
-
224
- return $sanitized_value;
225
- }
226
-
227
- /**
228
- * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
229
- *
230
- * @since 1.0.0.
231
- *
232
- * @param array $part_data Form part data.
233
- * @param string $value Submitted value.
234
- *
235
- * @return string|object
236
- */
237
- public function validate_value( $part_data, $value ) {
238
- $part_id = $part_data['id'];
239
- $validated_value = $value;
240
-
241
- if ( 1 === $part_data['required'] && empty( $validated_value ) ) {
242
- $validated_value = new WP_Error( $part_id, 'missing_required_field' );
243
- }
244
-
245
- if ( !in_array( $validated_value, $this->get_countries_array() ) ) {
246
- $validated_value = new WP_Error( $part_id, 'invalid_country' );
247
- }
248
-
249
- return $validated_value;
250
- }
251
-
252
- /**
253
- * Get array of countries in the world.
254
- *
255
- * @since 1.0.0.
256
- *
257
- * @return array List of countries.
258
- */
259
- public function get_countries_array() {
260
- return array( 'Afghanistan', 'Albania', 'Algeria', 'American Samoa', 'Andorra', 'Angola', 'Anguilla', 'Antarctica', 'Antigua and Barbuda', 'Argentina', 'Armenia', 'Aruba', 'Australia', 'Austria', 'Azerbaijan', 'Bahamas', 'Bahrain', 'Bangladesh', 'Barbados', 'Belarus', 'Belgium', 'Belize', 'Benin', 'Bermuda', 'Bhutan', 'Bolivia', 'Bosnia and Herzegowina', 'Botswana', 'Bouvet Island', 'Brazil', 'British Indian Ocean Territory', 'Brunei Darussalam', 'Bulgaria', 'Burkina Faso', 'Burundi', 'Cambodia', 'Cameroon', 'Canada', 'Cape Verde', 'Cayman Islands', 'Central African Republic', 'Chad', 'Chile', 'China', 'Christmas Island', 'Cocos (Keeling) Islands', 'Colombia', 'Comoros', 'Congo', 'Congo, the Democratic Republic of the', 'Cook Islands', 'Costa Rica', 'Cote d\'Ivoire', 'Croatia (Hrvatska)', 'Cuba', 'Cyprus', 'Czech Republic', 'Denmark', 'Djibouti', 'Dominica', 'Dominican Republic', 'East Timor', 'Ecuador', 'Egypt', 'El Salvador', 'Equatorial Guinea', 'Eritrea', 'Estonia', 'Ethiopia', 'Falkland Islands (Malvinas)', 'Faroe Islands', 'Fiji', 'Finland', 'France', 'France Metropolitan', 'French Guiana', 'French Polynesia', 'French Southern Territories', 'Gabon', 'Gambia', 'Georgia', 'Germany', 'Ghana', 'Gibraltar', 'Greece', 'Greenland', 'Grenada', 'Guadeloupe', 'Guam', 'Guatemala', 'Guinea', 'Guinea-Bissau', 'Guyana', 'Haiti', 'Heard and Mc Donald Islands', 'Holy See (Vatican City State)', 'Honduras', 'Hong Kong', 'Hungary', 'Iceland', 'India', 'Indonesia', 'Iran (Islamic Republic of)', 'Iraq', 'Ireland', 'Israel', 'Italy', 'Jamaica', 'Japan', 'Jordan', 'Kazakhstan', 'Kenya', 'Kiribati', 'Korea, Democratic People\'s Republic of', 'Korea, Republic of', 'Kuwait', 'Kyrgyzstan', 'Lao, People\'s Democratic Republic', 'Latvia', 'Lebanon', 'Lesotho', 'Liberia', 'Libyan Arab Jamahiriya', 'Liechtenstein', 'Lithuania', 'Luxembourg', 'Macau', 'Macedonia, The Former Yugoslav Republic of', 'Madagascar', 'Malawi', 'Malaysia', 'Maldives', 'Mali', 'Malta', 'Marshall Islands', 'Martinique', 'Mauritania', 'Mauritius', 'Mayotte', 'Mexico', 'Micronesia, Federated States of', 'Moldova, Republic of', 'Monaco', 'Mongolia', 'Montserrat', 'Morocco', 'Mozambique', 'Myanmar', 'Namibia', 'Nauru', 'Nepal', 'Netherlands', 'Netherlands Antilles', 'New Caledonia', 'New Zealand', 'Nicaragua', 'Niger', 'Nigeria', 'Niue', 'Norfolk Island', 'Northern Mariana Islands', 'Norway', 'Oman', 'Pakistan', 'Palau', 'Panama', 'Papua New Guinea', 'Paraguay', 'Peru', 'Philippines', 'Pitcairn', 'Poland', 'Portugal', 'Puerto Rico', 'Qatar', 'Reunion', 'Romania', 'Russian Federation', 'Rwanda', 'Saint Kitts and Nevis', 'Saint Lucia', 'Saint Vincent and the Grenadines', 'Samoa', 'San Marino', 'Sao Tome and Principe', 'Saudi Arabia', 'Senegal', 'Seychelles', 'Sierra Leone', 'Singapore', 'Slovakia (Slovak Republic)', 'Slovenia', 'Solomon Islands', 'Somalia', 'South Africa', 'South Georgia and the South Sandwich Islands', 'Spain', 'Sri Lanka', 'St. Helena', 'St. Pierre and Miquelon', 'Sudan', 'Suriname', 'Svalbard and Jan Mayen Islands', 'Swaziland', 'Sweden', 'Switzerland', 'Syrian Arab Republic', 'Taiwan, Province of China', 'Tajikistan', 'Tanzania, United Republic of', 'Thailand', 'Togo', 'Tokelau', 'Tonga', 'Trinidad and Tobago', 'Tunisia', 'Turkey', 'Turkmenistan', 'Turks and Caicos Islands', 'Tuvalu', 'Uganda', 'Ukraine', 'United Arab Emirates', 'United Kingdom', 'United States', 'United States Minor Outlying Islands', 'Uruguay', 'Uzbekistan', 'Vanuatu', 'Venezuela', 'Vietnam', 'Virgin Islands (British)', 'Virgin Islands (U.S.)', 'Wallis and Futuna Islands', 'Western Sahara', 'Yemen', 'Yugoslavia', 'Zambia', 'Zimbabwe' );
261
- }
262
-
263
- /**
264
- * Enqueue scripts in customizer area.
265
- *
266
- * @since 1.0.0.
267
- *
268
- * @param array List of dependencies.
269
- *
270
- * @return void
271
- */
272
- public function customize_enqueue_scripts( $deps = array() ) {
273
- wp_enqueue_script(
274
- 'part-country',
275
- happyforms_get_plugin_url() . 'assets/js/parts/part-country.js',
276
- $deps,
277
- false,
278
- true
279
- );
280
- }
281
-
282
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
inc/classes/parts/class-part-date.php CHANGED
@@ -7,14 +7,14 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
7
 
8
  public function __construct() {
9
  $this->label = __( 'Date', 'happyforms' );
10
- $this->description = __( 'For date fields with date picker.', 'happyforms' );
11
  }
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
- *
16
  * @since 1.0.0.
17
- *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
@@ -35,9 +35,17 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
38
- 'placeholder' => array(
39
- 'default' => '',
40
- 'sanitize' => 'sanitize_text_field',
 
 
 
 
 
 
 
 
41
  ),
42
  'width' => array(
43
  'default' => 'full',
@@ -47,18 +55,6 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
47
  'default' => '',
48
  'sanitize' => 'sanitize_text_field'
49
  ),
50
- 'date_format' => array(
51
- 'default' => 'mm/dd/yy',
52
- 'sanitize' => 'sanitize_text_field'
53
- ),
54
- 'change_year' => array(
55
- 'default' => 0,
56
- 'sanitize' => 'intval'
57
- ),
58
- 'change_month' => array(
59
- 'default' => 1,
60
- 'sanitize' => 'intval'
61
- ),
62
  'required' => array(
63
  'default' => 1,
64
  'sanitize' => 'happyforms_sanitize_checkbox',
@@ -68,9 +64,9 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
68
 
69
  /**
70
  * Get template for part item in customize pane.
71
- *
72
  * @since 1.0.0.
73
- *
74
  * @return string
75
  */
76
  public function customize_template() {
@@ -87,32 +83,34 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
87
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
88
  </select>
89
  </p>
 
 
 
 
 
90
  <p>
91
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
92
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
93
  </p>
94
- <p>
95
- <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
96
- <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
97
- </p>
98
- <p>
99
- <label for="<%= instance.id %>_format"><?php _e( 'Format', 'happyforms' ); ?></label>
100
- <select id="<%= instance.id %>_format" data-bind="date_format">
101
- <option value="mm/dd/yy"<%= (instance.date_format == 'mm/dd/yy') ? ' selected' : '' %>>mm/dd/yy</option>
102
- <option value="dd/mm/yy"<%= (instance.date_format == 'dd/mm/yy') ? ' selected' : '' %>>dd/mm/yy</option>
103
- <option value="yy/dd/mm"<%= (instance.date_format == 'yy/dd/mm') ? ' selected' : '' %>>yy/dd/mm</option>
104
- <option value="yy/mm/dd"<%= (instance.date_format == 'yy/mm/dd') ? ' selected' : '' %>>yy/mm/dd</option>
105
- </select>
106
- </p>
107
- <p>
108
  <label>
109
- <input type="checkbox" class="checkbox adatepicker-checkboxes" value="1" <% if ( instance.change_month ) { %>checked="checked"<% } %> data-bind="change_month" /> <?php _e( 'Allow changing month in calendar', 'happyforms' ); ?>
110
  </label>
111
  </p>
112
  <p>
113
- <label>
114
- <input type="checkbox" class="checkbox datepicker-checkboxes" value="1" <% if ( instance.change_year ) { %>checked="checked"<% } %> data-bind="change_year" /> <?php _e( 'Allow changing year in calendar', 'happyforms' ); ?>
115
- </label>
 
 
 
 
 
 
 
 
 
 
116
  </p>
117
  <p>
118
  <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
@@ -122,6 +120,11 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
122
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
123
  </select>
124
  </p>
 
 
 
 
 
125
  <p>
126
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
127
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -136,62 +139,137 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
136
 
137
  /**
138
  * Get front end part template with parsed data.
139
- *
140
  * @since 1.0.0.
141
- *
142
  * @param array $part_data Form part data.
143
  * @param array $form_data Form (post) data.
144
- *
145
  * @return string Markup for the form part.
146
  */
147
  public function frontend_template( $part_data = array(), $form_data = array() ) {
148
  $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
149
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
150
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
151
- $mask = '99/99/9999';
152
-
153
- if ( $part_data['date_format'] ) {
154
- $mask = str_replace( array('m', 'd'), '9', $part_data['date_format'] );
155
- $mask = str_replace( 'yy', '9999', $mask );
156
- }
157
 
158
- $classes = ' ';
159
 
160
  if ( $part_data['width'] ) {
161
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
162
  }
163
 
164
  if ( $part_data['label_placement'] ) {
165
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
166
  }
167
 
168
  if ( !empty( $part_data['css_class'] ) ) {
169
- $classes .= $part_data['css_class'];
170
  }
171
 
172
- wp_enqueue_script( 'jquery-ui-datepicker' );
173
 
174
- wp_enqueue_script(
175
- 'cleave',
176
- happyforms_get_plugin_url() . 'assets/js/lib/cleave.min.js',
177
- array()
178
- );
179
  ?>
180
- <div class="happyforms-part happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
181
- <?php
182
- if ( $form_data ) :
183
- happyforms_message_notices( $form_data, $part_data['id'] );
184
- endif;
185
- ?>
186
  <div class="happyforms-part__wrap">
187
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
188
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
189
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
190
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
191
  <?php endif; ?>
192
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
193
  </label>
194
- <input type="text" id="<?php echo esc_attr( $html_id ); ?>" name="<?php echo esc_attr( $part_data['id'] ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" class="happyforms-part__el happyforms-part__el--text-input happyforms-datepicker happyforms-masked-input" data-mask-type="date" data-format="<?php echo esc_attr( $part_data[ 'date_format' ] ); ?>" data-change-year="<?php echo esc_attr( $part_data[ 'change_year' ] ); ?>" data-change-month="<?php echo esc_attr( $part_data[ 'change_month' ] ); ?>" data-mask="<?php echo esc_attr( $mask ); ?>" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195
  </div>
196
  </div>
197
  <?php
@@ -199,9 +277,9 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
199
 
200
  /**
201
  * Get all possible messages definitions.
202
- *
203
  * @since 1.0.0.
204
- *
205
  * @return array Associative array, specifying message type and copy.
206
  */
207
  public function get_message_definitions() {
@@ -219,19 +297,49 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
219
 
220
  /**
221
  * Sanitize submitted value before storing it.
222
- *
223
  * @since 1.0.0.
224
- *
225
  * @param array $part_data Form part data.
226
- *
227
  * @return string
228
  */
229
  public function sanitize_value( $part_data = array() ) {
230
- $sanitized_value = $this->get_default_value();
231
  $part_id = $part_data['id'];
232
 
233
  if ( isset( $_REQUEST[$part_id] ) ) {
234
- $sanitized_value = sanitize_text_field( $_REQUEST[$part_id] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  }
236
 
237
  return $sanitized_value;
@@ -239,12 +347,12 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
239
 
240
  /**
241
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
242
- *
243
  * @since 1.0.0.
244
- *
245
  * @param array $part_data Form part data.
246
  * @param string $value Submitted value.
247
- *
248
  * @return string|object
249
  */
250
  public function validate_value( $part_data, $value ) {
@@ -255,11 +363,23 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
255
  $validated_value = new WP_Error( $part_id, 'missing_required_field' );
256
  }
257
 
258
- $php_format = str_replace( 'mm', 'm', $part_data['date_format'] );
259
- $php_format = str_replace( 'dd', 'd', $php_format );
260
- $php_format = str_replace( 'yy', 'Y', $php_format );
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
- if ( !date_create_from_format( $php_format, $validated_value ) ) {
263
  $validated_value = new WP_Error( $part_id, 'not_valid_date' );
264
  }
265
 
@@ -268,11 +388,11 @@ class HappyForms_Part_Date extends HappyForms_Form_Part {
268
 
269
  /**
270
  * Enqueue scripts in customizer area.
271
- *
272
  * @since 1.0.0.
273
- *
274
  * @param array List of dependencies.
275
- *
276
  * @return void
277
  */
278
  public function customize_enqueue_scripts( $deps = array() ) {
7
 
8
  public function __construct() {
9
  $this->label = __( 'Date', 'happyforms' );
10
+ $this->description = __( 'For formatted day, month, year and or time fields.', 'happyforms' );
11
  }
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
+ *
16
  * @since 1.0.0.
17
+ *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
38
+ 'tooltip_description' => array(
39
+ 'default' => 0,
40
+ 'sanitize' => 'happyforms_sanitize_checkbox'
41
+ ),
42
+ 'date_type' => array(
43
+ 'default' => 'date',
44
+ 'sanitize' => 'sanitize_text_field'
45
+ ),
46
+ 'time_format' => array(
47
+ 'default' => 12,
48
+ 'sanitize' => 'intval'
49
  ),
50
  'width' => array(
51
  'default' => 'full',
55
  'default' => '',
56
  'sanitize' => 'sanitize_text_field'
57
  ),
 
 
 
 
 
 
 
 
 
 
 
 
58
  'required' => array(
59
  'default' => 1,
60
  'sanitize' => 'happyforms_sanitize_checkbox',
64
 
65
  /**
66
  * Get template for part item in customize pane.
67
+ *
68
  * @since 1.0.0.
69
+ *
70
  * @return string
71
  */
72
  public function customize_template() {
83
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
84
  </select>
85
  </p>
86
+ <p class="label_placement-options" style="display: none">
87
+ <label>
88
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
89
+ </label>
90
+ </p>
91
  <p>
92
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
93
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
94
  </p>
95
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
 
 
 
 
 
 
 
 
 
 
 
 
 
96
  <label>
97
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
98
  </label>
99
  </p>
100
  <p>
101
+ <label for="<%= instance.id %>_date_type"><?php _e( 'Show', 'happyforms' ); ?></label>
102
+ <select id="<%= instance.id %>_date_type" name="date_type" data-bind="date_type" class="widefat">
103
+ <option value="date"<%= (instance.date_type == 'date') ? ' selected' : '' %>><?php _e( 'Date', 'happyforms' ); ?></option>
104
+ <option value="datetime"<%= (instance.date_type == 'datetime') ? ' selected' : '' %>><?php _e( 'Date &amp; Time', 'happyforms' ); ?></option>
105
+ <option value="time"<%= (instance.date_type == 'time') ? ' selected' : '' %>><?php _e( 'Time', 'happyforms' ); ?></option>
106
+ </select>
107
+ </p>
108
+ <p class="time-options"<%= (instance.date_type == 'date') ? ' style="display: none"' : '' %>>
109
+ <label for="<%= instance.id %>_time_format"><?php _e( 'Time format', 'happyforms' ); ?></label>
110
+ <select id="<%= instance.id %>_time_format" name="time_format" data-bind="time_format" class="widefat">
111
+ <option value="12"<%= (instance.time_format == '12') ? ' selected' : '' %>><?php _e( '12h', 'happyforms' ); ?></option>
112
+ <option value="24"<%= (instance.time_format == '24') ? ' selected' : '' %>><?php _e( '24h', 'happyforms' ); ?></option>
113
+ </select>
114
  </p>
115
  <p>
116
  <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
120
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
121
  </select>
122
  </p>
123
+ <p class="width-options" style="display: none">
124
+ <label>
125
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
126
+ </label>
127
+ </p>
128
  <p>
129
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
130
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
139
 
140
  /**
141
  * Get front end part template with parsed data.
142
+ *
143
  * @since 1.0.0.
144
+ *
145
  * @param array $part_data Form part data.
146
  * @param array $form_data Form (post) data.
147
+ *
148
  * @return string Markup for the form part.
149
  */
150
  public function frontend_template( $part_data = array(), $form_data = array() ) {
151
  $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
152
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
153
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
 
 
 
 
 
 
154
 
155
+ $classes = array('happyforms-part--date', 'happyforms-part-date');
156
 
157
  if ( $part_data['width'] ) {
158
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
159
  }
160
 
161
  if ( $part_data['label_placement'] ) {
162
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
163
  }
164
 
165
  if ( !empty( $part_data['css_class'] ) ) {
166
+ $classes[] = $part_data['css_class'];
167
  }
168
 
169
+ $classes[] = 'happyforms-part-date--' . $part_data['date_type'];
170
 
171
+ $classes = implode( ' ', $classes );
 
 
 
 
172
  ?>
173
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
174
  <div class="happyforms-part__wrap">
175
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
176
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
177
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
178
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
179
  <?php endif; ?>
 
180
  </label>
181
+ <div class="happyforms-part__el">
182
+ <?php if ( is_customize_preview() || $part_data['date_type'] === 'datetime' || $part_data['date_type'] === 'date' ) : ?>
183
+ <div class="happyforms-part__select-wrap happyforms-part-date__date-input">
184
+ <select name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>[month]"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
185
+ <option value=""><?php _e( 'Month', 'happyforms' ); ?></option>
186
+ <?php for ( $i = 1; $i <= 12; $i++ ) : ?>
187
+ <option value="<?php echo $i; ?>"><?php echo date( 'F', mktime( 0, 0, 0, $i) ); ?></option>
188
+ <?php endfor; ?>
189
+ </select>
190
+ </div>
191
+ <div class="happyforms-part__select-wrap happyforms-part-date__date-input">
192
+ <select name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>[day]"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
193
+ <option value=""><?php _e( 'Day', 'happyforms' ); ?></option>
194
+ <?php for ( $i = 1; $i <= 31; $i++ ) : ?>
195
+ <option value="<?php echo $i; ?>"><?php echo $i; ?></option>
196
+ <?php endfor; ?>
197
+ </select>
198
+ </div>
199
+ <div class="happyforms-part__select-wrap happyforms-part-date__date-input">
200
+ <select name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>[year]"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
201
+ <option value=""><?php _e( 'Year', 'happyforms' ); ?></option>
202
+ <?php
203
+ $year_cutoff = 1910;
204
+ $year_current = date('Y');
205
+
206
+ for ( $i = $year_current; $i >= $year_cutoff; $i-- ) :
207
+ ?>
208
+ <option value="<?php echo $i; ?>"><?php echo $i; ?></option>
209
+ <?php
210
+ endfor;
211
+ ?>
212
+ </select>
213
+ </div>
214
+ <?php endif; ?>
215
+ <?php if ( is_customize_preview() || $part_data['date_type'] === 'datetime' || $part_data['date_type'] === 'time' ) : ?>
216
+ <div class="happyforms-part__select-wrap happyforms-part-date__time-input">
217
+ <select name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>[hour]"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
218
+ <option value=""><?php _e( 'Hour', 'happyforms' ); ?></option>
219
+ <?php
220
+ if ( 24 === $part_data['time_format'] ) :
221
+ $i_min = 0;
222
+ $i_max = 24;
223
+ else:
224
+ $i_min = 1;
225
+ $i_max = 13;
226
+ endif;
227
+
228
+ if ( !is_customize_preview() ) :
229
+ for ( $i = $i_min; $i < $i_max; $i++ ) :
230
+ ?>
231
+ <option value="<?php echo $i; ?>"><?php echo $i; ?></option>
232
+ <?php
233
+ endfor;
234
+ else:
235
+ for ( $i = 0; $i < 24; $i++ ) :
236
+ ?>
237
+ <option value="<?php echo $i; ?>" class="<?php echo ($i > 12) ? 'format-24' : ''; ?>" style="<?php echo ($i > 12 && $part_data['time_format'] == 12) ? 'display: none' : ''; ?>"><?php echo $i; ?></option>
238
+ <?php
239
+ endfor;
240
+ endif;
241
+ ?>
242
+ </select>
243
+ </div>
244
+ <div class="happyforms-part__select-wrap happyforms-part-date__time-input">
245
+ <select name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>[minute]"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
246
+ <option value=""><?php _e( 'Minute', 'happyforms' ); ?></option>
247
+ <?php
248
+ for ( $i = 0; $i < 60; $i++ ) :
249
+ ?>
250
+ <option value="<?php echo $i; ?>"><?php echo $i; ?></option>
251
+ <?php
252
+ endfor;
253
+ ?>
254
+ </select>
255
+ </div>
256
+ <?php if ( is_customize_preview() || 12 == $part_data['time_format'] ) : ?>
257
+ <div class="happyforms-part__select-wrap happyforms-part-date__time-input happyforms-part-date__time-input--period">
258
+ <select name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>[period]"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
259
+ <option value=""><?php _e( 'Period', 'happyforms' ); ?></option>
260
+ <option value="AM"><?php _e( 'AM', 'happyforms' ); ?></option>
261
+ <option value="PM"><?php _e( 'PM', 'happyforms' ); ?></option>
262
+ </select>
263
+ </div>
264
+ <?php endif; ?>
265
+ <?php endif; ?>
266
+ </div>
267
+ <?php happyforms_print_part_description( $part_data ); ?>
268
+ <?php
269
+ if ( $form_data ) :
270
+ happyforms_message_notices( $form_data, $part_data['id'] );
271
+ endif;
272
+ ?>
273
  </div>
274
  </div>
275
  <?php
277
 
278
  /**
279
  * Get all possible messages definitions.
280
+ *
281
  * @since 1.0.0.
282
+ *
283
  * @return array Associative array, specifying message type and copy.
284
  */
285
  public function get_message_definitions() {
297
 
298
  /**
299
  * Sanitize submitted value before storing it.
300
+ *
301
  * @since 1.0.0.
302
+ *
303
  * @param array $part_data Form part data.
304
+ *
305
  * @return string
306
  */
307
  public function sanitize_value( $part_data = array() ) {
308
+ $original_value = $this->get_default_value();
309
  $part_id = $part_data['id'];
310
 
311
  if ( isset( $_REQUEST[$part_id] ) ) {
312
+ $data = $_REQUEST[$part_id];
313
+
314
+ if ( is_array( $data ) ) {
315
+ foreach( $data as $key => $date_part ) {
316
+ if ( $key === 'period' ) {
317
+ $original_value[$key] = sanitize_text_field( $date_part );
318
+ } else {
319
+ $original_value[$key] = intval( $date_part );
320
+ }
321
+ }
322
+ }
323
+
324
+ if ( $part_data['date_type'] === 'date' ) {
325
+ $sanitized_value = $original_value['year'] . '-' . sprintf( '%02d', $original_value['month'] ) . '-' . sprintf( '%02d', $original_value['day'] );
326
+ }
327
+
328
+ if ( $part_data['date_type'] === 'datetime' ) {
329
+ $sanitized_value = $original_value['year'] . '-' . sprintf( '%02d', $original_value['month'] ) . '-' . sprintf( '%02d', $original_value['day'] ) . ' ' . sprintf( '%02d', $original_value['hour'] ) . ':' . sprintf( '%02d', $original_value['minute'] );
330
+
331
+ if ( 12 == $part_data['time_format'] ) {
332
+ $sanitized_value .= ' ' . $original_value['period'];
333
+ }
334
+ }
335
+
336
+ if ( $part_data['date_type'] === 'time' ) {
337
+ $sanitized_value = sprintf( '%02d', $original_value['hour'] ) . ':' . sprintf( '%02d', $original_value['minute'] );
338
+
339
+ if ( 12 == $part_data['time_format'] ) {
340
+ $sanitized_value .= ' ' . $original_value['period'];
341
+ }
342
+ }
343
  }
344
 
345
  return $sanitized_value;
347
 
348
  /**
349
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
350
+ *
351
  * @since 1.0.0.
352
+ *
353
  * @param array $part_data Form part data.
354
  * @param string $value Submitted value.
355
+ *
356
  * @return string|object
357
  */
358
  public function validate_value( $part_data, $value ) {
363
  $validated_value = new WP_Error( $part_id, 'missing_required_field' );
364
  }
365
 
366
+ if ( $part_data['date_type'] === 'date' ) {
367
+ $date_format = 'Y-m-d';
368
+ } elseif ( $part_data['date_type'] === 'datetime' ) {
369
+ if ( 12 == $part_data['time_format'] ) {
370
+ $date_format = 'Y-m-d h:i A';
371
+ } else {
372
+ $date_format = 'Y-m-d H:i';
373
+ }
374
+ } else {
375
+ if ( 12 == $part_data['time_format'] ) {
376
+ $date_format = 'h:i A';
377
+ } else {
378
+ $date_format = 'H:i';
379
+ }
380
+ }
381
 
382
+ if ( !date_create_from_format( $date_format, $validated_value ) ) {
383
  $validated_value = new WP_Error( $part_id, 'not_valid_date' );
384
  }
385
 
388
 
389
  /**
390
  * Enqueue scripts in customizer area.
391
+ *
392
  * @since 1.0.0.
393
+ *
394
  * @param array List of dependencies.
395
+ *
396
  * @return void
397
  */
398
  public function customize_enqueue_scripts( $deps = array() ) {
inc/classes/parts/class-part-email.php CHANGED
@@ -13,9 +13,9 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
13
 
14
  /**
15
  * Get all part meta fields defaults.
16
- *
17
  * @since 1.0.0.
18
- *
19
  * @return array
20
  */
21
  public function get_customize_fields() {
@@ -36,6 +36,10 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
36
  'default' => '',
37
  'sanitize' => 'sanitize_text_field'
38
  ),
 
 
 
 
39
  'confirmation_field' => array(
40
  'default' => 0,
41
  'sanitize' => 'intval'
@@ -69,9 +73,9 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
69
 
70
  /**
71
  * Get template for part item in customize pane.
72
- *
73
  * @since 1.0.0.
74
- *
75
  * @return string
76
  */
77
  public function customize_template() {
@@ -88,10 +92,20 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
88
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
89
  </select>
90
  </p>
 
 
 
 
 
91
  <p>
92
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
93
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
94
  </p>
 
 
 
 
 
95
  <p>
96
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
97
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
@@ -104,6 +118,11 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
104
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
105
  </select>
106
  </p>
 
 
 
 
 
107
  <p>
108
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
109
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -127,12 +146,12 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
127
 
128
  /**
129
  * Get front end part template with parsed data.
130
- *
131
  * @since 1.0.0.
132
- *
133
  * @param array $part_data Form part data.
134
  * @param array $form_data Form (post) data.
135
- *
136
  * @return string Markup for the form part.
137
  */
138
  public function frontend_template( $part_data = array(), $form_data = array() ) {
@@ -140,35 +159,47 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
140
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
141
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
142
 
143
- $classes = ' ';
144
 
145
  if ( $part_data['width'] ) {
146
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
147
  }
148
 
149
  if ( $part_data['label_placement'] ) {
150
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
151
  }
152
 
153
  if ( !empty( $part_data['css_class'] ) ) {
154
- $classes .= $part_data['css_class'];
 
 
 
 
 
 
 
 
 
 
155
  }
 
 
156
  ?>
157
- <div class="happyforms-part happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
158
- <?php
159
- if ( $form_data ) :
160
- happyforms_message_notices( $form_data, $part_data['id'] );
161
- endif;
162
- ?>
163
  <div class="happyforms-part__wrap">
164
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
165
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
166
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
167
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
168
  <?php endif; ?>
169
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
170
  </label>
171
- <input type="email" id="<?php echo esc_attr( $html_id ); ?>" name="<?php echo esc_attr( $part_data['id'] ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" class="happyforms-part__el happyforms-part__el--text-input" <?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?> />
 
 
 
 
 
 
172
  </div>
173
  <?php if ( 1 === $part_data['confirmation_field'] ) : ?>
174
  <div class="happyforms-part__wrap happyforms-part__wrap--confirmation" id="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>">
@@ -192,9 +223,9 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
192
 
193
  /**
194
  * Get confirmation field Backbone template for preview purposes.
195
- *
196
  * @since 1.0.0.
197
- *
198
  * @return string Backbone template.
199
  */
200
  public function preview_confirmation_template() {
@@ -211,9 +242,9 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
211
 
212
  /**
213
  * Get all possible messages definitions.
214
- *
215
  * @since 1.0.0.
216
- *
217
  * @return array Associative array, specifying message type and copy.
218
  */
219
  public function get_message_definitions() {
@@ -243,11 +274,11 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
243
 
244
  /**
245
  * Sanitize submitted value before storing it.
246
- *
247
  * @since 1.0.0.
248
- *
249
  * @param array $part_data Form part data.
250
- *
251
  * @return string
252
  */
253
  public function sanitize_value( $part_data = array() ) {
@@ -270,47 +301,45 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
270
 
271
  /**
272
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
273
- *
274
  * @since 1.0.0.
275
- *
276
  * @param array $part_data Form part data.
277
  * @param string $value Submitted value.
278
- *
279
  * @return string|object
280
  */
281
  public function validate_value( $part_data, $value ) {
282
  $part_id = $part_data['id'];
283
  $validated_value = $value;
 
284
 
285
  if ( is_array( $validated_value ) ) {
 
286
  $validated_confirmation_value = $validated_value[1];
287
  $validated_value = $validated_value[0];
288
- } else {
289
- $validated_confirmation_value = $validated_value;
290
  }
291
 
292
  if ( 1 === $part_data['required'] && empty( $validated_value ) ) {
293
  $validated_value = new WP_Error( $part_id, 'missing_required_field' );
294
  }
295
 
296
- if ( !filter_var( $validated_value, FILTER_VALIDATE_EMAIL ) ) {
297
  $validated_value = new WP_error( $part_id, 'not_valid_email' );
298
  }
299
 
300
- if ( 1 === $part_data['required'] && empty( $validated_confirmation_value ) ) {
301
- $validated_value = new WP_Error( $part_id, 'missing_required_confirmation_field' );
302
- }
 
303
 
304
- if ( !filter_var( $validated_confirmation_value, FILTER_VALIDATE_EMAIL ) ) {
305
- $validated_value = new WP_error( $part_id, 'not_valid_confirmation_email' );
306
- }
307
 
308
- if ( $validated_value !== $validated_confirmation_value ) {
309
- $validated_value = new WP_Error( $part_id, 'emails_not_matching' );
310
- }
311
-
312
- if ( empty( $validated_value ) ) {
313
- $validated_value = new WP_error( $part_id, 'not_valid_email' );
314
  }
315
 
316
  return $validated_value;
@@ -318,11 +347,11 @@ class HappyForms_Part_Email extends HappyForms_Form_Part {
318
 
319
  /**
320
  * Enqueue scripts in customizer area.
321
- *
322
  * @since 1.0.0.
323
- *
324
  * @param array List of dependencies.
325
- *
326
  * @return void
327
  */
328
  public function customize_enqueue_scripts( $deps = array() ) {
13
 
14
  /**
15
  * Get all part meta fields defaults.
16
+ *
17
  * @since 1.0.0.
18
+ *
19
  * @return array
20
  */
21
  public function get_customize_fields() {
36
  'default' => '',
37
  'sanitize' => 'sanitize_text_field'
38
  ),
39
+ 'tooltip_description' => array(
40
+ 'default' => 0,
41
+ 'sanitize' => 'happyforms_sanitize_checkbox'
42
+ ),
43
  'confirmation_field' => array(
44
  'default' => 0,
45
  'sanitize' => 'intval'
73
 
74
  /**
75
  * Get template for part item in customize pane.
76
+ *
77
  * @since 1.0.0.
78
+ *
79
  * @return string
80
  */
81
  public function customize_template() {
92
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
93
  </select>
94
  </p>
95
+ <p class="label_placement-options" style="display: none">
96
+ <label>
97
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
98
+ </label>
99
+ </p>
100
  <p>
101
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
102
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
103
  </p>
104
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
105
+ <label>
106
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
107
+ </label>
108
+ </p>
109
  <p>
110
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
111
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
118
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
119
  </select>
120
  </p>
121
+ <p class="width-options" style="display: none">
122
+ <label>
123
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
124
+ </label>
125
+ </p>
126
  <p>
127
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
128
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
146
 
147
  /**
148
  * Get front end part template with parsed data.
149
+ *
150
  * @since 1.0.0.
151
+ *
152
  * @param array $part_data Form part data.
153
  * @param array $form_data Form (post) data.
154
+ *
155
  * @return string Markup for the form part.
156
  */
157
  public function frontend_template( $part_data = array(), $form_data = array() ) {
159
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
160
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
161
 
162
+ $classes = array('happyforms-part--email');
163
 
164
  if ( $part_data['width'] ) {
165
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
166
  }
167
 
168
  if ( $part_data['label_placement'] ) {
169
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
170
  }
171
 
172
  if ( !empty( $part_data['css_class'] ) ) {
173
+ $classes[] = $part_data['css_class'];
174
+ }
175
+
176
+ $message_notices = '';
177
+
178
+ if ( $form_data ) {
179
+ $message_notices = happyforms_get_message_notices()->get_messages( $form_data, $part_data['id'] );
180
+
181
+ if ( !empty( $message_notices ) ) {
182
+ $classes[] = ' happyforms-part--error';
183
+ }
184
  }
185
+
186
+ $classes = implode( ' ', $classes );
187
  ?>
188
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
189
  <div class="happyforms-part__wrap">
190
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
191
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
192
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
193
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
194
  <?php endif; ?>
 
195
  </label>
196
+ <input type="email" id="<?php echo esc_attr( $html_id ); ?>" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" class="happyforms-part__el happyforms-part__el--text-input" <?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?> />
197
+ <?php happyforms_print_part_description( $part_data ); ?>
198
+ <?php
199
+ if ( $form_data ) :
200
+ happyforms_message_notices( $form_data, $part_data['id'] );
201
+ endif;
202
+ ?>
203
  </div>
204
  <?php if ( 1 === $part_data['confirmation_field'] ) : ?>
205
  <div class="happyforms-part__wrap happyforms-part__wrap--confirmation" id="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>">
223
 
224
  /**
225
  * Get confirmation field Backbone template for preview purposes.
226
+ *
227
  * @since 1.0.0.
228
+ *
229
  * @return string Backbone template.
230
  */
231
  public function preview_confirmation_template() {
242
 
243
  /**
244
  * Get all possible messages definitions.
245
+ *
246
  * @since 1.0.0.
247
+ *
248
  * @return array Associative array, specifying message type and copy.
249
  */
250
  public function get_message_definitions() {
274
 
275
  /**
276
  * Sanitize submitted value before storing it.
277
+ *
278
  * @since 1.0.0.
279
+ *
280
  * @param array $part_data Form part data.
281
+ *
282
  * @return string
283
  */
284
  public function sanitize_value( $part_data = array() ) {
301
 
302
  /**
303
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
304
+ *
305
  * @since 1.0.0.
306
+ *
307
  * @param array $part_data Form part data.
308
  * @param string $value Submitted value.
309
+ *
310
  * @return string|object
311
  */
312
  public function validate_value( $part_data, $value ) {
313
  $part_id = $part_data['id'];
314
  $validated_value = $value;
315
+ $has_confirmation_value = false;
316
 
317
  if ( is_array( $validated_value ) ) {
318
+ $has_confirmation_value = true;
319
  $validated_confirmation_value = $validated_value[1];
320
  $validated_value = $validated_value[0];
 
 
321
  }
322
 
323
  if ( 1 === $part_data['required'] && empty( $validated_value ) ) {
324
  $validated_value = new WP_Error( $part_id, 'missing_required_field' );
325
  }
326
 
327
+ if ( empty( $validated_value ) || !filter_var( $validated_value, FILTER_VALIDATE_EMAIL ) ) {
328
  $validated_value = new WP_error( $part_id, 'not_valid_email' );
329
  }
330
 
331
+ if ( true === $has_confirmation_value ) {
332
+ if ( 1 === $part_data['required'] && empty( $validated_confirmation_value ) ) {
333
+ $validated_value = new WP_Error( $part_id, 'missing_required_confirmation_field' );
334
+ }
335
 
336
+ if ( !filter_var( $validated_confirmation_value, FILTER_VALIDATE_EMAIL ) ) {
337
+ $validated_value = new WP_error( $part_id, 'not_valid_confirmation_email' );
338
+ }
339
 
340
+ if ( $validated_value !== $validated_confirmation_value ) {
341
+ $validated_value = new WP_Error( $part_id, 'emails_not_matching' );
342
+ }
 
 
 
343
  }
344
 
345
  return $validated_value;
347
 
348
  /**
349
  * Enqueue scripts in customizer area.
350
+ *
351
  * @since 1.0.0.
352
+ *
353
  * @param array List of dependencies.
354
+ *
355
  * @return void
356
  */
357
  public function customize_enqueue_scripts( $deps = array() ) {
inc/classes/parts/class-part-legal.php ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class HappyForms_Part_Legal extends HappyForms_Form_Part {
4
+
5
+ public $type = 'legal';
6
+ public $template_id = 'happyforms-legal-template';
7
+
8
+ public function __construct() {
9
+ $this->label = __( 'Legal', 'happyforms' );
10
+ $this->description = __( 'For requiring fine print before accepting submission.', 'happyforms' );
11
+ }
12
+
13
+ /**
14
+ * Get all part meta fields defaults.
15
+ *
16
+ * @since 1.0.0.
17
+ *
18
+ * @return array
19
+ */
20
+ public function get_customize_fields() {
21
+ return array(
22
+ 'type' => array(
23
+ 'default' => $this->type,
24
+ 'sanitize' => 'sanitize_text_field',
25
+ ),
26
+ 'legal_text' => array(
27
+ 'default' => __( 'I accept terms and conditions.', 'happyforms' ),
28
+ 'sanitize' => 'sanitize_text_field'
29
+ ),
30
+ 'width' => array(
31
+ 'default' => 'full',
32
+ 'sanitize' => 'sanitize_key'
33
+ ),
34
+ 'css_class' => array(
35
+ 'default' => '',
36
+ 'sanitize' => 'sanitize_text_field'
37
+ ),
38
+ 'required' => array(
39
+ 'default' => 1,
40
+ 'sanitize' => 'happyforms_sanitize_checkbox',
41
+ ),
42
+ );
43
+ }
44
+
45
+ /**
46
+ * Get template for part item in customize pane.
47
+ *
48
+ * @since 1.0.0.
49
+ *
50
+ * @return string
51
+ */
52
+ public function customize_template() {
53
+ ?>
54
+ <p>
55
+ <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
56
+ <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
57
+ <option value="full"<%= (instance.width == 'full') ? ' selected' : '' %>><?php _e( 'Full', 'happyforms' ); ?></option>
58
+ <option value="half"<%= (instance.width == 'half') ? ' selected' : '' %>><?php _e( 'Half', 'happyforms' ); ?></option>
59
+ <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
60
+ </select>
61
+ </p>
62
+ <p>
63
+ <label for="<%= instance.id %>_legal_text"><?php _e( 'Legal text', 'happyforms' ); ?></label>
64
+ <textarea id="<%= instance.id %>_legal_text" rows="5" name="legal_text" data-bind="legal_text" class="widefat"><%= instance.legal_text %></textarea>
65
+ </p>
66
+ <p>
67
+ <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
68
+ <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
69
+ </p>
70
+ <?php
71
+ }
72
+
73
+ /**
74
+ * Get front end part template with parsed data.
75
+ *
76
+ * @since 1.0.0.
77
+ *
78
+ * @param array $part_data Form part data.
79
+ * @param array $form_data Form (post) data.
80
+ *
81
+ * @return string Markup for the form part.
82
+ */
83
+ public function frontend_template( $part_data = array(), $form_data = array() ) {
84
+ $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
85
+ $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
86
+ $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
87
+
88
+ $classes = array('happyforms-part--legal');
89
+
90
+ if ( $part_data['width'] ) {
91
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
92
+ }
93
+
94
+ if ( !empty( $part_data['css_class'] ) ) {
95
+ $classes[] = $part_data['css_class'] . ' ';
96
+ }
97
+
98
+ $classes = implode( ' ', $classes );
99
+ ?>
100
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
101
+ <div class="happyforms-part__wrap">
102
+ <div class="happyforms-part__el">
103
+ <label>
104
+ <input id="<?php echo esc_attr( $html_id ); ?>" type="checkbox" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" value="yes" required aria-required="true" /> <span><?php echo $part_data['legal_text']; ?></span>
105
+ </label>
106
+ </div>
107
+ </div>
108
+ <?php
109
+ if ( $form_data ) :
110
+ happyforms_message_notices( $form_data, $part_data['id'] );
111
+ endif;
112
+ ?>
113
+ </div>
114
+ <?php
115
+ }
116
+
117
+ /**
118
+ * Get all possible messages definitions.
119
+ *
120
+ * @since 1.0.0.
121
+ *
122
+ * @return array Associative array, specifying message type and copy.
123
+ */
124
+ public function get_message_definitions() {
125
+ return array(
126
+ 'missing_required_field' => array(
127
+ 'type' => 'error',
128
+ 'message' => __( 'This field is required.', 'happyforms' ),
129
+ ),
130
+ 'not_valid_value' => array(
131
+ 'type' => 'error',
132
+ 'message' => __( 'Please accept terms before proceeding.', 'happyforms' ),
133
+ ),
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Sanitize submitted value before storing it.
139
+ *
140
+ * @since 1.0.0.
141
+ *
142
+ * @param array $part_data Form part data.
143
+ *
144
+ * @return string
145
+ */
146
+ public function sanitize_value( $part_data = array() ) {
147
+ $sanitized_value = $this->get_default_value();
148
+ $part_id = $part_data['id'];
149
+
150
+ if ( isset( $_REQUEST[$part_id] ) ) {
151
+ $sanitized_value = sanitize_text_field( $_REQUEST[$part_id] );
152
+ }
153
+
154
+ return $sanitized_value;
155
+ }
156
+
157
+ /**
158
+ * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
159
+ *
160
+ * @since 1.0.0.
161
+ *
162
+ * @param array $part_data Form part data.
163
+ * @param string $value Submitted value.
164
+ *
165
+ * @return string|object
166
+ */
167
+ public function validate_value( $part_data, $value ) {
168
+ $part_id = $part_data['id'];
169
+ $validated_value = $value;
170
+
171
+ if ( empty( $validated_value ) ) {
172
+ $validated_value = new WP_Error( $part_id, 'missing_required_field' );
173
+ }
174
+
175
+ if ( $validated_value !== 'yes' ) {
176
+ $validated_value = new WP_Error( $part_id, 'not_valid_value' );
177
+ }
178
+
179
+ return $validated_value;
180
+ }
181
+
182
+ /**
183
+ * Enqueue scripts in customizer area.
184
+ *
185
+ * @since 1.0.0.
186
+ *
187
+ * @param array List of dependencies.
188
+ *
189
+ * @return void
190
+ */
191
+ public function customize_enqueue_scripts( $deps = array() ) {
192
+ wp_enqueue_script(
193
+ 'part-legal',
194
+ happyforms_get_plugin_url() . 'assets/js/parts/part-legal.js',
195
+ $deps,
196
+ false,
197
+ true
198
+ );
199
+ }
200
+
201
+ }
inc/classes/parts/class-part-multi-line-text.php CHANGED
@@ -12,9 +12,9 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
- *
16
  * @since 1.0.0.
17
- *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
@@ -35,6 +35,10 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
 
 
 
 
38
  'placeholder' => array(
39
  'default' => '',
40
  'sanitize' => 'sanitize_text_field',
@@ -56,9 +60,9 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
56
 
57
  /**
58
  * Get template for part item in customize pane.
59
- *
60
  * @since 1.0.0.
61
- *
62
  * @return string
63
  */
64
  public function customize_template() {
@@ -75,10 +79,20 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
75
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
76
  </select>
77
  </p>
 
 
 
 
 
78
  <p>
79
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
80
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
81
  </p>
 
 
 
 
 
82
  <p>
83
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
84
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
@@ -91,6 +105,11 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
91
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
92
  </select>
93
  </p>
 
 
 
 
 
94
  <p>
95
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
96
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -105,12 +124,12 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
105
 
106
  /**
107
  * Get front end part template with parsed data.
108
- *
109
  * @since 1.0.0.
110
- *
111
  * @param array $part_data Form part data.
112
  * @param array $form_data Form (post) data.
113
- *
114
  * @return string Markup for the form part.
115
  */
116
  public function frontend_template( $part_data = array(), $form_data = array() ) {
@@ -118,35 +137,37 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
118
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
119
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
120
 
121
- $classes = ' ';
122
 
123
  if ( $part_data['width'] ) {
124
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
125
  }
126
 
127
  if ( $part_data['label_placement'] ) {
128
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
129
  }
130
 
131
  if ( !empty( $part_data['css_class'] ) ) {
132
- $classes .= $part_data['css_class'];
133
  }
 
 
134
  ?>
135
- <div class="happyforms-part happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
136
- <?php
137
- if ( $form_data ) :
138
- happyforms_message_notices( $form_data, $part_data['id'] );
139
- endif;
140
- ?>
141
  <div class="happyforms-part__wrap">
142
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
143
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
144
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
145
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
146
  <?php endif; ?>
147
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
148
  </label>
149
- <textarea id="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__el happyforms-part__el--text-input" name="<?php echo esc_attr( $part_data['id'] ); ?>" rows="5" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>></textarea>
 
 
 
 
 
 
150
  </div>
151
  </div>
152
  <?php
@@ -154,9 +175,9 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
154
 
155
  /**
156
  * Get all possible messages definitions.
157
- *
158
  * @since 1.0.0.
159
- *
160
  * @return array Associative array, specifying message type and copy.
161
  */
162
  public function get_message_definitions() {
@@ -170,11 +191,11 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
170
 
171
  /**
172
  * Enqueue scripts in customizer area.
173
- *
174
  * @since 1.0.0.
175
- *
176
  * @param array List of dependencies.
177
- *
178
  * @return void
179
  */
180
  public function customize_enqueue_scripts( $deps = array() ) {
@@ -189,11 +210,11 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
189
 
190
  /**
191
  * Sanitize submitted value before storing it.
192
- *
193
  * @since 1.0.0.
194
- *
195
  * @param array $part_data Form part data.
196
- *
197
  * @return string
198
  */
199
  public function sanitize_value( $part_data = array() ) {
@@ -209,12 +230,12 @@ class HappyForms_Part_MultiLineText extends HappyForms_Form_Part {
209
 
210
  /**
211
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
212
- *
213
  * @since 1.0.0.
214
- *
215
  * @param array $part_data Form part data.
216
  * @param string $value Submitted value.
217
- *
218
  * @return string|object
219
  */
220
  public function validate_value( $part_data, $value ) {
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
+ *
16
  * @since 1.0.0.
17
+ *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
38
+ 'tooltip_description' => array(
39
+ 'default' => 0,
40
+ 'sanitize' => 'happyforms_sanitize_checkbox'
41
+ ),
42
  'placeholder' => array(
43
  'default' => '',
44
  'sanitize' => 'sanitize_text_field',
60
 
61
  /**
62
  * Get template for part item in customize pane.
63
+ *
64
  * @since 1.0.0.
65
+ *
66
  * @return string
67
  */
68
  public function customize_template() {
79
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
80
  </select>
81
  </p>
82
+ <p class="label_placement-options" style="display: none">
83
+ <label>
84
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
85
+ </label>
86
+ </p>
87
  <p>
88
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
89
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
90
  </p>
91
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
92
+ <label>
93
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
94
+ </label>
95
+ </p>
96
  <p>
97
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
98
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
105
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
106
  </select>
107
  </p>
108
+ <p class="width-options" style="display: none">
109
+ <label>
110
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
111
+ </label>
112
+ </p>
113
  <p>
114
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
115
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
124
 
125
  /**
126
  * Get front end part template with parsed data.
127
+ *
128
  * @since 1.0.0.
129
+ *
130
  * @param array $part_data Form part data.
131
  * @param array $form_data Form (post) data.
132
+ *
133
  * @return string Markup for the form part.
134
  */
135
  public function frontend_template( $part_data = array(), $form_data = array() ) {
137
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
138
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
139
 
140
+ $classes = array('happyforms-part--multi-line-text');
141
 
142
  if ( $part_data['width'] ) {
143
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
144
  }
145
 
146
  if ( $part_data['label_placement'] ) {
147
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
148
  }
149
 
150
  if ( !empty( $part_data['css_class'] ) ) {
151
+ $classes[] = $part_data['css_class'];
152
  }
153
+
154
+ $classes = implode( ' ', $classes );
155
  ?>
156
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
157
  <div class="happyforms-part__wrap">
158
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
159
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
160
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
161
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
162
  <?php endif; ?>
 
163
  </label>
164
+ <textarea id="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__el happyforms-part__el--text-input" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" rows="5" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>></textarea>
165
+ <?php happyforms_print_part_description( $part_data ); ?>
166
+ <?php
167
+ if ( $form_data ) :
168
+ happyforms_message_notices( $form_data, $part_data['id'] );
169
+ endif;
170
+ ?>
171
  </div>
172
  </div>
173
  <?php
175
 
176
  /**
177
  * Get all possible messages definitions.
178
+ *
179
  * @since 1.0.0.
180
+ *
181
  * @return array Associative array, specifying message type and copy.
182
  */
183
  public function get_message_definitions() {
191
 
192
  /**
193
  * Enqueue scripts in customizer area.
194
+ *
195
  * @since 1.0.0.
196
+ *
197
  * @param array List of dependencies.
198
+ *
199
  * @return void
200
  */
201
  public function customize_enqueue_scripts( $deps = array() ) {
210
 
211
  /**
212
  * Sanitize submitted value before storing it.
213
+ *
214
  * @since 1.0.0.
215
+ *
216
  * @param array $part_data Form part data.
217
+ *
218
  * @return string
219
  */
220
  public function sanitize_value( $part_data = array() ) {
230
 
231
  /**
232
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
233
+ *
234
  * @since 1.0.0.
235
+ *
236
  * @param array $part_data Form part data.
237
  * @param string $value Submitted value.
238
+ *
239
  * @return string|object
240
  */
241
  public function validate_value( $part_data, $value ) {
inc/classes/parts/class-part-number.php CHANGED
@@ -8,14 +8,14 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
8
 
9
  public function __construct() {
10
  $this->label = __( 'Number', 'happyforms' );
11
- $this->description = __( 'For numeric fields. Includes phone formatting.', 'happyforms' );
12
  }
13
 
14
  /**
15
  * Get all part meta fields defaults.
16
- *
17
  * @since 1.0.0.
18
- *
19
  * @return array
20
  */
21
  public function get_customize_fields() {
@@ -36,6 +36,10 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
36
  'default' => '',
37
  'sanitize' => 'sanitize_text_field'
38
  ),
 
 
 
 
39
  'placeholder' => array(
40
  'default' => '',
41
  'sanitize' => 'sanitize_text_field',
@@ -48,14 +52,18 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
48
  'default' => '',
49
  'sanitize' => 'sanitize_text_field'
50
  ),
 
 
 
 
 
 
 
 
51
  'masked' => array(
52
  'default' => 0,
53
  'sanitize' => 'intval'
54
  ),
55
- 'mask_type' => array(
56
- 'default' => 'numeric',
57
- 'sanitize' => 'sanitize_text_field'
58
- ),
59
  'mask_numeric_thousands_delimiter' => array(
60
  'default' => ',',
61
  'sanitize' => 'sanitize_text_field'
@@ -68,10 +76,6 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
68
  'default' => '',
69
  'sanitize' => 'sanitize_text_field'
70
  ),
71
- 'mask_phone_country' => array(
72
- 'default' => '',
73
- 'sanitize' => 'intval'
74
- ),
75
  'confirmation_field' => array(
76
  'default' => 0,
77
  'sanitize' => 'intval'
@@ -93,9 +97,9 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
93
 
94
  /**
95
  * Get template for part item in customize pane.
96
- *
97
  * @since 1.0.0.
98
- *
99
  * @return string
100
  */
101
  public function customize_template() {
@@ -112,27 +116,40 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
112
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
113
  </select>
114
  </p>
 
 
 
 
 
115
  <p>
116
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
117
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
118
  </p>
 
 
 
 
 
119
  <p>
120
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
121
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
122
  </p>
 
 
 
 
 
 
 
 
 
 
123
  <p>
124
  <label>
125
  <input type="checkbox" name="masked" class="checkbox" value="1" <% if ( instance.masked ) { %>checked="checked"<% } %> data-bind="masked" /> <?php _e( 'Mask this input', 'happyforms' ); ?>
126
  </label>
127
  </p>
128
- <p class="mask-wrapper" style="display: <%= (instance.masked == 1) ? 'block' : 'none' %>">
129
- <label for="<%= instance.id %>_mask_type"><?php _e( 'Field type', 'happyforms' ); ?></label>
130
- <select id="<%= instance.id %>_mask_type" name="mask_type" data-bind="mask_type" class="widefat">
131
- <option value="numeric"<%= (instance.mask_type == 'numeric') ? ' selected' : '' %>><?php _e( 'Numeric', 'happyforms' ); ?></option>
132
- <option value="phone"<%= (instance.mask_type == 'phone') ? ' selected' : '' %>><?php _e( 'Phone', 'happyforms' ); ?></option>
133
- </select>
134
- </p>
135
- <div class="number-options number-options--numeric" style="display: <%= (instance.mask_type == 'numeric') ? 'block' : 'none' %>">
136
  <p>
137
  <label for="<%= instance.id %>_mask_numeric_thousands_delimiter"><?php _e( 'Thousands delimiter', 'happyforms' ); ?></label>
138
  <input type="text" id="<%= instance.id %>_mask_numeric_thousands_delimiter" class="widefat title" value="<%= instance.mask_numeric_thousands_delimiter %>" data-bind="mask_numeric_thousands_delimiter" />
@@ -146,21 +163,6 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
146
  <input type="text" id="<%= instance.id %>_mask_numeric_prefix" class="widefat title" value="<%= instance.mask_numeric_prefix %>" data-bind="mask_numeric_prefix" />
147
  </p>
148
  </div>
149
- <div class="number-options number-options--phone" style="display: <%= (instance.mask_type == 'phone') ? 'block' : 'none' %>">
150
- <p>
151
- <label for="<%= instance.id %>_mask_phone_country"><?php _e( 'Pre-format phone number region', 'happyforms' ); ?></label>
152
- <select id="<%= instance.id %>_mask_phone_country" class="widefat title" data-bind="mask_phone_country">
153
- <option value="">- <?php _e( 'Select', 'happyforms' ); ?> -</option>
154
- <?php
155
- $phone_countries = $this->get_phone_countries_array();
156
-
157
- foreach ( $phone_countries as $country_code => $country ) {
158
- echo '<option value="'. $country['code'] .'"<% if (instance.mask_phone_country == "'. $country['code'] .'") { %> selected<% } %>>'. ucwords( strtolower( $country['name'] ) ) .'</option>';
159
- }
160
- ?>
161
- </select>
162
- </p>
163
- </div>
164
  <p>
165
  <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
166
  <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
@@ -169,6 +171,11 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
169
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
170
  </select>
171
  </p>
 
 
 
 
 
172
  <p>
173
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
174
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -192,12 +199,12 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
192
 
193
  /**
194
  * Get front end part template with parsed data.
195
- *
196
  * @since 1.0.0.
197
- *
198
  * @param array $part_data Form part data.
199
  * @param array $form_data Form (post) data.
200
- *
201
  * @return string Markup for the form part.
202
  */
203
  public function frontend_template( $part_data = array(), $form_data = array() ) {
@@ -213,51 +220,46 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
213
  );
214
  }
215
 
216
- if ( $part_data['mask_type'] == 'phone' ) {
217
- wp_enqueue_script(
218
- 'cleave-phone',
219
- happyforms_get_plugin_url() . 'assets/js/lib/cleave-phone.i18n.js',
220
- array()
221
- );
222
- }
223
-
224
- $classes = ' ';
225
 
226
  if ( $part_data['width'] ) {
227
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
228
  }
229
 
230
  if ( $part_data['label_placement'] ) {
231
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
232
  }
233
 
234
  if ( !empty( $part_data['css_class'] ) ) {
235
- $classes .= $part_data['css_class'];
236
  }
 
 
237
  ?>
238
- <div class="happyforms-part happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
239
- <?php
240
- if ( $form_data ) :
241
- happyforms_message_notices( $form_data, $part_data['id'] );
242
- endif;
243
- ?>
244
  <div class="happyforms-part__wrap">
245
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
246
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
247
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
248
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
249
  <?php endif; ?>
250
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
251
  </label>
252
- <input id="<?php echo esc_attr( $html_id ); ?>" type="text" name="<?php echo esc_attr( $part_data['id'] ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>"
253
  class="happyforms-part__el happyforms-part__el--text-input
254
- <?php if ( $part_data['masked'] === 1 ) : ?> happyforms-masked-input<?php endif; ?>"
 
 
255
  <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?>
256
- <?php if ( $part_data['mask_type'] ) : ?>data-mask-type="<?php echo esc_attr( $part_data['mask_type'] ); ?>"<?php endif; ?>
257
- <?php if ( $part_data['mask_numeric_thousands_delimiter'] ) : ?>data-mask-thousands-delimiter="<?php echo esc_attr( $part_data['mask_numeric_thousands_delimiter'] ); ?>"<?php endif; ?>
258
- <?php if ( $part_data['mask_numeric_decimal_mark'] ) : ?>data-mask-decimal-mark="<?php echo esc_attr( $part_data['mask_numeric_decimal_mark'] ); ?>"<?php endif; ?>
259
- <?php if ( $part_data['mask_numeric_prefix'] ) : ?>data-mask-prefix="<?php echo esc_attr( $part_data['mask_numeric_prefix'] ); ?>"<?php endif; ?>
260
- <?php if ( $part_data['mask_phone_country'] ) : ?>data-mask-phone-country="<?php echo esc_attr( $part_data['mask_phone_country'] ); ?>"<?php endif; ?> />
 
 
 
 
 
261
  </div>
262
  <?php if ( 1 === $part_data['confirmation_field'] ) : ?>
263
  <div class="happyforms-part__wrap happyforms-part__wrap--confirmation" id="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>">
@@ -275,13 +277,14 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
275
  <input id="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>_input" type="text" name="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>"
276
  data-confirmation-of="<?php echo esc_attr( $part_data['id'] ); ?>"
277
  class="happyforms-part__el happyforms-part__el--text-input happyforms-confirmation-input
278
- <?php if ( $part_data['masked'] === 1 ) : ?> happyforms-masked-input<?php endif; ?>"
 
 
279
  <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?>
280
- <?php if ( $part_data['mask_type'] ) : ?>data-mask-type="<?php echo esc_attr( $part_data['mask_type'] ); ?>"<?php endif; ?>
281
  <?php if ( $part_data['mask_numeric_thousands_delimiter'] ) : ?>data-mask-thousands-delimiter="<?php echo esc_attr( $part_data['mask_numeric_thousands_delimiter'] ); ?>"<?php endif; ?>
282
  <?php if ( $part_data['mask_numeric_decimal_mark'] ) : ?>data-mask-decimal-mark="<?php echo esc_attr( $part_data['mask_numeric_decimal_mark'] ); ?>"<?php endif; ?>
283
  <?php if ( $part_data['mask_numeric_prefix'] ) : ?>data-mask-prefix="<?php echo esc_attr( $part_data['mask_numeric_prefix'] ); ?>"<?php endif; ?>
284
- <?php if ( $part_data['mask_phone_country'] ) : ?>data-mask-phone-country="<?php echo esc_attr( $part_data['mask_phone_country'] ); ?>"<?php endif; ?> />
285
  </div>
286
  <?php endif; ?>
287
  </div>
@@ -290,9 +293,9 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
290
 
291
  /**
292
  * Get confirmation field Backbone template for preview purposes.
293
- *
294
  * @since 1.0.0.
295
- *
296
  * @return string Backbone template.
297
  */
298
  public function preview_confirmation_template() {
@@ -309,9 +312,9 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
309
 
310
  /**
311
  * Get all possible messages definitions.
312
- *
313
  * @since 1.0.0.
314
- *
315
  * @return array Associative array, specifying message type and copy.
316
  */
317
  public function get_message_definitions() {
@@ -339,257 +342,13 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
339
  );
340
  }
341
 
342
- /**
343
- * Get associative array of country code => country name and phone code (prefix) for masking purposes.
344
- *
345
- * @since 1.0.0.
346
- *
347
- * @return array
348
- */
349
- public function get_phone_countries_array() {
350
- $phone_countries = array(
351
- 'AD'=>array('name'=>'ANDORRA','code'=>'376'),
352
- 'AE'=>array('name'=>'UNITED ARAB EMIRATES','code'=>'971'),
353
- 'AF'=>array('name'=>'AFGHANISTAN','code'=>'93'),
354
- 'AG'=>array('name'=>'ANTIGUA AND BARBUDA','code'=>'1268'),
355
- 'AI'=>array('name'=>'ANGUILLA','code'=>'1264'),
356
- 'AL'=>array('name'=>'ALBANIA','code'=>'355'),
357
- 'AM'=>array('name'=>'ARMENIA','code'=>'374'),
358
- 'AN'=>array('name'=>'NETHERLANDS ANTILLES','code'=>'599'),
359
- 'AO'=>array('name'=>'ANGOLA','code'=>'244'),
360
- 'AQ'=>array('name'=>'ANTARCTICA','code'=>'672'),
361
- 'AR'=>array('name'=>'ARGENTINA','code'=>'54'),
362
- 'AS'=>array('name'=>'AMERICAN SAMOA','code'=>'1684'),
363
- 'AT'=>array('name'=>'AUSTRIA','code'=>'43'),
364
- 'AU'=>array('name'=>'AUSTRALIA','code'=>'61'),
365
- 'AW'=>array('name'=>'ARUBA','code'=>'297'),
366
- 'AZ'=>array('name'=>'AZERBAIJAN','code'=>'994'),
367
- 'BA'=>array('name'=>'BOSNIA AND HERZEGOVINA','code'=>'387'),
368
- 'BB'=>array('name'=>'BARBADOS','code'=>'1246'),
369
- 'BD'=>array('name'=>'BANGLADESH','code'=>'880'),
370
- 'BE'=>array('name'=>'BELGIUM','code'=>'32'),
371
- 'BF'=>array('name'=>'BURKINA FASO','code'=>'226'),
372
- 'BG'=>array('name'=>'BULGARIA','code'=>'359'),
373
- 'BH'=>array('name'=>'BAHRAIN','code'=>'973'),
374
- 'BI'=>array('name'=>'BURUNDI','code'=>'257'),
375
- 'BJ'=>array('name'=>'BENIN','code'=>'229'),
376
- 'BL'=>array('name'=>'SAINT BARTHELEMY','code'=>'590'),
377
- 'BM'=>array('name'=>'BERMUDA','code'=>'1441'),
378
- 'BN'=>array('name'=>'BRUNEI DARUSSALAM','code'=>'673'),
379
- 'BO'=>array('name'=>'BOLIVIA','code'=>'591'),
380
- 'BR'=>array('name'=>'BRAZIL','code'=>'55'),
381
- 'BS'=>array('name'=>'BAHAMAS','code'=>'1242'),
382
- 'BT'=>array('name'=>'BHUTAN','code'=>'975'),
383
- 'BW'=>array('name'=>'BOTSWANA','code'=>'267'),
384
- 'BY'=>array('name'=>'BELARUS','code'=>'375'),
385
- 'BZ'=>array('name'=>'BELIZE','code'=>'501'),
386
- 'CA'=>array('name'=>'CANADA','code'=>'1'),
387
- 'CC'=>array('name'=>'COCOS (KEELING) ISLANDS','code'=>'61'),
388
- 'CD'=>array('name'=>'CONGO, THE DEMOCRATIC REPUBLIC OF THE','code'=>'243'),
389
- 'CF'=>array('name'=>'CENTRAL AFRICAN REPUBLIC','code'=>'236'),
390
- 'CG'=>array('name'=>'CONGO','code'=>'242'),
391
- 'CH'=>array('name'=>'SWITZERLAND','code'=>'41'),
392
- 'CI'=>array('name'=>'COTE D IVOIRE','code'=>'225'),
393
- 'CK'=>array('name'=>'COOK ISLANDS','code'=>'682'),
394
- 'CL'=>array('name'=>'CHILE','code'=>'56'),
395
- 'CM'=>array('name'=>'CAMEROON','code'=>'237'),
396
- 'CN'=>array('name'=>'CHINA','code'=>'86'),
397
- 'CO'=>array('name'=>'COLOMBIA','code'=>'57'),
398
- 'CR'=>array('name'=>'COSTA RICA','code'=>'506'),
399
- 'CU'=>array('name'=>'CUBA','code'=>'53'),
400
- 'CV'=>array('name'=>'CAPE VERDE','code'=>'238'),
401
- 'CX'=>array('name'=>'CHRISTMAS ISLAND','code'=>'61'),
402
- 'CY'=>array('name'=>'CYPRUS','code'=>'357'),
403
- 'CZ'=>array('name'=>'CZECH REPUBLIC','code'=>'420'),
404
- 'DE'=>array('name'=>'GERMANY','code'=>'49'),
405
- 'DJ'=>array('name'=>'DJIBOUTI','code'=>'253'),
406
- 'DK'=>array('name'=>'DENMARK','code'=>'45'),
407
- 'DM'=>array('name'=>'DOMINICA','code'=>'1767'),
408
- 'DO'=>array('name'=>'DOMINICAN REPUBLIC','code'=>'1809'),
409
- 'DZ'=>array('name'=>'ALGERIA','code'=>'213'),
410
- 'EC'=>array('name'=>'ECUADOR','code'=>'593'),
411
- 'EE'=>array('name'=>'ESTONIA','code'=>'372'),
412
- 'EG'=>array('name'=>'EGYPT','code'=>'20'),
413
- 'ER'=>array('name'=>'ERITREA','code'=>'291'),
414
- 'ES'=>array('name'=>'SPAIN','code'=>'34'),
415
- 'ET'=>array('name'=>'ETHIOPIA','code'=>'251'),
416
- 'FI'=>array('name'=>'FINLAND','code'=>'358'),
417
- 'FJ'=>array('name'=>'FIJI','code'=>'679'),
418
- 'FK'=>array('name'=>'FALKLAND ISLANDS (MALVINAS)','code'=>'500'),
419
- 'FM'=>array('name'=>'MICRONESIA, FEDERATED STATES OF','code'=>'691'),
420
- 'FO'=>array('name'=>'FAROE ISLANDS','code'=>'298'),
421
- 'FR'=>array('name'=>'FRANCE','code'=>'33'),
422
- 'GA'=>array('name'=>'GABON','code'=>'241'),
423
- 'GB'=>array('name'=>'UNITED KINGDOM','code'=>'44'),
424
- 'GD'=>array('name'=>'GRENADA','code'=>'1473'),
425
- 'GE'=>array('name'=>'GEORGIA','code'=>'995'),
426
- 'GH'=>array('name'=>'GHANA','code'=>'233'),
427
- 'GI'=>array('name'=>'GIBRALTAR','code'=>'350'),
428
- 'GL'=>array('name'=>'GREENLAND','code'=>'299'),
429
- 'GM'=>array('name'=>'GAMBIA','code'=>'220'),
430
- 'GN'=>array('name'=>'GUINEA','code'=>'224'),
431
- 'GQ'=>array('name'=>'EQUATORIAL GUINEA','code'=>'240'),
432
- 'GR'=>array('name'=>'GREECE','code'=>'30'),
433
- 'GT'=>array('name'=>'GUATEMALA','code'=>'502'),
434
- 'GU'=>array('name'=>'GUAM','code'=>'1671'),
435
- 'GW'=>array('name'=>'GUINEA-BISSAU','code'=>'245'),
436
- 'GY'=>array('name'=>'GUYANA','code'=>'592'),
437
- 'HK'=>array('name'=>'HONG KONG','code'=>'852'),
438
- 'HN'=>array('name'=>'HONDURAS','code'=>'504'),
439
- 'HR'=>array('name'=>'CROATIA','code'=>'385'),
440
- 'HT'=>array('name'=>'HAITI','code'=>'509'),
441
- 'HU'=>array('name'=>'HUNGARY','code'=>'36'),
442
- 'ID'=>array('name'=>'INDONESIA','code'=>'62'),
443
- 'IE'=>array('name'=>'IRELAND','code'=>'353'),
444
- 'IL'=>array('name'=>'ISRAEL','code'=>'972'),
445
- 'IM'=>array('name'=>'ISLE OF MAN','code'=>'44'),
446
- 'IN'=>array('name'=>'INDIA','code'=>'91'),
447
- 'IQ'=>array('name'=>'IRAQ','code'=>'964'),
448
- 'IR'=>array('name'=>'IRAN, ISLAMIC REPUBLIC OF','code'=>'98'),
449
- 'IS'=>array('name'=>'ICELAND','code'=>'354'),
450
- 'IT'=>array('name'=>'ITALY','code'=>'39'),
451
- 'JM'=>array('name'=>'JAMAICA','code'=>'1876'),
452
- 'JO'=>array('name'=>'JORDAN','code'=>'962'),
453
- 'JP'=>array('name'=>'JAPAN','code'=>'81'),
454
- 'KE'=>array('name'=>'KENYA','code'=>'254'),
455
- 'KG'=>array('name'=>'KYRGYZSTAN','code'=>'996'),
456
- 'KH'=>array('name'=>'CAMBODIA','code'=>'855'),
457
- 'KI'=>array('name'=>'KIRIBATI','code'=>'686'),
458
- 'KM'=>array('name'=>'COMOROS','code'=>'269'),
459
- 'KN'=>array('name'=>'SAINT KITTS AND NEVIS','code'=>'1869'),
460
- 'KP'=>array('name'=>'KOREA DEMOCRATIC PEOPLES REPUBLIC OF','code'=>'850'),
461
- 'KR'=>array('name'=>'KOREA REPUBLIC OF','code'=>'82'),
462
- 'KW'=>array('name'=>'KUWAIT','code'=>'965'),
463
- 'KY'=>array('name'=>'CAYMAN ISLANDS','code'=>'1345'),
464
- 'KZ'=>array('name'=>'KAZAKSTAN','code'=>'7'),
465
- 'LA'=>array('name'=>'LAO PEOPLES DEMOCRATIC REPUBLIC','code'=>'856'),
466
- 'LB'=>array('name'=>'LEBANON','code'=>'961'),
467
- 'LC'=>array('name'=>'SAINT LUCIA','code'=>'1758'),
468
- 'LI'=>array('name'=>'LIECHTENSTEIN','code'=>'423'),
469
- 'LK'=>array('name'=>'SRI LANKA','code'=>'94'),
470
- 'LR'=>array('name'=>'LIBERIA','code'=>'231'),
471
- 'LS'=>array('name'=>'LESOTHO','code'=>'266'),
472
- 'LT'=>array('name'=>'LITHUANIA','code'=>'370'),
473
- 'LU'=>array('name'=>'LUXEMBOURG','code'=>'352'),
474
- 'LV'=>array('name'=>'LATVIA','code'=>'371'),
475
- 'LY'=>array('name'=>'LIBYAN ARAB JAMAHIRIYA','code'=>'218'),
476
- 'MA'=>array('name'=>'MOROCCO','code'=>'212'),
477
- 'MC'=>array('name'=>'MONACO','code'=>'377'),
478
- 'MD'=>array('name'=>'MOLDOVA, REPUBLIC OF','code'=>'373'),
479
- 'ME'=>array('name'=>'MONTENEGRO','code'=>'382'),
480
- 'MF'=>array('name'=>'SAINT MARTIN','code'=>'1599'),
481
- 'MG'=>array('name'=>'MADAGASCAR','code'=>'261'),
482
- 'MH'=>array('name'=>'MARSHALL ISLANDS','code'=>'692'),
483
- 'MK'=>array('name'=>'MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF','code'=>'389'),
484
- 'ML'=>array('name'=>'MALI','code'=>'223'),
485
- 'MM'=>array('name'=>'MYANMAR','code'=>'95'),
486
- 'MN'=>array('name'=>'MONGOLIA','code'=>'976'),
487
- 'MO'=>array('name'=>'MACAU','code'=>'853'),
488
- 'MP'=>array('name'=>'NORTHERN MARIANA ISLANDS','code'=>'1670'),
489
- 'MR'=>array('name'=>'MAURITANIA','code'=>'222'),
490
- 'MS'=>array('name'=>'MONTSERRAT','code'=>'1664'),
491
- 'MT'=>array('name'=>'MALTA','code'=>'356'),
492
- 'MU'=>array('name'=>'MAURITIUS','code'=>'230'),
493
- 'MV'=>array('name'=>'MALDIVES','code'=>'960'),
494
- 'MW'=>array('name'=>'MALAWI','code'=>'265'),
495
- 'MX'=>array('name'=>'MEXICO','code'=>'52'),
496
- 'MY'=>array('name'=>'MALAYSIA','code'=>'60'),
497
- 'MZ'=>array('name'=>'MOZAMBIQUE','code'=>'258'),
498
- 'NA'=>array('name'=>'NAMIBIA','code'=>'264'),
499
- 'NC'=>array('name'=>'NEW CALEDONIA','code'=>'687'),
500
- 'NE'=>array('name'=>'NIGER','code'=>'227'),
501
- 'NG'=>array('name'=>'NIGERIA','code'=>'234'),
502
- 'NI'=>array('name'=>'NICARAGUA','code'=>'505'),
503
- 'NL'=>array('name'=>'NETHERLANDS','code'=>'31'),
504
- 'NO'=>array('name'=>'NORWAY','code'=>'47'),
505
- 'NP'=>array('name'=>'NEPAL','code'=>'977'),
506
- 'NR'=>array('name'=>'NAURU','code'=>'674'),
507
- 'NU'=>array('name'=>'NIUE','code'=>'683'),
508
- 'NZ'=>array('name'=>'NEW ZEALAND','code'=>'64'),
509
- 'OM'=>array('name'=>'OMAN','code'=>'968'),
510
- 'PA'=>array('name'=>'PANAMA','code'=>'507'),
511
- 'PE'=>array('name'=>'PERU','code'=>'51'),
512
- 'PF'=>array('name'=>'FRENCH POLYNESIA','code'=>'689'),
513
- 'PG'=>array('name'=>'PAPUA NEW GUINEA','code'=>'675'),
514
- 'PH'=>array('name'=>'PHILIPPINES','code'=>'63'),
515
- 'PK'=>array('name'=>'PAKISTAN','code'=>'92'),
516
- 'PL'=>array('name'=>'POLAND','code'=>'48'),
517
- 'PM'=>array('name'=>'SAINT PIERRE AND MIQUELON','code'=>'508'),
518
- 'PN'=>array('name'=>'PITCAIRN','code'=>'870'),
519
- 'PR'=>array('name'=>'PUERTO RICO','code'=>'1'),
520
- 'PT'=>array('name'=>'PORTUGAL','code'=>'351'),
521
- 'PW'=>array('name'=>'PALAU','code'=>'680'),
522
- 'PY'=>array('name'=>'PARAGUAY','code'=>'595'),
523
- 'QA'=>array('name'=>'QATAR','code'=>'974'),
524
- 'RO'=>array('name'=>'ROMANIA','code'=>'40'),
525
- 'RS'=>array('name'=>'SERBIA','code'=>'381'),
526
- 'RU'=>array('name'=>'RUSSIAN FEDERATION','code'=>'7'),
527
- 'RW'=>array('name'=>'RWANDA','code'=>'250'),
528
- 'SA'=>array('name'=>'SAUDI ARABIA','code'=>'966'),
529
- 'SB'=>array('name'=>'SOLOMON ISLANDS','code'=>'677'),
530
- 'SC'=>array('name'=>'SEYCHELLES','code'=>'248'),
531
- 'SD'=>array('name'=>'SUDAN','code'=>'249'),
532
- 'SE'=>array('name'=>'SWEDEN','code'=>'46'),
533
- 'SG'=>array('name'=>'SINGAPORE','code'=>'65'),
534
- 'SH'=>array('name'=>'SAINT HELENA','code'=>'290'),
535
- 'SI'=>array('name'=>'SLOVENIA','code'=>'386'),
536
- 'SK'=>array('name'=>'SLOVAKIA','code'=>'421'),
537
- 'SL'=>array('name'=>'SIERRA LEONE','code'=>'232'),
538
- 'SM'=>array('name'=>'SAN MARINO','code'=>'378'),
539
- 'SN'=>array('name'=>'SENEGAL','code'=>'221'),
540
- 'SO'=>array('name'=>'SOMALIA','code'=>'252'),
541
- 'SR'=>array('name'=>'SURINAME','code'=>'597'),
542
- 'ST'=>array('name'=>'SAO TOME AND PRINCIPE','code'=>'239'),
543
- 'SV'=>array('name'=>'EL SALVADOR','code'=>'503'),
544
- 'SY'=>array('name'=>'SYRIAN ARAB REPUBLIC','code'=>'963'),
545
- 'SZ'=>array('name'=>'SWAZILAND','code'=>'268'),
546
- 'TC'=>array('name'=>'TURKS AND CAICOS ISLANDS','code'=>'1649'),
547
- 'TD'=>array('name'=>'CHAD','code'=>'235'),
548
- 'TG'=>array('name'=>'TOGO','code'=>'228'),
549
- 'TH'=>array('name'=>'THAILAND','code'=>'66'),
550
- 'TJ'=>array('name'=>'TAJIKISTAN','code'=>'992'),
551
- 'TK'=>array('name'=>'TOKELAU','code'=>'690'),
552
- 'TL'=>array('name'=>'TIMOR-LESTE','code'=>'670'),
553
- 'TM'=>array('name'=>'TURKMENISTAN','code'=>'993'),
554
- 'TN'=>array('name'=>'TUNISIA','code'=>'216'),
555
- 'TO'=>array('name'=>'TONGA','code'=>'676'),
556
- 'TR'=>array('name'=>'TURKEY','code'=>'90'),
557
- 'TT'=>array('name'=>'TRINIDAD AND TOBAGO','code'=>'1868'),
558
- 'TV'=>array('name'=>'TUVALU','code'=>'688'),
559
- 'TW'=>array('name'=>'TAIWAN, PROVINCE OF CHINA','code'=>'886'),
560
- 'TZ'=>array('name'=>'TANZANIA, UNITED REPUBLIC OF','code'=>'255'),
561
- 'UA'=>array('name'=>'UKRAINE','code'=>'380'),
562
- 'UG'=>array('name'=>'UGANDA','code'=>'256'),
563
- 'US'=>array('name'=>'UNITED STATES','code'=>'1'),
564
- 'UY'=>array('name'=>'URUGUAY','code'=>'598'),
565
- 'UZ'=>array('name'=>'UZBEKISTAN','code'=>'998'),
566
- 'VA'=>array('name'=>'HOLY SEE (VATICAN CITY STATE)','code'=>'39'),
567
- 'VC'=>array('name'=>'SAINT VINCENT AND THE GRENADINES','code'=>'1784'),
568
- 'VE'=>array('name'=>'VENEZUELA','code'=>'58'),
569
- 'VG'=>array('name'=>'VIRGIN ISLANDS, BRITISH','code'=>'1284'),
570
- 'VI'=>array('name'=>'VIRGIN ISLANDS, U.S.','code'=>'1340'),
571
- 'VN'=>array('name'=>'VIET NAM','code'=>'84'),
572
- 'VU'=>array('name'=>'VANUATU','code'=>'678'),
573
- 'WF'=>array('name'=>'WALLIS AND FUTUNA','code'=>'681'),
574
- 'WS'=>array('name'=>'SAMOA','code'=>'685'),
575
- 'XK'=>array('name'=>'KOSOVO','code'=>'381'),
576
- 'YE'=>array('name'=>'YEMEN','code'=>'967'),
577
- 'YT'=>array('name'=>'MAYOTTE','code'=>'262'),
578
- 'ZA'=>array('name'=>'SOUTH AFRICA','code'=>'27'),
579
- 'ZM'=>array('name'=>'ZAMBIA','code'=>'260'),
580
- 'ZW'=>array('name'=>'ZIMBABWE','code'=>'263')
581
- );
582
-
583
- return $phone_countries;
584
- }
585
-
586
  /**
587
  * Sanitize submitted value before storing it.
588
- *
589
  * @since 1.0.0.
590
- *
591
  * @param array $part_data Form part data.
592
- *
593
  * @return string
594
  */
595
  public function sanitize_value( $part_data = array() ) {
@@ -612,19 +371,21 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
612
 
613
  /**
614
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
615
- *
616
  * @since 1.0.0.
617
- *
618
  * @param array $part_data Form part data.
619
  * @param string $value Submitted value.
620
- *
621
  * @return string|object
622
  */
623
  public function validate_value( $part_data, $value ) {
624
  $part_id = $part_data['id'];
625
  $validated_value = $value;
 
626
 
627
  if ( is_array( $validated_value ) ) {
 
628
  $validated_confirmation_value = $validated_value[1];
629
  $validated_value = $validated_value[0];
630
  } else {
@@ -635,23 +396,22 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
635
  $validated_value = new WP_Error( $part_id, 'missing_required_field' );
636
  }
637
 
638
- if ( 1 === $part_data['required'] && empty( $validated_confirmation_value ) ) {
639
- $validated_value = new WP_Error( $part_id, 'missing_required_confirmation_field' );
640
- }
 
641
 
642
- if ( $validated_value !== $validated_confirmation_value ) {
643
- $validated_value = new WP_Error( $part_id, 'numbers_not_matching' );
 
644
  }
645
 
646
- // If field type is set to number, do additional checks using `is_numeric()`.
647
- if ( $part_data['type'] === 'number' ) {
648
- if ( $part_data['masked'] === 0 && !is_numeric( $validated_confirmation_value ) ) {
649
- $validated_value = new WP_error( $part_id, 'not_a_number_confirmation' );
650
- }
651
 
652
- if ( $part_data['masked'] === 0 && !is_numeric( $validated_value ) ) {
653
- $validated_value = new WP_Error( $part_id, 'not_a_number' );
654
- }
655
  }
656
 
657
  return $validated_value;
@@ -659,11 +419,11 @@ class HappyForms_Part_Number extends HappyForms_Form_Part {
659
 
660
  /**
661
  * Enqueue scripts in customizer area.
662
- *
663
  * @since 1.0.0.
664
- *
665
  * @param array List of dependencies.
666
- *
667
  * @return void
668
  */
669
  public function customize_enqueue_scripts( $deps = array() ) {
8
 
9
  public function __construct() {
10
  $this->label = __( 'Number', 'happyforms' );
11
+ $this->description = __( 'For numeric fields.', 'happyforms' );
12
  }
13
 
14
  /**
15
  * Get all part meta fields defaults.
16
+ *
17
  * @since 1.0.0.
18
+ *
19
  * @return array
20
  */
21
  public function get_customize_fields() {
36
  'default' => '',
37
  'sanitize' => 'sanitize_text_field'
38
  ),
39
+ 'tooltip_description' => array(
40
+ 'default' => 0,
41
+ 'sanitize' => 'happyforms_sanitize_checkbox'
42
+ ),
43
  'placeholder' => array(
44
  'default' => '',
45
  'sanitize' => 'sanitize_text_field',
52
  'default' => '',
53
  'sanitize' => 'sanitize_text_field'
54
  ),
55
+ 'min_value' => array(
56
+ 'default' => 0,
57
+ 'sanitize' => 'intval'
58
+ ),
59
+ 'max_value' => array(
60
+ 'default' => 0,
61
+ 'sanitize' => 'intval'
62
+ ),
63
  'masked' => array(
64
  'default' => 0,
65
  'sanitize' => 'intval'
66
  ),
 
 
 
 
67
  'mask_numeric_thousands_delimiter' => array(
68
  'default' => ',',
69
  'sanitize' => 'sanitize_text_field'
76
  'default' => '',
77
  'sanitize' => 'sanitize_text_field'
78
  ),
 
 
 
 
79
  'confirmation_field' => array(
80
  'default' => 0,
81
  'sanitize' => 'intval'
97
 
98
  /**
99
  * Get template for part item in customize pane.
100
+ *
101
  * @since 1.0.0.
102
+ *
103
  * @return string
104
  */
105
  public function customize_template() {
116
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
117
  </select>
118
  </p>
119
+ <p class="label_placement-options" style="display: none">
120
+ <label>
121
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
122
+ </label>
123
+ </p>
124
  <p>
125
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
126
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
127
  </p>
128
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
129
+ <label>
130
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
131
+ </label>
132
+ </p>
133
  <p>
134
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
135
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
136
  </p>
137
+ <div class="min-max-wrapper" style="display: <%= (instance.masked == 0) ? 'block' : 'none' %>">
138
+ <p>
139
+ <label for="<%= instance.id %>_min_value"><?php _e( 'Minimum accepted value', 'happyforms' ); ?></label>
140
+ <input type="text" id="<%= instance.id %>_min_value" class="widefat title" value="<%= instance.min_value %>" data-bind="min_value" />
141
+ </p>
142
+ <p>
143
+ <label for="<%= instance.id %>_max_value"><?php _e( 'Maximum accepted value', 'happyforms' ); ?></label>
144
+ <input type="text" id="<%= instance.id %>_max_value" class="widefat title" value="<%= instance.max_value %>" data-bind="max_value" />
145
+ </p>
146
+ </div>
147
  <p>
148
  <label>
149
  <input type="checkbox" name="masked" class="checkbox" value="1" <% if ( instance.masked ) { %>checked="checked"<% } %> data-bind="masked" /> <?php _e( 'Mask this input', 'happyforms' ); ?>
150
  </label>
151
  </p>
152
+ <div class="mask-wrapper number-options number-options--numeric" style="display: <%= (instance.masked == 1) ? 'block' : 'none' %>">
 
 
 
 
 
 
 
153
  <p>
154
  <label for="<%= instance.id %>_mask_numeric_thousands_delimiter"><?php _e( 'Thousands delimiter', 'happyforms' ); ?></label>
155
  <input type="text" id="<%= instance.id %>_mask_numeric_thousands_delimiter" class="widefat title" value="<%= instance.mask_numeric_thousands_delimiter %>" data-bind="mask_numeric_thousands_delimiter" />
163
  <input type="text" id="<%= instance.id %>_mask_numeric_prefix" class="widefat title" value="<%= instance.mask_numeric_prefix %>" data-bind="mask_numeric_prefix" />
164
  </p>
165
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  <p>
167
  <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
168
  <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
171
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
172
  </select>
173
  </p>
174
+ <p class="width-options" style="display: none">
175
+ <label>
176
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
177
+ </label>
178
+ </p>
179
  <p>
180
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
181
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
199
 
200
  /**
201
  * Get front end part template with parsed data.
202
+ *
203
  * @since 1.0.0.
204
+ *
205
  * @param array $part_data Form part data.
206
  * @param array $form_data Form (post) data.
207
+ *
208
  * @return string Markup for the form part.
209
  */
210
  public function frontend_template( $part_data = array(), $form_data = array() ) {
220
  );
221
  }
222
 
223
+ $classes = array('happyforms-part--number');
 
 
 
 
 
 
 
 
224
 
225
  if ( $part_data['width'] ) {
226
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
227
  }
228
 
229
  if ( $part_data['label_placement'] ) {
230
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
231
  }
232
 
233
  if ( !empty( $part_data['css_class'] ) ) {
234
+ $classes[] = $part_data['css_class'];
235
  }
236
+
237
+ $classes = implode( ' ', $classes );
238
  ?>
239
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
240
  <div class="happyforms-part__wrap">
241
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
242
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
243
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
244
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
245
  <?php endif; ?>
 
246
  </label>
247
+ <input id="<?php echo esc_attr( $html_id ); ?>" type="<?php echo ( 1 === $part_data['masked'] ) ? 'text' : 'number'; ?>" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>"
248
  class="happyforms-part__el happyforms-part__el--text-input
249
+ <?php echo ( 1 === $part_data['masked'] ) ? ' happyforms-masked-input' : ''; ?>"
250
+ <?php if ( 0 === $part_data['masked'] && $part_data['min_value'] > 0 ) : ?>min="<?php echo esc_attr( $part_data['min_value'] ); ?>"<?php endif; ?>
251
+ <?php if ( 0 === $part_data['masked'] && $part_data['max_value'] > 0 ) : ?>max="<?php echo esc_attr( $part_data['max_value'] ); ?>"<?php endif; ?>
252
  <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?>
253
+ <?php if ( 1 === $part_data['masked'] ) : ?>data-mask-type="numeric"<?php endif; ?>
254
+ <?php if ( 1 === $part_data['masked'] && $part_data['mask_numeric_thousands_delimiter'] ) : ?>data-mask-thousands-delimiter="<?php echo esc_attr( $part_data['mask_numeric_thousands_delimiter'] ); ?>"<?php endif; ?>
255
+ <?php if ( 1 === $part_data['masked'] && $part_data['mask_numeric_decimal_mark'] ) : ?>data-mask-decimal-mark="<?php echo esc_attr( $part_data['mask_numeric_decimal_mark'] ); ?>"<?php endif; ?>
256
+ <?php if ( 1 === $part_data['masked'] && $part_data['mask_numeric_prefix'] ) : ?>data-mask-prefix="<?php echo esc_attr( $part_data['mask_numeric_prefix'] ); ?>"<?php endif; ?> />
257
+ <?php happyforms_print_part_description( $part_data ); ?>
258
+ <?php
259
+ if ( $form_data ) :
260
+ happyforms_message_notices( $form_data, $part_data['id'] );
261
+ endif;
262
+ ?>
263
  </div>
264
  <?php if ( 1 === $part_data['confirmation_field'] ) : ?>
265
  <div class="happyforms-part__wrap happyforms-part__wrap--confirmation" id="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>">
277
  <input id="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>_input" type="text" name="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>"
278
  data-confirmation-of="<?php echo esc_attr( $part_data['id'] ); ?>"
279
  class="happyforms-part__el happyforms-part__el--text-input happyforms-confirmation-input
280
+ <?php if ( 1 === $part_data['masked'] ) : ?> happyforms-masked-input<?php endif; ?>"
281
+ <?php if ( 0 === $part_data['masked'] && $part_data['min_value'] > 0 ) : ?>min="<?php echo esc_attr( $part_data['min_value'] ); ?>"<?php endif; ?>
282
+ <?php if ( 0 === $part_data['masked'] && $part_data['max_value'] > 0 ) : ?>max="<?php echo esc_attr( $part_data['max_value'] ); ?>"<?php endif; ?>
283
  <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?>
284
+ <?php if ( 1 === $part_data['masked'] ) : ?>data-mask-type="numeric"<?php endif; ?>
285
  <?php if ( $part_data['mask_numeric_thousands_delimiter'] ) : ?>data-mask-thousands-delimiter="<?php echo esc_attr( $part_data['mask_numeric_thousands_delimiter'] ); ?>"<?php endif; ?>
286
  <?php if ( $part_data['mask_numeric_decimal_mark'] ) : ?>data-mask-decimal-mark="<?php echo esc_attr( $part_data['mask_numeric_decimal_mark'] ); ?>"<?php endif; ?>
287
  <?php if ( $part_data['mask_numeric_prefix'] ) : ?>data-mask-prefix="<?php echo esc_attr( $part_data['mask_numeric_prefix'] ); ?>"<?php endif; ?>
 
288
  </div>
289
  <?php endif; ?>
290
  </div>
293
 
294
  /**
295
  * Get confirmation field Backbone template for preview purposes.
296
+ *
297
  * @since 1.0.0.
298
+ *
299
  * @return string Backbone template.
300
  */
301
  public function preview_confirmation_template() {
312
 
313
  /**
314
  * Get all possible messages definitions.
315
+ *
316
  * @since 1.0.0.
317
+ *
318
  * @return array Associative array, specifying message type and copy.
319
  */
320
  public function get_message_definitions() {
342
  );
343
  }
344
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
345
  /**
346
  * Sanitize submitted value before storing it.
347
+ *
348
  * @since 1.0.0.
349
+ *
350
  * @param array $part_data Form part data.
351
+ *
352
  * @return string
353
  */
354
  public function sanitize_value( $part_data = array() ) {
371
 
372
  /**
373
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
374
+ *
375
  * @since 1.0.0.
376
+ *
377
  * @param array $part_data Form part data.
378
  * @param string $value Submitted value.
379
+ *
380
  * @return string|object
381
  */
382
  public function validate_value( $part_data, $value ) {
383
  $part_id = $part_data['id'];
384
  $validated_value = $value;
385
+ $has_confirmation_value = false;
386
 
387
  if ( is_array( $validated_value ) ) {
388
+ $has_confirmation_value = true;
389
  $validated_confirmation_value = $validated_value[1];
390
  $validated_value = $validated_value[0];
391
  } else {
396
  $validated_value = new WP_Error( $part_id, 'missing_required_field' );
397
  }
398
 
399
+ if ( true === $has_confirmation_value ) {
400
+ if ( 1 === $part_data['required'] && empty( $validated_confirmation_value ) ) {
401
+ $validated_value = new WP_Error( $part_id, 'missing_required_confirmation_field' );
402
+ }
403
 
404
+ if ( $validated_value !== $validated_confirmation_value ) {
405
+ $validated_value = new WP_Error( $part_id, 'numbers_not_matching' );
406
+ }
407
  }
408
 
409
+ if ( $part_data['masked'] === 0 && !is_numeric( $validated_value ) ) {
410
+ $validated_value = new WP_Error( $part_id, 'not_a_number' );
411
+ }
 
 
412
 
413
+ if ( true === $has_confirmation_value && $part_data['masked'] === 0 && !is_numeric( $validated_confirmation_value ) ) {
414
+ $validated_value = new WP_error( $part_id, 'not_a_number_confirmation' );
 
415
  }
416
 
417
  return $validated_value;
419
 
420
  /**
421
  * Enqueue scripts in customizer area.
422
+ *
423
  * @since 1.0.0.
424
+ *
425
  * @param array List of dependencies.
426
+ *
427
  * @return void
428
  */
429
  public function customize_enqueue_scripts( $deps = array() ) {
inc/classes/parts/class-part-phone.php ADDED
@@ -0,0 +1,640 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class HappyForms_Part_Phone extends HappyForms_Form_Part {
4
+
5
+ public $type = 'phone';
6
+ public $template_id = 'happyforms-phone-template';
7
+ public $preview_confirmation_template_id = 'happyforms-phone-confirmation-template';
8
+
9
+ public function __construct() {
10
+ $this->label = __( 'Phone', 'happyforms' );
11
+ $this->description = __( 'For phone numbers. Includes country specific formatting.', 'happyforms' );
12
+ }
13
+
14
+ /**
15
+ * Get all part meta fields defaults.
16
+ *
17
+ * @since 1.0.0.
18
+ *
19
+ * @return array
20
+ */
21
+ public function get_customize_fields() {
22
+ return array(
23
+ 'type' => array(
24
+ 'default' => $this->type,
25
+ 'sanitize' => 'sanitize_text_field',
26
+ ),
27
+ 'label' => array(
28
+ 'default' => __( 'Phone', 'happyforms' ),
29
+ 'sanitize' => 'sanitize_text_field',
30
+ ),
31
+ 'label_placement' => array(
32
+ 'default' => 'above',
33
+ 'sanitize' => 'sanitize_text_field'
34
+ ),
35
+ 'description' => array(
36
+ 'default' => '',
37
+ 'sanitize' => 'sanitize_text_field'
38
+ ),
39
+ 'tooltip_description' => array(
40
+ 'default' => 0,
41
+ 'sanitize' => 'happyforms_sanitize_checkbox'
42
+ ),
43
+ 'placeholder' => array(
44
+ 'default' => '',
45
+ 'sanitize' => 'sanitize_text_field',
46
+ ),
47
+ 'width' => array(
48
+ 'default' => 'full',
49
+ 'sanitize' => 'sanitize_key'
50
+ ),
51
+ 'css_class' => array(
52
+ 'default' => '',
53
+ 'sanitize' => 'sanitize_text_field'
54
+ ),
55
+ 'masked' => array(
56
+ 'default' => 0,
57
+ 'sanitize' => 'intval'
58
+ ),
59
+ 'mask_phone_country' => array(
60
+ 'default' => '',
61
+ 'sanitize' => 'intval'
62
+ ),
63
+ 'confirmation_field' => array(
64
+ 'default' => 0,
65
+ 'sanitize' => 'intval'
66
+ ),
67
+ 'confirmation_field_id' => array(
68
+ 'default' => '',
69
+ 'sanitize' => 'sanitize_text_field'
70
+ ),
71
+ 'confirmation_field_label' => array(
72
+ 'default' => __( 'Confirm Number', 'happyforms' ),
73
+ 'sanitize' => 'sanitize_text_field'
74
+ ),
75
+ 'required' => array(
76
+ 'default' => 1,
77
+ 'sanitize' => 'happyforms_sanitize_checkbox',
78
+ ),
79
+ );
80
+ }
81
+
82
+ /**
83
+ * Get template for part item in customize pane.
84
+ *
85
+ * @since 1.0.0.
86
+ *
87
+ * @return string
88
+ */
89
+ public function customize_template() {
90
+ ?>
91
+ <p>
92
+ <label for="<%= instance.id %>_title"><?php _e( 'Title', 'happyforms' ); ?></label>
93
+ <input type="text" id="<%= instance.id %>_title" class="widefat title" value="<%= instance.label %>" data-bind="label" />
94
+ </p>
95
+ <p>
96
+ <label for="<%= instance.id %>_label_placement"><?php _e( 'Title placement', 'happyforms' ); ?></label>
97
+ <select id="<%= instance.id %>_label_placement" data-bind="label_placement">
98
+ <option value="above"<%= (instance.label_placement == 'above') ? ' selected' : '' %>><?php _e( 'Above', 'happyforms' ); ?></option>
99
+ <option value="left"<%= (instance.label_placement == 'left') ? ' selected' : '' %>><?php _e( 'Left', 'happyforms' ); ?></option>
100
+ <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
101
+ </select>
102
+ </p>
103
+ <p class="label_placement-options" style="display: none">
104
+ <label>
105
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
106
+ </label>
107
+ </p>
108
+ <p>
109
+ <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
110
+ <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
111
+ </p>
112
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
113
+ <label>
114
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
115
+ </label>
116
+ </p>
117
+ <p>
118
+ <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
119
+ <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
120
+ </p>
121
+ <p>
122
+ <label>
123
+ <input type="checkbox" name="masked" class="checkbox" value="1" <% if ( instance.masked ) { %>checked="checked"<% } %> data-bind="masked" /> <?php _e( 'Mask this input', 'happyforms' ); ?>
124
+ </label>
125
+ </p>
126
+ <div class="number-options number-options--phone" style="display: <%= (instance.masked == 1) ? 'block' : 'none' %>">
127
+ <p>
128
+ <label for="<%= instance.id %>_mask_phone_country"><?php _e( 'Pre-format phone number region', 'happyforms' ); ?></label>
129
+ <select id="<%= instance.id %>_mask_phone_country" class="widefat title" data-bind="mask_phone_country">
130
+ <option value="">- <?php _e( 'Select', 'happyforms' ); ?> -</option>
131
+ <?php
132
+ $phone_countries = $this->get_phone_countries_array();
133
+
134
+ foreach ( $phone_countries as $country_code => $country ) {
135
+ echo '<option value="'. $country['code'] .'"<% if (instance.mask_phone_country == "'. $country['code'] .'") { %> selected<% } %>>'. ucwords( strtolower( $country['name'] ) ) .'</option>';
136
+ }
137
+ ?>
138
+ </select>
139
+ </p>
140
+ </div>
141
+ <p>
142
+ <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
143
+ <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
144
+ <option value="full"<%= (instance.width == 'full') ? ' selected' : '' %>><?php _e( 'Full', 'happyforms' ); ?></option>
145
+ <option value="half"<%= (instance.width == 'half') ? ' selected' : '' %>><?php _e( 'Half', 'happyforms' ); ?></option>
146
+ <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
147
+ </select>
148
+ </p>
149
+ <p class="width-options" style="display: none">
150
+ <label>
151
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
152
+ </label>
153
+ </p>
154
+ <p>
155
+ <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
156
+ <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
157
+ </p>
158
+ <p>
159
+ <label>
160
+ <input type="checkbox" class="checkbox confirmation-checkbox" value="1" <% if ( instance.confirmation_field ) { %>checked="checked"<% } %> data-bind="confirmation_field" /> <?php _e( 'Require confirmation of the value', 'happyforms' ); ?>
161
+ </label>
162
+ </p>
163
+ <p class="confirmation-field-setting" style="display: <%= (instance.confirmation_field == 1) ? 'block' : 'none' %>">
164
+ <label for="<%= instance.id %>_confirmation_field_label"><?php _e( 'Confirmation field title', 'happyforms' ); ?></label>
165
+ <input type="text" id="<%= instance.id %>_confirmation_field_label" class="widefat title" value="<%= instance.confirmation_field_label %>" data-bind="confirmation_field_label" />
166
+ </p>
167
+ <p>
168
+ <label>
169
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.required ) { %>checked="checked"<% } %> data-bind="required" /> <?php _e( 'This is a required field', 'happyforms' ); ?>
170
+ </label>
171
+ </p>
172
+ <?php
173
+ }
174
+
175
+ /**
176
+ * Get front end part template with parsed data.
177
+ *
178
+ * @since 1.0.0.
179
+ *
180
+ * @param array $part_data Form part data.
181
+ * @param array $form_data Form (post) data.
182
+ *
183
+ * @return string Markup for the form part.
184
+ */
185
+ public function frontend_template( $part_data = array(), $form_data = array() ) {
186
+ $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
187
+ $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
188
+ $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
189
+
190
+ if ( $part_data['masked'] ) {
191
+ wp_enqueue_script(
192
+ 'cleave',
193
+ happyforms_get_plugin_url() . 'assets/js/lib/cleave.min.js',
194
+ array()
195
+ );
196
+
197
+ wp_enqueue_script(
198
+ 'cleave-phone',
199
+ happyforms_get_plugin_url() . 'assets/js/lib/cleave-phone.i18n.js',
200
+ array()
201
+ );
202
+ }
203
+
204
+ $classes = array('happyforms-part--phone');
205
+
206
+ if ( $part_data['width'] ) {
207
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
208
+ }
209
+
210
+ if ( $part_data['label_placement'] ) {
211
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
212
+ }
213
+
214
+ if ( !empty( $part_data['css_class'] ) ) {
215
+ $classes[] = $part_data['css_class'];
216
+ }
217
+
218
+ $classes = implode( ' ', $classes );
219
+ ?>
220
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
221
+ <div class="happyforms-part__wrap">
222
+ <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
223
+ <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
224
+ <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
225
+ <span class="happyforms-required"> <?php echo $required_text; ?></span>
226
+ <?php endif; ?>
227
+ </label>
228
+ <input id="<?php echo esc_attr( $html_id ); ?>" type="text" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>"
229
+ class="happyforms-part__el happyforms-part__el--text-input
230
+ <?php if ( 1 === $part_data['masked'] ) : ?> happyforms-masked-input<?php endif; ?>"
231
+ <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?>
232
+ <?php if ( 1 === $part_data['masked'] ) : ?>data-mask-type="phone"<?php endif; ?>
233
+ <?php if ( $part_data['mask_phone_country'] ) : ?>data-mask-phone-country="<?php echo esc_attr( $part_data['mask_phone_country'] ); ?>"<?php endif; ?> />
234
+ <?php happyforms_print_part_description( $part_data ); ?>
235
+ <?php
236
+ if ( $form_data ) :
237
+ happyforms_message_notices( $form_data, $part_data['id'] );
238
+ endif;
239
+ ?>
240
+ </div>
241
+ <?php if ( 1 === $part_data['confirmation_field'] ) : ?>
242
+ <div class="happyforms-part__wrap happyforms-part__wrap--confirmation" id="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>">
243
+ <div class="happyforms-message-notices" style="display: none">
244
+ <div class="happyforms-message-notice error">
245
+ <h2><?php _e( 'Fields do not match.', 'happyforms' ); ?></h2>
246
+ </div>
247
+ </div>
248
+ <label for="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>_input" class="happyforms-part__label happyforms-part__label--confirmation">
249
+ <span class="label"><?php echo esc_html( $part_data['confirmation_field_label'] ); ?></span>
250
+ <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
251
+ <span class="happyforms-required"> <?php echo $required_text; ?></span>
252
+ <?php endif; ?>
253
+ </label>
254
+ <input id="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>_input" type="text" name="<?php echo esc_attr( $part_data['confirmation_field_id'] ); ?>"
255
+ data-confirmation-of="<?php echo esc_attr( $part_data['id'] ); ?>"
256
+ class="happyforms-part__el happyforms-part__el--text-input happyforms-confirmation-input
257
+ <?php if ( 1 === $part_data['masked'] ) : ?> happyforms-masked-input<?php endif; ?>"
258
+ <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?>
259
+ <?php if ( 1 === $part_data['masked'] ) : ?>data-mask-type="phone"<?php endif; ?>
260
+ <?php if ( $part_data['mask_phone_country'] ) : ?>data-mask-phone-country="<?php echo esc_attr( $part_data['mask_phone_country'] ); ?>"<?php endif; ?> />
261
+ </div>
262
+ <?php endif; ?>
263
+ </div>
264
+ <?php
265
+ }
266
+
267
+ /**
268
+ * Get confirmation field Backbone template for preview purposes.
269
+ *
270
+ * @since 1.0.0.
271
+ *
272
+ * @return string Backbone template.
273
+ */
274
+ public function preview_confirmation_template() {
275
+ ?>
276
+ <div class="happyforms-part__el happyforms-part__el--confirmation" id="<%= confirmation_field_id %>">
277
+ <label for="" class="happyforms-part__label happyforms-part__label--confirmation">
278
+ <span class="label"><%= confirmation_field_label %></span>
279
+ <span class="happyforms-required"> *</span>
280
+ </label>
281
+ <input type="text" class="happyforms-part__el happyforms-part__el--text-input" required aria-required="true" />
282
+ </div>
283
+ <?php
284
+ }
285
+
286
+ /**
287
+ * Get all possible messages definitions.
288
+ *
289
+ * @since 1.0.0.
290
+ *
291
+ * @return array Associative array, specifying message type and copy.
292
+ */
293
+ public function get_message_definitions() {
294
+ return array(
295
+ 'missing_required_field' => array(
296
+ 'type' => 'error',
297
+ 'message' => __( 'This field is required.', 'happyforms' ),
298
+ ),
299
+ 'missing_required_confirmation_field' => array(
300
+ 'type' => 'error',
301
+ 'message' => __( 'Confirmation field is required.', 'happyforms' )
302
+ ),
303
+ 'numbers_not_matching' => array(
304
+ 'type' => 'error',
305
+ 'message' => __( 'Number and confirmation number are not matching.', 'happyforms' )
306
+ ),
307
+ );
308
+ }
309
+
310
+ /**
311
+ * Get associative array of country code => country name and phone code (prefix) for masking purposes.
312
+ *
313
+ * @since 1.0.0.
314
+ *
315
+ * @return array
316
+ */
317
+ public function get_phone_countries_array() {
318
+ $phone_countries = array(
319
+ 'AD'=>array('name'=>'ANDORRA','code'=>'376'),
320
+ 'AE'=>array('name'=>'UNITED ARAB EMIRATES','code'=>'971'),
321
+ 'AF'=>array('name'=>'AFGHANISTAN','code'=>'93'),
322
+ 'AG'=>array('name'=>'ANTIGUA AND BARBUDA','code'=>'1268'),
323
+ 'AI'=>array('name'=>'ANGUILLA','code'=>'1264'),
324
+ 'AL'=>array('name'=>'ALBANIA','code'=>'355'),
325
+ 'AM'=>array('name'=>'ARMENIA','code'=>'374'),
326
+ 'AN'=>array('name'=>'NETHERLANDS ANTILLES','code'=>'599'),
327
+ 'AO'=>array('name'=>'ANGOLA','code'=>'244'),
328
+ 'AQ'=>array('name'=>'ANTARCTICA','code'=>'672'),
329
+ 'AR'=>array('name'=>'ARGENTINA','code'=>'54'),
330
+ 'AS'=>array('name'=>'AMERICAN SAMOA','code'=>'1684'),
331
+ 'AT'=>array('name'=>'AUSTRIA','code'=>'43'),
332
+ 'AU'=>array('name'=>'AUSTRALIA','code'=>'61'),
333
+ 'AW'=>array('name'=>'ARUBA','code'=>'297'),
334
+ 'AZ'=>array('name'=>'AZERBAIJAN','code'=>'994'),
335
+ 'BA'=>array('name'=>'BOSNIA AND HERZEGOVINA','code'=>'387'),
336
+ 'BB'=>array('name'=>'BARBADOS','code'=>'1246'),
337
+ 'BD'=>array('name'=>'BANGLADESH','code'=>'880'),
338
+ 'BE'=>array('name'=>'BELGIUM','code'=>'32'),
339
+ 'BF'=>array('name'=>'BURKINA FASO','code'=>'226'),
340
+ 'BG'=>array('name'=>'BULGARIA','code'=>'359'),
341
+ 'BH'=>array('name'=>'BAHRAIN','code'=>'973'),
342
+ 'BI'=>array('name'=>'BURUNDI','code'=>'257'),
343
+ 'BJ'=>array('name'=>'BENIN','code'=>'229'),
344
+ 'BL'=>array('name'=>'SAINT BARTHELEMY','code'=>'590'),
345
+ 'BM'=>array('name'=>'BERMUDA','code'=>'1441'),
346
+ 'BN'=>array('name'=>'BRUNEI DARUSSALAM','code'=>'673'),
347
+ 'BO'=>array('name'=>'BOLIVIA','code'=>'591'),
348
+ 'BR'=>array('name'=>'BRAZIL','code'=>'55'),
349
+ 'BS'=>array('name'=>'BAHAMAS','code'=>'1242'),
350
+ 'BT'=>array('name'=>'BHUTAN','code'=>'975'),
351
+ 'BW'=>array('name'=>'BOTSWANA','code'=>'267'),
352
+ 'BY'=>array('name'=>'BELARUS','code'=>'375'),
353
+ 'BZ'=>array('name'=>'BELIZE','code'=>'501'),
354
+ 'CA'=>array('name'=>'CANADA','code'=>'1'),
355
+ 'CC'=>array('name'=>'COCOS (KEELING) ISLANDS','code'=>'61'),
356
+ 'CD'=>array('name'=>'CONGO, THE DEMOCRATIC REPUBLIC OF THE','code'=>'243'),
357
+ 'CF'=>array('name'=>'CENTRAL AFRICAN REPUBLIC','code'=>'236'),
358
+ 'CG'=>array('name'=>'CONGO','code'=>'242'),
359
+ 'CH'=>array('name'=>'SWITZERLAND','code'=>'41'),
360
+ 'CI'=>array('name'=>'COTE D IVOIRE','code'=>'225'),
361
+ 'CK'=>array('name'=>'COOK ISLANDS','code'=>'682'),
362
+ 'CL'=>array('name'=>'CHILE','code'=>'56'),
363
+ 'CM'=>array('name'=>'CAMEROON','code'=>'237'),
364
+ 'CN'=>array('name'=>'CHINA','code'=>'86'),
365
+ 'CO'=>array('name'=>'COLOMBIA','code'=>'57'),
366
+ 'CR'=>array('name'=>'COSTA RICA','code'=>'506'),
367
+ 'CU'=>array('name'=>'CUBA','code'=>'53'),
368
+ 'CV'=>array('name'=>'CAPE VERDE','code'=>'238'),
369
+ 'CX'=>array('name'=>'CHRISTMAS ISLAND','code'=>'61'),
370
+ 'CY'=>array('name'=>'CYPRUS','code'=>'357'),
371
+ 'CZ'=>array('name'=>'CZECH REPUBLIC','code'=>'420'),
372
+ 'DE'=>array('name'=>'GERMANY','code'=>'49'),
373
+ 'DJ'=>array('name'=>'DJIBOUTI','code'=>'253'),
374
+ 'DK'=>array('name'=>'DENMARK','code'=>'45'),
375
+ 'DM'=>array('name'=>'DOMINICA','code'=>'1767'),
376
+ 'DO'=>array('name'=>'DOMINICAN REPUBLIC','code'=>'1809'),
377
+ 'DZ'=>array('name'=>'ALGERIA','code'=>'213'),
378
+ 'EC'=>array('name'=>'ECUADOR','code'=>'593'),
379
+ 'EE'=>array('name'=>'ESTONIA','code'=>'372'),
380
+ 'EG'=>array('name'=>'EGYPT','code'=>'20'),
381
+ 'ER'=>array('name'=>'ERITREA','code'=>'291'),
382
+ 'ES'=>array('name'=>'SPAIN','code'=>'34'),
383
+ 'ET'=>array('name'=>'ETHIOPIA','code'=>'251'),
384
+ 'FI'=>array('name'=>'FINLAND','code'=>'358'),
385
+ 'FJ'=>array('name'=>'FIJI','code'=>'679'),
386
+ 'FK'=>array('name'=>'FALKLAND ISLANDS (MALVINAS)','code'=>'500'),
387
+ 'FM'=>array('name'=>'MICRONESIA, FEDERATED STATES OF','code'=>'691'),
388
+ 'FO'=>array('name'=>'FAROE ISLANDS','code'=>'298'),
389
+ 'FR'=>array('name'=>'FRANCE','code'=>'33'),
390
+ 'GA'=>array('name'=>'GABON','code'=>'241'),
391
+ 'GB'=>array('name'=>'UNITED KINGDOM','code'=>'44'),
392
+ 'GD'=>array('name'=>'GRENADA','code'=>'1473'),
393
+ 'GE'=>array('name'=>'GEORGIA','code'=>'995'),
394
+ 'GH'=>array('name'=>'GHANA','code'=>'233'),
395
+ 'GI'=>array('name'=>'GIBRALTAR','code'=>'350'),
396
+ 'GL'=>array('name'=>'GREENLAND','code'=>'299'),
397
+ 'GM'=>array('name'=>'GAMBIA','code'=>'220'),
398
+ 'GN'=>array('name'=>'GUINEA','code'=>'224'),
399
+ 'GQ'=>array('name'=>'EQUATORIAL GUINEA','code'=>'240'),
400
+ 'GR'=>array('name'=>'GREECE','code'=>'30'),
401
+ 'GT'=>array('name'=>'GUATEMALA','code'=>'502'),
402
+ 'GU'=>array('name'=>'GUAM','code'=>'1671'),
403
+ 'GW'=>array('name'=>'GUINEA-BISSAU','code'=>'245'),
404
+ 'GY'=>array('name'=>'GUYANA','code'=>'592'),
405
+ 'HK'=>array('name'=>'HONG KONG','code'=>'852'),
406
+ 'HN'=>array('name'=>'HONDURAS','code'=>'504'),
407
+ 'HR'=>array('name'=>'CROATIA','code'=>'385'),
408
+ 'HT'=>array('name'=>'HAITI','code'=>'509'),
409
+ 'HU'=>array('name'=>'HUNGARY','code'=>'36'),
410
+ 'ID'=>array('name'=>'INDONESIA','code'=>'62'),
411
+ 'IE'=>array('name'=>'IRELAND','code'=>'353'),
412
+ 'IL'=>array('name'=>'ISRAEL','code'=>'972'),
413
+ 'IM'=>array('name'=>'ISLE OF MAN','code'=>'44'),
414
+ 'IN'=>array('name'=>'INDIA','code'=>'91'),
415
+ 'IQ'=>array('name'=>'IRAQ','code'=>'964'),
416
+ 'IR'=>array('name'=>'IRAN, ISLAMIC REPUBLIC OF','code'=>'98'),
417
+ 'IS'=>array('name'=>'ICELAND','code'=>'354'),
418
+ 'IT'=>array('name'=>'ITALY','code'=>'39'),
419
+ 'JM'=>array('name'=>'JAMAICA','code'=>'1876'),
420
+ 'JO'=>array('name'=>'JORDAN','code'=>'962'),
421
+ 'JP'=>array('name'=>'JAPAN','code'=>'81'),
422
+ 'KE'=>array('name'=>'KENYA','code'=>'254'),
423
+ 'KG'=>array('name'=>'KYRGYZSTAN','code'=>'996'),
424
+ 'KH'=>array('name'=>'CAMBODIA','code'=>'855'),
425
+ 'KI'=>array('name'=>'KIRIBATI','code'=>'686'),
426
+ 'KM'=>array('name'=>'COMOROS','code'=>'269'),
427
+ 'KN'=>array('name'=>'SAINT KITTS AND NEVIS','code'=>'1869'),
428
+ 'KP'=>array('name'=>'KOREA DEMOCRATIC PEOPLES REPUBLIC OF','code'=>'850'),
429
+ 'KR'=>array('name'=>'KOREA REPUBLIC OF','code'=>'82'),
430
+ 'KW'=>array('name'=>'KUWAIT','code'=>'965'),
431
+ 'KY'=>array('name'=>'CAYMAN ISLANDS','code'=>'1345'),
432
+ 'KZ'=>array('name'=>'KAZAKSTAN','code'=>'7'),
433
+ 'LA'=>array('name'=>'LAO PEOPLES DEMOCRATIC REPUBLIC','code'=>'856'),
434
+ 'LB'=>array('name'=>'LEBANON','code'=>'961'),
435
+ 'LC'=>array('name'=>'SAINT LUCIA','code'=>'1758'),
436
+ 'LI'=>array('name'=>'LIECHTENSTEIN','code'=>'423'),
437
+ 'LK'=>array('name'=>'SRI LANKA','code'=>'94'),
438
+ 'LR'=>array('name'=>'LIBERIA','code'=>'231'),
439
+ 'LS'=>array('name'=>'LESOTHO','code'=>'266'),
440
+ 'LT'=>array('name'=>'LITHUANIA','code'=>'370'),
441
+ 'LU'=>array('name'=>'LUXEMBOURG','code'=>'352'),
442
+ 'LV'=>array('name'=>'LATVIA','code'=>'371'),
443
+ 'LY'=>array('name'=>'LIBYAN ARAB JAMAHIRIYA','code'=>'218'),
444
+ 'MA'=>array('name'=>'MOROCCO','code'=>'212'),
445
+ 'MC'=>array('name'=>'MONACO','code'=>'377'),
446
+ 'MD'=>array('name'=>'MOLDOVA, REPUBLIC OF','code'=>'373'),
447
+ 'ME'=>array('name'=>'MONTENEGRO','code'=>'382'),
448
+ 'MF'=>array('name'=>'SAINT MARTIN','code'=>'1599'),
449
+ 'MG'=>array('name'=>'MADAGASCAR','code'=>'261'),
450
+ 'MH'=>array('name'=>'MARSHALL ISLANDS','code'=>'692'),
451
+ 'MK'=>array('name'=>'MACEDONIA, THE FORMER YUGOSLAV REPUBLIC OF','code'=>'389'),
452
+ 'ML'=>array('name'=>'MALI','code'=>'223'),
453
+ 'MM'=>array('name'=>'MYANMAR','code'=>'95'),
454
+ 'MN'=>array('name'=>'MONGOLIA','code'=>'976'),
455
+ 'MO'=>array('name'=>'MACAU','code'=>'853'),
456
+ 'MP'=>array('name'=>'NORTHERN MARIANA ISLANDS','code'=>'1670'),
457
+ 'MR'=>array('name'=>'MAURITANIA','code'=>'222'),
458
+ 'MS'=>array('name'=>'MONTSERRAT','code'=>'1664'),
459
+ 'MT'=>array('name'=>'MALTA','code'=>'356'),
460
+ 'MU'=>array('name'=>'MAURITIUS','code'=>'230'),
461
+ 'MV'=>array('name'=>'MALDIVES','code'=>'960'),
462
+ 'MW'=>array('name'=>'MALAWI','code'=>'265'),
463
+ 'MX'=>array('name'=>'MEXICO','code'=>'52'),
464
+ 'MY'=>array('name'=>'MALAYSIA','code'=>'60'),
465
+ 'MZ'=>array('name'=>'MOZAMBIQUE','code'=>'258'),
466
+ 'NA'=>array('name'=>'NAMIBIA','code'=>'264'),
467
+ 'NC'=>array('name'=>'NEW CALEDONIA','code'=>'687'),
468
+ 'NE'=>array('name'=>'NIGER','code'=>'227'),
469
+ 'NG'=>array('name'=>'NIGERIA','code'=>'234'),
470
+ 'NI'=>array('name'=>'NICARAGUA','code'=>'505'),
471
+ 'NL'=>array('name'=>'NETHERLANDS','code'=>'31'),
472
+ 'NO'=>array('name'=>'NORWAY','code'=>'47'),
473
+ 'NP'=>array('name'=>'NEPAL','code'=>'977'),
474
+ 'NR'=>array('name'=>'NAURU','code'=>'674'),
475
+ 'NU'=>array('name'=>'NIUE','code'=>'683'),
476
+ 'NZ'=>array('name'=>'NEW ZEALAND','code'=>'64'),
477
+ 'OM'=>array('name'=>'OMAN','code'=>'968'),
478
+ 'PA'=>array('name'=>'PANAMA','code'=>'507'),
479
+ 'PE'=>array('name'=>'PERU','code'=>'51'),
480
+ 'PF'=>array('name'=>'FRENCH POLYNESIA','code'=>'689'),
481
+ 'PG'=>array('name'=>'PAPUA NEW GUINEA','code'=>'675'),
482
+ 'PH'=>array('name'=>'PHILIPPINES','code'=>'63'),
483
+ 'PK'=>array('name'=>'PAKISTAN','code'=>'92'),
484
+ 'PL'=>array('name'=>'POLAND','code'=>'48'),
485
+ 'PM'=>array('name'=>'SAINT PIERRE AND MIQUELON','code'=>'508'),
486
+ 'PN'=>array('name'=>'PITCAIRN','code'=>'870'),
487
+ 'PR'=>array('name'=>'PUERTO RICO','code'=>'1'),
488
+ 'PT'=>array('name'=>'PORTUGAL','code'=>'351'),
489
+ 'PW'=>array('name'=>'PALAU','code'=>'680'),
490
+ 'PY'=>array('name'=>'PARAGUAY','code'=>'595'),
491
+ 'QA'=>array('name'=>'QATAR','code'=>'974'),
492
+ 'RO'=>array('name'=>'ROMANIA','code'=>'40'),
493
+ 'RS'=>array('name'=>'SERBIA','code'=>'381'),
494
+ 'RU'=>array('name'=>'RUSSIAN FEDERATION','code'=>'7'),
495
+ 'RW'=>array('name'=>'RWANDA','code'=>'250'),
496
+ 'SA'=>array('name'=>'SAUDI ARABIA','code'=>'966'),
497
+ 'SB'=>array('name'=>'SOLOMON ISLANDS','code'=>'677'),
498
+ 'SC'=>array('name'=>'SEYCHELLES','code'=>'248'),
499
+ 'SD'=>array('name'=>'SUDAN','code'=>'249'),
500
+ 'SE'=>array('name'=>'SWEDEN','code'=>'46'),
501
+ 'SG'=>array('name'=>'SINGAPORE','code'=>'65'),
502
+ 'SH'=>array('name'=>'SAINT HELENA','code'=>'290'),
503
+ 'SI'=>array('name'=>'SLOVENIA','code'=>'386'),
504
+ 'SK'=>array('name'=>'SLOVAKIA','code'=>'421'),
505
+ 'SL'=>array('name'=>'SIERRA LEONE','code'=>'232'),
506
+ 'SM'=>array('name'=>'SAN MARINO','code'=>'378'),
507
+ 'SN'=>array('name'=>'SENEGAL','code'=>'221'),
508
+ 'SO'=>array('name'=>'SOMALIA','code'=>'252'),
509
+ 'SR'=>array('name'=>'SURINAME','code'=>'597'),
510
+ 'ST'=>array('name'=>'SAO TOME AND PRINCIPE','code'=>'239'),
511
+ 'SV'=>array('name'=>'EL SALVADOR','code'=>'503'),
512
+ 'SY'=>array('name'=>'SYRIAN ARAB REPUBLIC','code'=>'963'),
513
+ 'SZ'=>array('name'=>'SWAZILAND','code'=>'268'),
514
+ 'TC'=>array('name'=>'TURKS AND CAICOS ISLANDS','code'=>'1649'),
515
+ 'TD'=>array('name'=>'CHAD','code'=>'235'),
516
+ 'TG'=>array('name'=>'TOGO','code'=>'228'),
517
+ 'TH'=>array('name'=>'THAILAND','code'=>'66'),
518
+ 'TJ'=>array('name'=>'TAJIKISTAN','code'=>'992'),
519
+ 'TK'=>array('name'=>'TOKELAU','code'=>'690'),
520
+ 'TL'=>array('name'=>'TIMOR-LESTE','code'=>'670'),
521
+ 'TM'=>array('name'=>'TURKMENISTAN','code'=>'993'),
522
+ 'TN'=>array('name'=>'TUNISIA','code'=>'216'),
523
+ 'TO'=>array('name'=>'TONGA','code'=>'676'),
524
+ 'TR'=>array('name'=>'TURKEY','code'=>'90'),
525
+ 'TT'=>array('name'=>'TRINIDAD AND TOBAGO','code'=>'1868'),
526
+ 'TV'=>array('name'=>'TUVALU','code'=>'688'),
527
+ 'TW'=>array('name'=>'TAIWAN, PROVINCE OF CHINA','code'=>'886'),
528
+ 'TZ'=>array('name'=>'TANZANIA, UNITED REPUBLIC OF','code'=>'255'),
529
+ 'UA'=>array('name'=>'UKRAINE','code'=>'380'),
530
+ 'UG'=>array('name'=>'UGANDA','code'=>'256'),
531
+ 'US'=>array('name'=>'UNITED STATES','code'=>'1'),
532
+ 'UY'=>array('name'=>'URUGUAY','code'=>'598'),
533
+ 'UZ'=>array('name'=>'UZBEKISTAN','code'=>'998'),
534
+ 'VA'=>array('name'=>'HOLY SEE (VATICAN CITY STATE)','code'=>'39'),
535
+ 'VC'=>array('name'=>'SAINT VINCENT AND THE GRENADINES','code'=>'1784'),
536
+ 'VE'=>array('name'=>'VENEZUELA','code'=>'58'),
537
+ 'VG'=>array('name'=>'VIRGIN ISLANDS, BRITISH','code'=>'1284'),
538
+ 'VI'=>array('name'=>'VIRGIN ISLANDS, U.S.','code'=>'1340'),
539
+ 'VN'=>array('name'=>'VIET NAM','code'=>'84'),
540
+ 'VU'=>array('name'=>'VANUATU','code'=>'678'),
541
+ 'WF'=>array('name'=>'WALLIS AND FUTUNA','code'=>'681'),
542
+ 'WS'=>array('name'=>'SAMOA','code'=>'685'),
543
+ 'XK'=>array('name'=>'KOSOVO','code'=>'381'),
544
+ 'YE'=>array('name'=>'YEMEN','code'=>'967'),
545
+ 'YT'=>array('name'=>'MAYOTTE','code'=>'262'),
546
+ 'ZA'=>array('name'=>'SOUTH AFRICA','code'=>'27'),
547
+ 'ZM'=>array('name'=>'ZAMBIA','code'=>'260'),
548
+ 'ZW'=>array('name'=>'ZIMBABWE','code'=>'263')
549
+ );
550
+
551
+ return $phone_countries;
552
+ }
553
+
554
+ /**
555
+ * Sanitize submitted value before storing it.
556
+ *
557
+ * @since 1.0.0.
558
+ *
559
+ * @param array $part_data Form part data.
560
+ *
561
+ * @return string
562
+ */
563
+ public function sanitize_value( $part_data = array() ) {
564
+ $sanitized_value = $this->get_default_value();
565
+ $part_id = $part_data['id'];
566
+
567
+ if ( isset( $_REQUEST[$part_id] ) ) {
568
+ $sanitized_value = sanitize_text_field( $_REQUEST[$part_id] );
569
+ }
570
+
571
+ if ( isset( $_REQUEST[$part_id . '_confirmation'] ) ) {
572
+ $sanitized_value = array(
573
+ $sanitized_value,
574
+ sanitize_text_field( $_REQUEST[$part_id . '_confirmation'] )
575
+ );
576
+ }
577
+
578
+ return $sanitized_value;
579
+ }
580
+
581
+ /**
582
+ * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
583
+ *
584
+ * @since 1.0.0.
585
+ *
586
+ * @param array $part_data Form part data.
587
+ * @param string $value Submitted value.
588
+ *
589
+ * @return string|object
590
+ */
591
+ public function validate_value( $part_data, $value ) {
592
+ $part_id = $part_data['id'];
593
+ $validated_value = $value;
594
+ $has_confirmation_value = false;
595
+
596
+ if ( is_array( $validated_value ) ) {
597
+ $has_confirmation_value = true;
598
+ $validated_confirmation_value = $validated_value[1];
599
+ $validated_value = $validated_value[0];
600
+ } else {
601
+ $validated_confirmation_value = $validated_value;
602
+ }
603
+
604
+ if ( 1 === $part_data['required'] && empty( $validated_value ) ) {
605
+ $validated_value = new WP_Error( $part_id, 'missing_required_field' );
606
+ }
607
+
608
+ if ( true === $has_confirmation_value ) {
609
+ if ( 1 === $part_data['required'] && empty( $validated_confirmation_value ) ) {
610
+ $validated_value = new WP_Error( $part_id, 'missing_required_confirmation_field' );
611
+ }
612
+
613
+ if ( $validated_value !== $validated_confirmation_value ) {
614
+ $validated_value = new WP_Error( $part_id, 'numbers_not_matching' );
615
+ }
616
+ }
617
+
618
+ return $validated_value;
619
+ }
620
+
621
+ /**
622
+ * Enqueue scripts in customizer area.
623
+ *
624
+ * @since 1.0.0.
625
+ *
626
+ * @param array List of dependencies.
627
+ *
628
+ * @return void
629
+ */
630
+ public function customize_enqueue_scripts( $deps = array() ) {
631
+ wp_enqueue_script(
632
+ 'part-phone',
633
+ happyforms_get_plugin_url() . 'assets/js/parts/part-phone.js',
634
+ $deps,
635
+ false,
636
+ true
637
+ );
638
+ }
639
+
640
+ }
inc/classes/parts/class-part-placeholder.php CHANGED
@@ -67,6 +67,11 @@ class HappyForms_Part_Placeholder extends HappyForms_Form_Part {
67
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
68
  </select>
69
  </p>
 
 
 
 
 
70
  <p>
71
  <label for="<%= instance.id %>_placeholder_text"><?php _e( 'Text', 'happyforms' ); ?></label>
72
  <textarea id="<%= instance.id %>_placeholder_text" class="widefat title" name="placeholder_text" data-bind="placeholder_text"><%= instance.placeholder_text %></textarea>
@@ -79,6 +84,11 @@ class HappyForms_Part_Placeholder extends HappyForms_Form_Part {
79
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
80
  </select>
81
  </p>
 
 
 
 
 
82
  <p>
83
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
84
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -99,21 +109,23 @@ class HappyForms_Part_Placeholder extends HappyForms_Form_Part {
99
  public function frontend_template( $part_data = array(), $form_data = array() ) {
100
  $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
101
 
102
- $classes = ' ';
103
 
104
  if ( $part_data['width'] ) {
105
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
106
  }
107
 
108
  if ( $part_data['label_placement'] ) {
109
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
110
  }
111
 
112
  if ( !empty( $part_data['css_class'] ) ) {
113
- $classes .= $part_data['css_class'];
114
  }
 
 
115
  ?>
116
- <div class="happyforms-part happyforms-part--placeholder happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
117
  <div class="happyforms-part__wrap">
118
  <label class="happyforms-part__label">
119
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
67
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
68
  </select>
69
  </p>
70
+ <p class="label_placement-options" style="display: none">
71
+ <label>
72
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
73
+ </label>
74
+ </p>
75
  <p>
76
  <label for="<%= instance.id %>_placeholder_text"><?php _e( 'Text', 'happyforms' ); ?></label>
77
  <textarea id="<%= instance.id %>_placeholder_text" class="widefat title" name="placeholder_text" data-bind="placeholder_text"><%= instance.placeholder_text %></textarea>
84
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
85
  </select>
86
  </p>
87
+ <p class="width-options" style="display: none">
88
+ <label>
89
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
90
+ </label>
91
+ </p>
92
  <p>
93
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
94
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
109
  public function frontend_template( $part_data = array(), $form_data = array() ) {
110
  $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
111
 
112
+ $classes = array('happyforms-part--placeholder');
113
 
114
  if ( $part_data['width'] ) {
115
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
116
  }
117
 
118
  if ( $part_data['label_placement'] ) {
119
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
120
  }
121
 
122
  if ( !empty( $part_data['css_class'] ) ) {
123
+ $classes[] = $part_data['css_class'];
124
  }
125
+
126
+ $classes = implode( ' ', $classes );
127
  ?>
128
+ <div class="happyforms-part happyforms-part--placeholder happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
129
  <div class="happyforms-part__wrap">
130
  <label class="happyforms-part__label">
131
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
inc/classes/parts/class-part-radio.php CHANGED
@@ -14,9 +14,9 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
14
 
15
  /**
16
  * Get all part meta fields defaults.
17
- *
18
  * @since 1.0.0.
19
- *
20
  * @return array
21
  */
22
  public function get_customize_fields() {
@@ -37,6 +37,10 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
37
  'default' => '',
38
  'sanitize' => 'sanitize_text_field'
39
  ),
 
 
 
 
40
  'width' => array(
41
  'default' => 'full',
42
  'sanitize' => 'sanitize_key'
@@ -46,7 +50,7 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
46
  'sanitize' => 'sanitize_text_field'
47
  ),
48
  'display_type' => array(
49
- 'default' => 'inline',
50
  'sanitize' => 'sanitize_text_field'
51
  ),
52
  'required' => array(
@@ -62,23 +66,24 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
62
 
63
  /**
64
  * Get part option (sub-part) defaults.
65
- *
66
  * @since 1.0.0.
67
- *
68
  * @return array
69
  */
70
  public function get_option_defaults() {
71
  return array(
72
  'is_default' => 0,
73
- 'label' => ''
 
74
  );
75
  }
76
 
77
  /**
78
  * Get template for part item in customize pane.
79
- *
80
  * @since 1.0.0.
81
- *
82
  * @return string
83
  */
84
  public function customize_template() {
@@ -95,10 +100,20 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
95
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
96
  </select>
97
  </p>
 
 
 
 
 
98
  <p>
99
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
100
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
101
  </p>
 
 
 
 
 
102
  <p>
103
  <label for="<%= instance.id %>_display_type"><?php _e( 'Display options', 'happyforms' ); ?></label>
104
  <select id="<%= instance.id %>_display_type" name="display_type" data-bind="display_type" class="widefat">
@@ -114,6 +129,11 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
114
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
115
  </select>
116
  </p>
 
 
 
 
 
117
  <p>
118
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
119
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -137,9 +157,9 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
137
 
138
  /**
139
  * Get template for option / sub-part item in customize pane.
140
- *
141
  * @since 1.0.0.
142
- *
143
  * @return string
144
  */
145
  public function customize_item_template() {
@@ -149,6 +169,10 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
149
  <?php _e( 'Label', 'happyforms' ); ?>
150
  <input type="text" class="widefat" name="" value="<%= label %>" data-option-attribute="label" data-preview-selector=".label">
151
  </label>
 
 
 
 
152
  <label>
153
  <input type="checkbox" name="" value="1" class="default-option-switch"<% if (is_default == 1) { %> checked="checked"<% } %>> <?php _e( 'Make this option default', 'happyforms' ); ?>
154
  </label>
@@ -161,41 +185,39 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
161
 
162
  /**
163
  * Get front end part template with parsed data.
164
- *
165
  * @since 1.0.0.
166
- *
167
  * @param array $part_data Form part data.
168
  * @param array $form_data Form (post) data.
169
- *
170
  * @return string Markup for the form part.
171
  */
172
  public function frontend_template( $part_data = array(), $form_data = array() ) {
173
  $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
174
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
175
- $classes = ' ';
 
176
 
177
  if ( $part_data['width'] ) {
178
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
179
  }
180
 
181
  if ( $part_data['display_type'] == 'block') {
182
- $classes .= 'display-type--block ';
183
  }
184
 
185
  if ( $part_data['label_placement'] ) {
186
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
187
  }
188
 
189
  if ( !empty( $part_data['css_class'] ) ) {
190
- $classes .= $part_data['css_class'];
191
  }
 
 
192
  ?>
193
- <div class="happyforms-part happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
194
- <?php
195
- if ( $form_data ) :
196
- happyforms_message_notices( $form_data, $part_data['id'] );
197
- endif;
198
- ?>
199
  <div class="happyforms-part__wrap">
200
  <label class="happyforms-part__label">
201
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
@@ -203,7 +225,6 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
203
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
204
  <?php endif; ?>
205
  </label>
206
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
207
  <div class="happyforms-part__el">
208
  <?php
209
  if ( isset( $part_data['options']) ) {
@@ -212,11 +233,17 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
212
  foreach( $options as $option ) {
213
  $option = wp_parse_args( $option, $this->get_option_defaults() );
214
 
215
- $this->frontend_item_template( $part_data, $option, $part_data['required'] );
216
  }
217
  }
218
  ?>
219
  </div>
 
 
 
 
 
 
220
  </div>
221
  </div>
222
  <?php
@@ -224,45 +251,64 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
224
 
225
  /**
226
  * Get front end option (sub-part) template with parsed data.
227
- *
228
  * @since 1.0.0.
229
- *
230
  * @param array $part_data Form part data.
231
  * @param array $option Option (form sub-part) data.
232
  * @param int $requred Required field (1) or not.
233
- *
234
  * @return string Markup for the part option.
235
  */
236
- public function frontend_item_template( $part_data, $option, $required ) {
237
  ?>
238
- <label class="option-label" id="<?php echo esc_attr( $option['id'] ); ?>">
239
- <input type="radio" name="<?php echo esc_attr( $part_data['id'] ); ?>" value="<?php echo esc_attr( $option['label'] ); ?>"<?php if ( $option['is_default'] == 1 ) : ?> checked<?php endif; ?><?php if ( 1 === intval( $required ) ) : ?> required aria-required="true"<?php endif; ?>> <span class="label"><?php echo esc_attr( $option['label'] ); ?></span>
240
- </label>
 
 
 
 
 
 
 
 
 
 
 
 
 
241
  <?php
242
  }
243
 
244
  /**
245
  * Get option's Backbone template for preview purposes. Passed to previewer to create a new Backbone view.
246
- *
247
  * @since 1.0.0.
248
- *
249
  * @return string Backbone template.
250
  */
251
  public function preview_option_template() {
252
  ?>
253
- <label class="option-label" id="<%= id %>">
254
- <input type="radio" name="" value="<%= label %>"> <span class="label"><%= label %></span>
255
- </label>
 
 
 
 
 
 
256
  <?php
257
  }
258
 
259
  /**
260
  * Enqueue scripts in customizer area.
261
- *
262
  * @since 1.0.0.
263
- *
264
  * @param array List of dependencies.
265
- *
266
  * @return void
267
  */
268
  public function customize_enqueue_scripts( $deps = array() ) {
@@ -277,9 +323,9 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
277
 
278
  /**
279
  * Get all possible messages definitions.
280
- *
281
  * @since 1.0.0.
282
- *
283
  * @return array Associative array, specifying message type and copy.
284
  */
285
  public function get_message_definitions() {
@@ -297,11 +343,11 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
297
 
298
  /**
299
  * Sanitize submitted value before storing it.
300
- *
301
  * @since 1.0.0.
302
- *
303
  * @param array $part_data Form part data.
304
- *
305
  * @return string
306
  */
307
  public function sanitize_value( $part_data = array() ) {
@@ -317,12 +363,12 @@ class HappyForms_Part_Radio extends HappyForms_Form_Part {
317
 
318
  /**
319
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
320
- *
321
  * @since 1.0.0.
322
- *
323
  * @param array $part_data Form part data.
324
  * @param string $value Submitted value.
325
- *
326
  * @return string|object
327
  */
328
  public function validate_value( $part_data, $value ) {
14
 
15
  /**
16
  * Get all part meta fields defaults.
17
+ *
18
  * @since 1.0.0.
19
+ *
20
  * @return array
21
  */
22
  public function get_customize_fields() {
37
  'default' => '',
38
  'sanitize' => 'sanitize_text_field'
39
  ),
40
+ 'tooltip_description' => array(
41
+ 'default' => 0,
42
+ 'sanitize' => 'happyforms_sanitize_checkbox'
43
+ ),
44
  'width' => array(
45
  'default' => 'full',
46
  'sanitize' => 'sanitize_key'
50
  'sanitize' => 'sanitize_text_field'
51
  ),
52
  'display_type' => array(
53
+ 'default' => 'block',
54
  'sanitize' => 'sanitize_text_field'
55
  ),
56
  'required' => array(
66
 
67
  /**
68
  * Get part option (sub-part) defaults.
69
+ *
70
  * @since 1.0.0.
71
+ *
72
  * @return array
73
  */
74
  public function get_option_defaults() {
75
  return array(
76
  'is_default' => 0,
77
+ 'label' => '',
78
+ 'description' => ''
79
  );
80
  }
81
 
82
  /**
83
  * Get template for part item in customize pane.
84
+ *
85
  * @since 1.0.0.
86
+ *
87
  * @return string
88
  */
89
  public function customize_template() {
100
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
101
  </select>
102
  </p>
103
+ <p class="label_placement-options" style="display: none">
104
+ <label>
105
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
106
+ </label>
107
+ </p>
108
  <p>
109
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
110
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
111
  </p>
112
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
113
+ <label>
114
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
115
+ </label>
116
+ </p>
117
  <p>
118
  <label for="<%= instance.id %>_display_type"><?php _e( 'Display options', 'happyforms' ); ?></label>
119
  <select id="<%= instance.id %>_display_type" name="display_type" data-bind="display_type" class="widefat">
129
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
130
  </select>
131
  </p>
132
+ <p class="width-options" style="display: none">
133
+ <label>
134
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
135
+ </label>
136
+ </p>
137
  <p>
138
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
139
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
157
 
158
  /**
159
  * Get template for option / sub-part item in customize pane.
160
+ *
161
  * @since 1.0.0.
162
+ *
163
  * @return string
164
  */
165
  public function customize_item_template() {
169
  <?php _e( 'Label', 'happyforms' ); ?>
170
  <input type="text" class="widefat" name="" value="<%= label %>" data-option-attribute="label" data-preview-selector=".label">
171
  </label>
172
+ <label class="happyforms-part-item-description">
173
+ <?php _e( 'Description', 'happyforms' ); ?>
174
+ <input type="text" class="widefat" name="" value="<%= (typeof description !== 'undefined') ? description : '' %>" data-option-attribute="description" data-preview-selector=".happyforms-part-option__description">
175
+ </label>
176
  <label>
177
  <input type="checkbox" name="" value="1" class="default-option-switch"<% if (is_default == 1) { %> checked="checked"<% } %>> <?php _e( 'Make this option default', 'happyforms' ); ?>
178
  </label>
185
 
186
  /**
187
  * Get front end part template with parsed data.
188
+ *
189
  * @since 1.0.0.
190
+ *
191
  * @param array $part_data Form part data.
192
  * @param array $form_data Form (post) data.
193
+ *
194
  * @return string Markup for the form part.
195
  */
196
  public function frontend_template( $part_data = array(), $form_data = array() ) {
197
  $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
198
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
199
+
200
+ $classes = array('happyforms-part--radio');
201
 
202
  if ( $part_data['width'] ) {
203
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
204
  }
205
 
206
  if ( $part_data['display_type'] == 'block') {
207
+ $classes[] = 'display-type--block ';
208
  }
209
 
210
  if ( $part_data['label_placement'] ) {
211
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
212
  }
213
 
214
  if ( !empty( $part_data['css_class'] ) ) {
215
+ $classes[] = $part_data['css_class'];
216
  }
217
+
218
+ $classes = implode( ' ', $classes );
219
  ?>
220
+ <div class="happyforms-part happyforms-part--radio happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
221
  <div class="happyforms-part__wrap">
222
  <label class="happyforms-part__label">
223
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
225
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
226
  <?php endif; ?>
227
  </label>
 
228
  <div class="happyforms-part__el">
229
  <?php
230
  if ( isset( $part_data['options']) ) {
233
  foreach( $options as $option ) {
234
  $option = wp_parse_args( $option, $this->get_option_defaults() );
235
 
236
+ $this->frontend_item_template( $part_data, $option, $part_data['required'], $form_data );
237
  }
238
  }
239
  ?>
240
  </div>
241
+ <?php happyforms_print_part_description( $part_data ); ?>
242
+ <?php
243
+ if ( $form_data ) :
244
+ happyforms_message_notices( $form_data, $part_data['id'] );
245
+ endif;
246
+ ?>
247
  </div>
248
  </div>
249
  <?php
251
 
252
  /**
253
  * Get front end option (sub-part) template with parsed data.
254
+ *
255
  * @since 1.0.0.
256
+ *
257
  * @param array $part_data Form part data.
258
  * @param array $option Option (form sub-part) data.
259
  * @param int $requred Required field (1) or not.
260
+ *
261
  * @return string Markup for the part option.
262
  */
263
+ public function frontend_item_template( $part_data, $option, $required, $form_data = array() ) {
264
  ?>
265
+ <div class="happyforms-part__option happyforms-part-option" id="<?php echo esc_attr( $option['id'] ); ?>">
266
+ <label class="option-label">
267
+ <input type="radio" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" value="<?php echo esc_attr( $option['label'] ); ?>"<?php if ( $option['is_default'] == 1 ) : ?> checked<?php endif; ?><?php if ( 1 === intval( $required ) ) : ?> required aria-required="true"<?php endif; ?>>
268
+ <span class="checkmark"></span>
269
+ <span class="border"></span>
270
+
271
+ <?php if ( is_customize_preview() || !empty( $option['label'] ) ) : ?>
272
+ <span class="label"><?php echo esc_attr( $option['label'] ); ?></span>
273
+ <?php endif; ?>
274
+ </label>
275
+ <?php if ( is_customize_preview() || !empty( $option['description'] ) ) : ?>
276
+ <span class="happyforms-part-option__description">
277
+ <?php echo esc_attr( $option['description'] ); ?>
278
+ </span>
279
+ <?php endif; ?>
280
+ </div>
281
  <?php
282
  }
283
 
284
  /**
285
  * Get option's Backbone template for preview purposes. Passed to previewer to create a new Backbone view.
286
+ *
287
  * @since 1.0.0.
288
+ *
289
  * @return string Backbone template.
290
  */
291
  public function preview_option_template() {
292
  ?>
293
+ <div class="happyforms-part__option happyforms-part-option">
294
+ <label class="option-label" id="<%= id %>">
295
+ <input type="radio" name="" value="<%= label %>">
296
+ <span class="checkmark"></span>
297
+ <span class="border"></span>
298
+ <span class="label"><%= label %></span>
299
+ </label>
300
+ <span class="happyforms-part-option__description"><%= description %></span>
301
+ </div>
302
  <?php
303
  }
304
 
305
  /**
306
  * Enqueue scripts in customizer area.
307
+ *
308
  * @since 1.0.0.
309
+ *
310
  * @param array List of dependencies.
311
+ *
312
  * @return void
313
  */
314
  public function customize_enqueue_scripts( $deps = array() ) {
323
 
324
  /**
325
  * Get all possible messages definitions.
326
+ *
327
  * @since 1.0.0.
328
+ *
329
  * @return array Associative array, specifying message type and copy.
330
  */
331
  public function get_message_definitions() {
343
 
344
  /**
345
  * Sanitize submitted value before storing it.
346
+ *
347
  * @since 1.0.0.
348
+ *
349
  * @param array $part_data Form part data.
350
+ *
351
  * @return string
352
  */
353
  public function sanitize_value( $part_data = array() ) {
363
 
364
  /**
365
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
366
+ *
367
  * @since 1.0.0.
368
+ *
369
  * @param array $part_data Form part data.
370
  * @param string $value Submitted value.
371
+ *
372
  * @return string|object
373
  */
374
  public function validate_value( $part_data, $value ) {
inc/classes/parts/class-part-rating.php CHANGED
@@ -12,9 +12,9 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
- *
16
  * @since 1.0.0.
17
- *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
@@ -35,6 +35,10 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
 
 
 
 
38
  'stars_num' => array(
39
  'default' => 5,
40
  'sanitize' => 'intval'
@@ -56,9 +60,9 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
56
 
57
  /**
58
  * Get template for part item in customize pane.
59
- *
60
  * @since 1.0.0.
61
- *
62
  * @return string
63
  */
64
  public function customize_template() {
@@ -75,10 +79,20 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
75
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
76
  </select>
77
  </p>
 
 
 
 
 
78
  <p>
79
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
80
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
81
  </p>
 
 
 
 
 
82
  <p>
83
  <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
84
  <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
@@ -87,6 +101,11 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
87
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
88
  </select>
89
  </p>
 
 
 
 
 
90
  <p>
91
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
92
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -101,12 +120,12 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
101
 
102
  /**
103
  * Get front end part template with parsed data.
104
- *
105
  * @since 1.0.0.
106
- *
107
  * @param array $part_data Form part data.
108
  * @param array $form_data Form (post) data.
109
- *
110
  * @return string Markup for the form part.
111
  */
112
  public function frontend_template( $part_data = array(), $form_data = array() ) {
@@ -114,40 +133,42 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
114
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
115
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
116
 
117
- $classes = ' ';
118
 
119
  if ( $part_data['width'] ) {
120
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
121
  }
122
 
123
  if ( $part_data['label_placement'] ) {
124
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
125
  }
126
 
127
  if ( !empty( $part_data['css_class'] ) ) {
128
- $classes .= $part_data['css_class'];
129
  }
 
 
130
  ?>
131
- <div class="happyforms-part happyforms-part--rating<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
132
- <?php
133
- if ( $form_data ) :
134
- happyforms_message_notices( $form_data, $part_data['id'] );
135
- endif;
136
- ?>
137
  <div class="happyforms-part__wrap">
138
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
139
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
140
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
141
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
142
  <?php endif; ?>
143
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
 
 
 
 
 
144
  </label>
145
 
146
  <div class="happyforms-part__el">
147
  <input class="happyforms-visuallyhidden" type="radio" value="0" id="<?php echo esc_attr( $part_data['id'] ); ?>_0" name="<?php echo esc_attr( $part_data['id'] ); ?>" checked>
148
 
149
  <?php for ( $i = 1; $i <= $part_data['stars_num']; $i++ ) { ?>
150
- <input class="happyforms-visuallyhidden star_<?php echo esc_attr( $i ); ?>" type="radio" value="<?php echo esc_attr( $i ); ?>" id="<?php echo esc_attr( $part_data['id'] ); ?>_<?php echo esc_attr( $i ); ?>" name="<?php echo esc_attr( $part_data['id'] ); ?>">
151
  <label class="happyforms-star__label" for="<?php echo esc_attr( $part_data['id'] ); ?>_<?php echo esc_attr( $i ); ?>">
152
  <span class="happyforms-visuallyhidden"><?php echo esc_attr( $i ); ?> <?php _e( 'Stars', 'happyforms' ); ?></span>
153
  <svg class="happyforms-star" viewBox="0 0 512 512" fill=""><path class="happyforms-star__star" d="M512 198.525l-176.89-25.704-79.11-160.291-79.108 160.291-176.892 25.704 128 124.769-30.216 176.176 158.216-83.179 158.216 83.179-30.217-176.176 128.001-124.769z"></path></svg>
@@ -161,9 +182,9 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
161
 
162
  /**
163
  * Get all possible messages definitions.
164
- *
165
  * @since 1.0.0.
166
- *
167
  * @return array Associative array, specifying message type and copy.
168
  */
169
  public function get_message_definitions() {
@@ -181,11 +202,11 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
181
 
182
  /**
183
  * Sanitize submitted value before storing it.
184
- *
185
  * @since 1.0.0.
186
- *
187
  * @param array $part_data Form part data.
188
- *
189
  * @return string
190
  */
191
  public function sanitize_value( $part_data = array() ) {
@@ -201,12 +222,12 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
201
 
202
  /**
203
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
204
- *
205
  * @since 1.0.0.
206
- *
207
  * @param array $part_data Form part data.
208
  * @param string $value Submitted value.
209
- *
210
  * @return string|object
211
  */
212
  public function validate_value( $part_data, $value ) {
@@ -226,11 +247,11 @@ class HappyForms_Part_Rating extends HappyForms_Form_Part {
226
 
227
  /**
228
  * Enqueue scripts in customizer area.
229
- *
230
  * @since 1.0.0.
231
- *
232
  * @param array List of dependencies.
233
- *
234
  * @return void
235
  */
236
  public function customize_enqueue_scripts( $deps = array() ) {
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
+ *
16
  * @since 1.0.0.
17
+ *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
38
+ 'tooltip_description' => array(
39
+ 'default' => 0,
40
+ 'sanitize' => 'happyforms_sanitize_checkbox'
41
+ ),
42
  'stars_num' => array(
43
  'default' => 5,
44
  'sanitize' => 'intval'
60
 
61
  /**
62
  * Get template for part item in customize pane.
63
+ *
64
  * @since 1.0.0.
65
+ *
66
  * @return string
67
  */
68
  public function customize_template() {
79
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
80
  </select>
81
  </p>
82
+ <p class="label_placement-options" style="display: none">
83
+ <label>
84
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
85
+ </label>
86
+ </p>
87
  <p>
88
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
89
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
90
  </p>
91
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
92
+ <label>
93
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
94
+ </label>
95
+ </p>
96
  <p>
97
  <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
98
  <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
101
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
102
  </select>
103
  </p>
104
+ <p class="width-options" style="display: none">
105
+ <label>
106
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
107
+ </label>
108
+ </p>
109
  <p>
110
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
111
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
120
 
121
  /**
122
  * Get front end part template with parsed data.
123
+ *
124
  * @since 1.0.0.
125
+ *
126
  * @param array $part_data Form part data.
127
  * @param array $form_data Form (post) data.
128
+ *
129
  * @return string Markup for the form part.
130
  */
131
  public function frontend_template( $part_data = array(), $form_data = array() ) {
133
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
134
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
135
 
136
+ $classes = array('happyforms-part--rating');
137
 
138
  if ( $part_data['width'] ) {
139
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
140
  }
141
 
142
  if ( $part_data['label_placement'] ) {
143
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
144
  }
145
 
146
  if ( !empty( $part_data['css_class'] ) ) {
147
+ $classes[] = $part_data['css_class'];
148
  }
149
+
150
+ $classes = implode( ' ', $classes );
151
  ?>
152
+ <div class="happyforms-part <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
153
  <div class="happyforms-part__wrap">
154
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
155
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
156
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
157
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
158
  <?php endif; ?>
159
+ <?php happyforms_print_part_description( $part_data ); ?>
160
+ <?php
161
+ if ( $form_data ) :
162
+ happyforms_message_notices( $form_data, $part_data['id'] );
163
+ endif;
164
+ ?>
165
  </label>
166
 
167
  <div class="happyforms-part__el">
168
  <input class="happyforms-visuallyhidden" type="radio" value="0" id="<?php echo esc_attr( $part_data['id'] ); ?>_0" name="<?php echo esc_attr( $part_data['id'] ); ?>" checked>
169
 
170
  <?php for ( $i = 1; $i <= $part_data['stars_num']; $i++ ) { ?>
171
+ <input class="happyforms-visuallyhidden star_<?php echo esc_attr( $i ); ?>" type="radio" value="<?php echo esc_attr( $i ); ?>" id="<?php echo esc_attr( $part_data['id'] ); ?>_<?php echo esc_attr( $i ); ?>" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>">
172
  <label class="happyforms-star__label" for="<?php echo esc_attr( $part_data['id'] ); ?>_<?php echo esc_attr( $i ); ?>">
173
  <span class="happyforms-visuallyhidden"><?php echo esc_attr( $i ); ?> <?php _e( 'Stars', 'happyforms' ); ?></span>
174
  <svg class="happyforms-star" viewBox="0 0 512 512" fill=""><path class="happyforms-star__star" d="M512 198.525l-176.89-25.704-79.11-160.291-79.108 160.291-176.892 25.704 128 124.769-30.216 176.176 158.216-83.179 158.216 83.179-30.217-176.176 128.001-124.769z"></path></svg>
182
 
183
  /**
184
  * Get all possible messages definitions.
185
+ *
186
  * @since 1.0.0.
187
+ *
188
  * @return array Associative array, specifying message type and copy.
189
  */
190
  public function get_message_definitions() {
202
 
203
  /**
204
  * Sanitize submitted value before storing it.
205
+ *
206
  * @since 1.0.0.
207
+ *
208
  * @param array $part_data Form part data.
209
+ *
210
  * @return string
211
  */
212
  public function sanitize_value( $part_data = array() ) {
222
 
223
  /**
224
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
225
+ *
226
  * @since 1.0.0.
227
+ *
228
  * @param array $part_data Form part data.
229
  * @param string $value Submitted value.
230
+ *
231
  * @return string|object
232
  */
233
  public function validate_value( $part_data, $value ) {
247
 
248
  /**
249
  * Enqueue scripts in customizer area.
250
+ *
251
  * @since 1.0.0.
252
+ *
253
  * @param array List of dependencies.
254
+ *
255
  * @return void
256
  */
257
  public function customize_enqueue_scripts( $deps = array() ) {
inc/classes/parts/class-part-scale.php ADDED
@@ -0,0 +1,372 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class HappyForms_Part_Scale extends HappyForms_Form_Part {
4
+
5
+ public $type = 'scale';
6
+ public $template_id = 'happyforms-scale-template';
7
+
8
+ public function __construct() {
9
+ $this->label = __( 'Scale', 'happyforms' );
10
+ $this->description = __( 'For collecting opinions using a horizontal slider.', 'happyforms' );
11
+
12
+ add_filter( 'happyforms_preview_dependencies', array( $this, 'preview_dependencies' ) );
13
+ add_action( 'happyforms_frontend_form_scripts', array( $this, 'frontend_enqueue_scripts' ) );
14
+ }
15
+
16
+ /**
17
+ * Get all part meta fields defaults.
18
+ *
19
+ * @since 1.0.0.
20
+ *
21
+ * @return array
22
+ */
23
+ public function get_customize_fields() {
24
+ return array(
25
+ 'type' => array(
26
+ 'default' => $this->type,
27
+ 'sanitize' => 'sanitize_text_field',
28
+ ),
29
+ 'label' => array(
30
+ 'default' => __( 'Scale', 'happyforms' ),
31
+ 'sanitize' => 'sanitize_text_field',
32
+ ),
33
+ 'label_placement' => array(
34
+ 'default' => 'above',
35
+ 'sanitize' => 'sanitize_text_field'
36
+ ),
37
+ 'description' => array(
38
+ 'default' => '',
39
+ 'sanitize' => 'sanitize_text_field'
40
+ ),
41
+ 'tooltip_description' => array(
42
+ 'default' => 0,
43
+ 'sanitize' => 'happyforms_sanitize_checkbox'
44
+ ),
45
+ 'width' => array(
46
+ 'default' => 'full',
47
+ 'sanitize' => 'sanitize_key'
48
+ ),
49
+ 'min_label' => array(
50
+ 'default' => '',
51
+ 'sanitize' => 'sanitize_text_field'
52
+ ),
53
+ 'max_label' => array(
54
+ 'default' => '',
55
+ 'sanitize' => 'sanitize_text_field'
56
+ ),
57
+ 'min_value' => array(
58
+ 'default' => 0,
59
+ 'sanitize' => 'intval'
60
+ ),
61
+ 'max_value' => array(
62
+ 'default' => 100,
63
+ 'sanitize' => 'intval'
64
+ ),
65
+ 'step' => array(
66
+ 'default' => 1,
67
+ 'sanitize' => 'sanitize_key'
68
+ ),
69
+ 'default_value' => array(
70
+ 'default' => 50,
71
+ 'sanitize' => 'intval'
72
+ ),
73
+ 'css_class' => array(
74
+ 'default' => '',
75
+ 'sanitize' => 'sanitize_text_field'
76
+ ),
77
+ 'required' => array(
78
+ 'default' => 1,
79
+ 'sanitize' => 'happyforms_sanitize_checkbox',
80
+ ),
81
+ );
82
+ }
83
+
84
+ /**
85
+ * Get template for part item in customize pane.
86
+ *
87
+ * @since 1.0.0.
88
+ *
89
+ * @return string
90
+ */
91
+ public function customize_template() {
92
+ ?>
93
+ <p>
94
+ <label for="<%= instance.id %>_title"><?php _e( 'Title', 'happyforms' ); ?></label>
95
+ <input type="text" id="<%= instance.id %>_title" class="widefat title" value="<%= instance.label %>" data-bind="label" />
96
+ </p>
97
+ <p>
98
+ <label for="<%= instance.id %>_label_placement"><?php _e( 'Title placement', 'happyforms' ); ?></label>
99
+ <select id="<%= instance.id %>_label_placement" data-bind="label_placement">
100
+ <option value="above"<%= (instance.label_placement == 'above') ? ' selected' : '' %>><?php _e( 'Above', 'happyforms' ); ?></option>
101
+ <option value="left"<%= (instance.label_placement == 'left') ? ' selected' : '' %>><?php _e( 'Left', 'happyforms' ); ?></option>
102
+ <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
103
+ </select>
104
+ </p>
105
+ <p class="label_placement-options" style="display: none">
106
+ <label>
107
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
108
+ </label>
109
+ </p>
110
+ <p>
111
+ <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
112
+ <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
113
+ </p>
114
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
115
+ <label>
116
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
117
+ </label>
118
+ </p>
119
+ <p>
120
+ <label for="<%= instance.id %>_min_label"><?php _e( 'Minimum value label', 'happyforms' ); ?></label>
121
+ <input type="text" id="<%= instance.id %>_min_label" class="widefat title" value="<%= instance.min_label %>" data-bind="min_label" />
122
+ </p>
123
+ <p>
124
+ <label for="<%= instance.id %>_max_label"><?php _e( 'Maximum value label', 'happyforms' ); ?></label>
125
+ <input type="text" id="<%= instance.id %>_max_label" class="widefat title" value="<%= instance.max_label %>" data-bind="max_label" />
126
+ </p>
127
+ <p>
128
+ <label for="<%= instance.id %>_max_value"><?php _e( 'Maximum accepted value', 'happyforms' ); ?></label>
129
+ <input type="text" id="<%= instance.id %>_max_value" class="widefat title" value="<%= instance.max_value %>" data-bind="max_value" />
130
+ </p>
131
+ <p>
132
+ <label for="<%= instance.id %>_default_value"><?php _e( 'Default value', 'happyforms' ); ?></label>
133
+ <input type="text" id="<%= instance.id %>_default_value" class="widefat title" value="<%= instance.default_value %>" data-bind="default_value" />
134
+ </p>
135
+ <p>
136
+ <label for="<%= instance.id %>_step"><?php _e( 'Step', 'happyforms' ); ?></label>
137
+ <select id="<%= instance.id %>_step" data-bind="step" class="widefat">
138
+ <option value="1"<%= (instance.step == '1') ? ' selected' : '' %>>1</option>
139
+ <option value="0.1"<%= (instance.width == '0.1') ? ' selected' : '' %>>0.1</option>
140
+ <option value="10"<%= (instance.width == '10') ? ' selected' : '' %>>10</option>
141
+ </select>
142
+ </p>
143
+ <p>
144
+ <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
145
+ <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
146
+ <option value="full"<%= (instance.width == 'full') ? ' selected' : '' %>><?php _e( 'Full', 'happyforms' ); ?></option>
147
+ <option value="half"<%= (instance.width == 'half') ? ' selected' : '' %>><?php _e( 'Half', 'happyforms' ); ?></option>
148
+ <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
149
+ </select>
150
+ </p>
151
+ <p class="width-options" style="display: none">
152
+ <label>
153
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
154
+ </label>
155
+ </p>
156
+ <p>
157
+ <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
158
+ <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
159
+ </p>
160
+ <p>
161
+ <label>
162
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.required ) { %>checked="checked"<% } %> data-bind="required" /> <?php _e( 'This is a required field', 'happyforms' ); ?>
163
+ </label>
164
+ </p>
165
+ <?php
166
+ }
167
+
168
+ /**
169
+ * Get front end part template with parsed data.
170
+ *
171
+ * @since 1.0.0.
172
+ *
173
+ * @param array $part_data Form part data.
174
+ * @param array $form_data Form (post) data.
175
+ *
176
+ * @return string Markup for the form part.
177
+ */
178
+ public function frontend_template( $part_data = array(), $form_data = array() ) {
179
+ $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
180
+ $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
181
+ $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
182
+
183
+ $classes = array('happyforms-part--scale');
184
+
185
+ if ( $part_data['width'] ) {
186
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
187
+ }
188
+
189
+ if ( $part_data['label_placement'] ) {
190
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
191
+ }
192
+
193
+ if ( !empty( $part_data['css_class'] ) ) {
194
+ $classes[] = $part_data['css_class'] . ' ';
195
+ }
196
+
197
+ $classes = implode( ' ', $classes );
198
+ ?>
199
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
200
+ <div class="happyforms-part__wrap">
201
+ <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
202
+ <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
203
+ <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
204
+ <span class="happyforms-required"> <?php echo $required_text; ?></span>
205
+ <?php endif; ?>
206
+ </label>
207
+ <?php if ( !empty( $part_data['min_label'] ) || !empty( $part_data['max_Label'] ) || is_customize_preview() ) : ?>
208
+ <div class="happyforms-part--scale__labels">
209
+ <span class="label-min"><?php echo $part_data['min_label']; ?></span>
210
+ <span class="label-max"><?php echo $part_data['max_label']; ?></span>
211
+ </div>
212
+ <?php endif; ?>
213
+ <input id="<?php echo esc_attr( $html_id ); ?>" type="range" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" step="<?php echo esc_attr( $part_data['step'] ); ?>" class="happyforms-part__el happyforms-part__el--text-input"
214
+ <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?>
215
+ min="<?php echo esc_attr( $part_data['min_value'] ); ?>" max="<?php echo esc_attr( $part_data['max_value'] ); ?>" value="<?php echo esc_attr( $part_data['default_value'] ); ?>"
216
+ />
217
+ <?php happyforms_print_part_description( $part_data ); ?>
218
+ <output for="<?php echo esc_attr( $html_id ); ?>"><?php echo $part_data['default_value']; ?></output>
219
+ <?php
220
+ if ( $form_data ) :
221
+ happyforms_message_notices( $form_data, $part_data['id'] );
222
+ endif;
223
+ ?>
224
+ </div>
225
+ </div>
226
+ <?php
227
+ }
228
+
229
+ /**
230
+ * Get all possible messages definitions.
231
+ *
232
+ * @since 1.0.0.
233
+ *
234
+ * @return array Associative array, specifying message type and copy.
235
+ */
236
+ public function get_message_definitions() {
237
+ return array(
238
+ 'missing_required_field' => array(
239
+ 'type' => 'error',
240
+ 'message' => __( 'This field is required.', 'happyforms' ),
241
+ ),
242
+ 'not_a_number' => array(
243
+ 'type' => 'error',
244
+ 'message' => __( 'This field requires numeric value.', 'happyforms' ),
245
+ )
246
+ );
247
+ }
248
+
249
+ /**
250
+ * Sanitize submitted value before storing it.
251
+ *
252
+ * @since 1.0.0.
253
+ *
254
+ * @param array $part_data Form part data.
255
+ *
256
+ * @return string
257
+ */
258
+ public function sanitize_value( $part_data = array() ) {
259
+ $sanitized_value = $this->get_default_value();
260
+ $part_id = $part_data['id'];
261
+
262
+ if ( isset( $_REQUEST[$part_id] ) ) {
263
+ $sanitized_value = sanitize_text_field( $_REQUEST[$part_id] );
264
+ }
265
+
266
+ return $sanitized_value;
267
+ }
268
+
269
+ /**
270
+ * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
271
+ *
272
+ * @since 1.0.0.
273
+ *
274
+ * @param array $part_data Form part data.
275
+ * @param string $value Submitted value.
276
+ *
277
+ * @return string|object
278
+ */
279
+ public function validate_value( $part_data, $value ) {
280
+ $part_id = $part_data['id'];
281
+ $validated_value = $value;
282
+
283
+ if ( 1 === $part_data['required'] && empty( $validated_value ) ) {
284
+ $validated_value = new WP_Error( $part_id, 'missing_required_field' );
285
+ }
286
+
287
+ if ( !is_numeric( $validated_value ) ) {
288
+ $validated_value = new WP_Error( $part_id, 'not_a_number' );
289
+ }
290
+
291
+ return $validated_value;
292
+ }
293
+
294
+ /**
295
+ * Enqueue scripts in customizer area.
296
+ *
297
+ * @since 1.0.0.
298
+ *
299
+ * @param array List of dependencies.
300
+ *
301
+ * @return void
302
+ */
303
+ public function customize_enqueue_scripts( $deps = array() ) {
304
+ wp_enqueue_script(
305
+ 'part-scale',
306
+ happyforms_get_plugin_url() . 'assets/js/parts/part-scale.js',
307
+ $deps,
308
+ false,
309
+ true
310
+ );
311
+ }
312
+
313
+
314
+ /**
315
+ * Filter: dependencies for the preview screen.
316
+ *
317
+ * @since 1.0.0.
318
+ *
319
+ * @hooked filter happyforms_preview_dependencies
320
+ *
321
+ * @param array List of dependencies.
322
+ *
323
+ * @return array
324
+ */
325
+ public function preview_dependencies( $deps = array() ) {
326
+ wp_register_script(
327
+ 'happyforms-part-scale',
328
+ happyforms_get_plugin_url() . 'assets/js/frontend/scale.js',
329
+ array( 'jquery', 'jquery-ui-autocomplete' ),
330
+ false,
331
+ true
332
+ );
333
+
334
+ array_push( $deps, 'happyforms-part-scale' );
335
+
336
+ return $deps;
337
+ }
338
+
339
+ /**
340
+ * Action: enqueue additional scripts on the frontend.
341
+ *
342
+ * @since 1.0.0.
343
+ *
344
+ * @hooked action happyforms_frontend_form_scripts
345
+ *
346
+ * @param array List of dependencies.
347
+ *
348
+ * @return array
349
+ */
350
+ public function frontend_enqueue_scripts( $form = array() ) {
351
+ $form_controller = happyforms_get_form_controller();
352
+
353
+ if ( empty( $form ) ) {
354
+ return;
355
+ }
356
+
357
+ if ( empty( $form_controller->get_first_part_by_type( $form, $this->type ) ) ) {
358
+ return;
359
+ }
360
+
361
+ wp_register_script(
362
+ 'happyforms-part-scale',
363
+ happyforms_get_plugin_url() . 'assets/js/frontend/scale.js',
364
+ array( 'jquery' ),
365
+ false,
366
+ true
367
+ );
368
+
369
+ wp_enqueue_script( 'happyforms-part-scale' );
370
+ }
371
+
372
+ }
inc/classes/parts/class-part-select.php CHANGED
@@ -14,9 +14,9 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
14
 
15
  /**
16
  * Get all part meta fields defaults.
17
- *
18
  * @since 1.0.0.
19
- *
20
  * @return array
21
  */
22
  public function get_customize_fields() {
@@ -37,6 +37,10 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
37
  'default' => '',
38
  'sanitize' => 'sanitize_text_field'
39
  ),
 
 
 
 
40
  'width' => array(
41
  'default' => 'full',
42
  'sanitize' => 'sanitize_key'
@@ -58,9 +62,9 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
58
 
59
  /**
60
  * Get part option (sub-part) defaults.
61
- *
62
  * @since 1.0.0.
63
- *
64
  * @return array
65
  */
66
  public function get_option_defaults() {
@@ -72,9 +76,9 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
72
 
73
  /**
74
  * Get template for part item in customize pane.
75
- *
76
  * @since 1.0.0.
77
- *
78
  * @return string
79
  */
80
  public function customize_template() {
@@ -91,10 +95,20 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
91
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
92
  </select>
93
  </p>
 
 
 
 
 
94
  <p>
95
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
96
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
97
  </p>
 
 
 
 
 
98
  <p>
99
  <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
100
  <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
@@ -103,6 +117,11 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
103
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
104
  </select>
105
  </p>
 
 
 
 
 
106
  <p>
107
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
108
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -126,9 +145,9 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
126
 
127
  /**
128
  * Get template for option / sub-part item in customize pane.
129
- *
130
  * @since 1.0.0.
131
- *
132
  * @return string
133
  */
134
  public function customize_item_template() {
@@ -150,12 +169,12 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
150
 
151
  /**
152
  * Get front end part template with parsed data.
153
- *
154
  * @since 1.0.0.
155
- *
156
  * @param array $part_data Form part data.
157
  * @param array $form_data Form (post) data.
158
- *
159
  * @return string Markup for the form part.
160
  */
161
  public function frontend_template( $part_data = array(), $form_data = array() ) {
@@ -163,47 +182,51 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
163
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
164
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
165
 
166
- $classes = ' ';
167
 
168
  if ( $part_data['width'] ) {
169
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
170
  }
171
 
172
  if ( $part_data['label_placement'] ) {
173
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
174
  }
175
 
176
  if ( !empty( $part_data['css_class'] ) ) {
177
- $classes .= $part_data['css_class'];
178
  }
 
 
179
  ?>
180
- <div class="happyforms-part happyforms-part--select happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
181
- <?php
182
- if ( $form_data ) :
183
- happyforms_message_notices( $form_data, $part_data['id'] );
184
- endif;
185
- ?>
186
  <div class="happyforms-part__wrap">
187
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
188
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
189
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
190
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
191
  <?php endif; ?>
192
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
193
  </label>
194
- <select id="<?php echo esc_attr( $html_id ); ?>" name="<?php echo esc_attr( $part_data['id'] ); ?>" class="happyforms-part__el"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
195
- <?php
196
- if ( isset( $part_data['options']) ) {
197
- $options = $part_data['options'];
 
198
 
199
- foreach( $options as $option ) {
200
- $option = wp_parse_args( $option, $this->get_option_defaults() );
201
 
202
- $this->frontend_item_template( $part_data, $option );
 
203
  }
204
- }
 
 
 
 
 
 
 
205
  ?>
206
- </select>
207
  </div>
208
  </div>
209
  <?php
@@ -211,13 +234,13 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
211
 
212
  /**
213
  * Get front end option (sub-part) template with parsed data.
214
- *
215
  * @since 1.0.0.
216
- *
217
  * @param array $part_data Form part data.
218
  * @param array $option Option (form sub-part) data.
219
  * @param int $requred Required field (1) or not.
220
- *
221
  * @return string Markup for the part option.
222
  */
223
  public function frontend_item_template( $part_data, $option ) {
@@ -228,9 +251,9 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
228
 
229
  /**
230
  * Get option's Backbone template for preview purposes. Passed to previewer to create a new Backbone view.
231
- *
232
  * @since 1.0.0.
233
- *
234
  * @return string Backbone template.
235
  */
236
  public function preview_option_template() {
@@ -241,11 +264,11 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
241
 
242
  /**
243
  * Enqueue scripts in customizer area.
244
- *
245
  * @since 1.0.0.
246
- *
247
  * @param array List of dependencies.
248
- *
249
  * @return void
250
  */
251
  public function customize_enqueue_scripts( $deps = array() ) {
@@ -260,9 +283,9 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
260
 
261
  /**
262
  * Get all possible messages definitions.
263
- *
264
  * @since 1.0.0.
265
- *
266
  * @return array Associative array, specifying message type and copy.
267
  */
268
  public function get_message_definitions() {
@@ -280,11 +303,11 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
280
 
281
  /**
282
  * Sanitize submitted value before storing it.
283
- *
284
  * @since 1.0.0.
285
- *
286
  * @param array $part_data Form part data.
287
- *
288
  * @return string
289
  */
290
  public function sanitize_value( $part_data = array() ) {
@@ -300,12 +323,12 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
300
 
301
  /**
302
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
303
- *
304
  * @since 1.0.0.
305
- *
306
  * @param array $part_data Form part data.
307
  * @param string $value Submitted value.
308
- *
309
  * @return string|object
310
  */
311
  public function validate_value( $part_data, $value ) {
@@ -323,10 +346,8 @@ class HappyForms_Part_Select extends HappyForms_Form_Part {
323
  array_push( $possible_options, $option['label'] );
324
  }
325
 
326
- foreach ( $validated_value as $value ) {
327
- if ( !in_array( $value, $possible_options ) ) {
328
- $validated_value = new WP_Error( $part_id, 'not_valid_value' );
329
- }
330
  }
331
 
332
  return $validated_value;
14
 
15
  /**
16
  * Get all part meta fields defaults.
17
+ *
18
  * @since 1.0.0.
19
+ *
20
  * @return array
21
  */
22
  public function get_customize_fields() {
37
  'default' => '',
38
  'sanitize' => 'sanitize_text_field'
39
  ),
40
+ 'tooltip_description' => array(
41
+ 'default' => 0,
42
+ 'sanitize' => 'happyforms_sanitize_checkbox'
43
+ ),
44
  'width' => array(
45
  'default' => 'full',
46
  'sanitize' => 'sanitize_key'
62
 
63
  /**
64
  * Get part option (sub-part) defaults.
65
+ *
66
  * @since 1.0.0.
67
+ *
68
  * @return array
69
  */
70
  public function get_option_defaults() {
76
 
77
  /**
78
  * Get template for part item in customize pane.
79
+ *
80
  * @since 1.0.0.
81
+ *
82
  * @return string
83
  */
84
  public function customize_template() {
95
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
96
  </select>
97
  </p>
98
+ <p class="label_placement-options" style="display: none">
99
+ <label>
100
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
101
+ </label>
102
+ </p>
103
  <p>
104
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
105
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
106
  </p>
107
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
108
+ <label>
109
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
110
+ </label>
111
+ </p>
112
  <p>
113
  <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
114
  <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
117
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
118
  </select>
119
  </p>
120
+ <p class="width-options" style="display: none">
121
+ <label>
122
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
123
+ </label>
124
+ </p>
125
  <p>
126
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
127
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
145
 
146
  /**
147
  * Get template for option / sub-part item in customize pane.
148
+ *
149
  * @since 1.0.0.
150
+ *
151
  * @return string
152
  */
153
  public function customize_item_template() {
169
 
170
  /**
171
  * Get front end part template with parsed data.
172
+ *
173
  * @since 1.0.0.
174
+ *
175
  * @param array $part_data Form part data.
176
  * @param array $form_data Form (post) data.
177
+ *
178
  * @return string Markup for the form part.
179
  */
180
  public function frontend_template( $part_data = array(), $form_data = array() ) {
182
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
183
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
184
 
185
+ $classes = array('happyforms-part--select');
186
 
187
  if ( $part_data['width'] ) {
188
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
189
  }
190
 
191
  if ( $part_data['label_placement'] ) {
192
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
193
  }
194
 
195
  if ( !empty( $part_data['css_class'] ) ) {
196
+ $classes[] = $part_data['css_class'];
197
  }
198
+
199
+ $classes = implode( ' ', $classes );
200
  ?>
201
+ <div class="happyforms-part happyforms-part--select happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
202
  <div class="happyforms-part__wrap">
203
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
204
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
205
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
206
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
207
  <?php endif; ?>
 
208
  </label>
209
+ <div class="happyforms-part__select-wrap">
210
+ <select id="<?php echo esc_attr( $html_id ); ?>" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" class="happyforms-part__el"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
211
+ <?php
212
+ if ( isset( $part_data['options']) ) {
213
+ $options = $part_data['options'];
214
 
215
+ foreach( $options as $option ) {
216
+ $option = wp_parse_args( $option, $this->get_option_defaults() );
217
 
218
+ $this->frontend_item_template( $part_data, $option );
219
+ }
220
  }
221
+ ?>
222
+ </select>
223
+ </div>
224
+ <?php happyforms_print_part_description( $part_data ); ?>
225
+ <?php
226
+ if ( $form_data ) :
227
+ happyforms_message_notices( $form_data, $part_data['id'] );
228
+ endif;
229
  ?>
 
230
  </div>
231
  </div>
232
  <?php
234
 
235
  /**
236
  * Get front end option (sub-part) template with parsed data.
237
+ *
238
  * @since 1.0.0.
239
+ *
240
  * @param array $part_data Form part data.
241
  * @param array $option Option (form sub-part) data.
242
  * @param int $requred Required field (1) or not.
243
+ *
244
  * @return string Markup for the part option.
245
  */
246
  public function frontend_item_template( $part_data, $option ) {
251
 
252
  /**
253
  * Get option's Backbone template for preview purposes. Passed to previewer to create a new Backbone view.
254
+ *
255
  * @since 1.0.0.
256
+ *
257
  * @return string Backbone template.
258
  */
259
  public function preview_option_template() {
264
 
265
  /**
266
  * Enqueue scripts in customizer area.
267
+ *
268
  * @since 1.0.0.
269
+ *
270
  * @param array List of dependencies.
271
+ *
272
  * @return void
273
  */
274
  public function customize_enqueue_scripts( $deps = array() ) {
283
 
284
  /**
285
  * Get all possible messages definitions.
286
+ *
287
  * @since 1.0.0.
288
+ *
289
  * @return array Associative array, specifying message type and copy.
290
  */
291
  public function get_message_definitions() {
303
 
304
  /**
305
  * Sanitize submitted value before storing it.
306
+ *
307
  * @since 1.0.0.
308
+ *
309
  * @param array $part_data Form part data.
310
+ *
311
  * @return string
312
  */
313
  public function sanitize_value( $part_data = array() ) {
323
 
324
  /**
325
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
326
+ *
327
  * @since 1.0.0.
328
+ *
329
  * @param array $part_data Form part data.
330
  * @param string $value Submitted value.
331
+ *
332
  * @return string|object
333
  */
334
  public function validate_value( $part_data, $value ) {
346
  array_push( $possible_options, $option['label'] );
347
  }
348
 
349
+ if ( !in_array( $validated_value, $possible_options ) ) {
350
+ $validated_value = new WP_Error( $part_id, 'not_valid_value' );
 
 
351
  }
352
 
353
  return $validated_value;
inc/classes/parts/class-part-single-line-text.php CHANGED
@@ -12,9 +12,9 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
- *
16
  * @since 1.0.0.
17
- *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
@@ -35,6 +35,10 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
 
 
 
 
38
  'placeholder' => array(
39
  'default' => '',
40
  'sanitize' => 'sanitize_text_field',
@@ -56,9 +60,9 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
56
 
57
  /**
58
  * Get template for part item in customize pane.
59
- *
60
  * @since 1.0.0.
61
- *
62
  * @return string
63
  */
64
  public function customize_template() {
@@ -75,10 +79,20 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
75
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
76
  </select>
77
  </p>
 
 
 
 
 
78
  <p>
79
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
80
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
81
  </p>
 
 
 
 
 
82
  <p>
83
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
84
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
@@ -91,6 +105,11 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
91
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
92
  </select>
93
  </p>
 
 
 
 
 
94
  <p>
95
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
96
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -105,12 +124,12 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
105
 
106
  /**
107
  * Get front end part template with parsed data.
108
- *
109
  * @since 1.0.0.
110
- *
111
  * @param array $part_data Form part data.
112
  * @param array $form_data Form (post) data.
113
- *
114
  * @return string Markup for the form part.
115
  */
116
  public function frontend_template( $part_data = array(), $form_data = array() ) {
@@ -118,35 +137,37 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
118
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
119
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
120
 
121
- $classes = ' ';
122
 
123
  if ( $part_data['width'] ) {
124
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
125
  }
126
 
127
  if ( $part_data['label_placement'] ) {
128
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
129
  }
130
 
131
  if ( !empty( $part_data['css_class'] ) ) {
132
- $classes .= $part_data['css_class'] . ' ';
133
  }
 
 
134
  ?>
135
- <div class="happyforms-part happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
136
- <?php
137
- if ( $form_data ) :
138
- happyforms_message_notices( $form_data, $part_data['id'] );
139
- endif;
140
- ?>
141
  <div class="happyforms-part__wrap">
142
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
143
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
144
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
145
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
146
  <?php endif; ?>
147
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
148
  </label>
149
- <input id="<?php echo esc_attr( $html_id ); ?>" type="text" name="<?php echo esc_attr( $part_data['id'] ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" class="happyforms-part__el happyforms-part__el--text-input" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> />
 
 
 
 
 
 
150
  </div>
151
  </div>
152
  <?php
@@ -154,9 +175,9 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
154
 
155
  /**
156
  * Get all possible messages definitions.
157
- *
158
  * @since 1.0.0.
159
- *
160
  * @return array Associative array, specifying message type and copy.
161
  */
162
  public function get_message_definitions() {
@@ -170,11 +191,11 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
170
 
171
  /**
172
  * Sanitize submitted value before storing it.
173
- *
174
  * @since 1.0.0.
175
- *
176
  * @param array $part_data Form part data.
177
- *
178
  * @return string
179
  */
180
  public function sanitize_value( $part_data = array() ) {
@@ -190,12 +211,12 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
190
 
191
  /**
192
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
193
- *
194
  * @since 1.0.0.
195
- *
196
  * @param array $part_data Form part data.
197
  * @param string $value Submitted value.
198
- *
199
  * @return string|object
200
  */
201
  public function validate_value( $part_data, $value ) {
@@ -211,11 +232,11 @@ class HappyForms_Part_SingleLineText extends HappyForms_Form_Part {
211
 
212
  /**
213
  * Enqueue scripts in customizer area.
214
- *
215
  * @since 1.0.0.
216
- *
217
  * @param array List of dependencies.
218
- *
219
  * @return void
220
  */
221
  public function customize_enqueue_scripts( $deps = array() ) {
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
+ *
16
  * @since 1.0.0.
17
+ *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
38
+ 'tooltip_description' => array(
39
+ 'default' => 0,
40
+ 'sanitize' => 'happyforms_sanitize_checkbox'
41
+ ),
42
  'placeholder' => array(
43
  'default' => '',
44
  'sanitize' => 'sanitize_text_field',
60
 
61
  /**
62
  * Get template for part item in customize pane.
63
+ *
64
  * @since 1.0.0.
65
+ *
66
  * @return string
67
  */
68
  public function customize_template() {
79
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
80
  </select>
81
  </p>
82
+ <p class="label_placement-options" style="display: none">
83
+ <label>
84
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
85
+ </label>
86
+ </p>
87
  <p>
88
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
89
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
90
  </p>
91
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
92
+ <label>
93
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
94
+ </label>
95
+ </p>
96
  <p>
97
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
98
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
105
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
106
  </select>
107
  </p>
108
+ <p class="width-options" style="display: none">
109
+ <label>
110
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
111
+ </label>
112
+ </p>
113
  <p>
114
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
115
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
124
 
125
  /**
126
  * Get front end part template with parsed data.
127
+ *
128
  * @since 1.0.0.
129
+ *
130
  * @param array $part_data Form part data.
131
  * @param array $form_data Form (post) data.
132
+ *
133
  * @return string Markup for the form part.
134
  */
135
  public function frontend_template( $part_data = array(), $form_data = array() ) {
137
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
138
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
139
 
140
+ $classes = array('happyforms-part--single-line-text');
141
 
142
  if ( $part_data['width'] ) {
143
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
144
  }
145
 
146
  if ( $part_data['label_placement'] ) {
147
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
148
  }
149
 
150
  if ( !empty( $part_data['css_class'] ) ) {
151
+ $classes[] = $part_data['css_class'] . ' ';
152
  }
153
+
154
+ $classes = implode( ' ', $classes );
155
  ?>
156
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
157
  <div class="happyforms-part__wrap">
158
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
159
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
160
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
161
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
162
  <?php endif; ?>
 
163
  </label>
164
+ <input id="<?php echo esc_attr( $html_id ); ?>" type="text" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" class="happyforms-part__el happyforms-part__el--text-input" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> />
165
+ <?php happyforms_print_part_description( $part_data ); ?>
166
+ <?php
167
+ if ( $form_data ) :
168
+ happyforms_message_notices( $form_data, $part_data['id'] );
169
+ endif;
170
+ ?>
171
  </div>
172
  </div>
173
  <?php
175
 
176
  /**
177
  * Get all possible messages definitions.
178
+ *
179
  * @since 1.0.0.
180
+ *
181
  * @return array Associative array, specifying message type and copy.
182
  */
183
  public function get_message_definitions() {
191
 
192
  /**
193
  * Sanitize submitted value before storing it.
194
+ *
195
  * @since 1.0.0.
196
+ *
197
  * @param array $part_data Form part data.
198
+ *
199
  * @return string
200
  */
201
  public function sanitize_value( $part_data = array() ) {
211
 
212
  /**
213
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
214
+ *
215
  * @since 1.0.0.
216
+ *
217
  * @param array $part_data Form part data.
218
  * @param string $value Submitted value.
219
+ *
220
  * @return string|object
221
  */
222
  public function validate_value( $part_data, $value ) {
232
 
233
  /**
234
  * Enqueue scripts in customizer area.
235
+ *
236
  * @since 1.0.0.
237
+ *
238
  * @param array List of dependencies.
239
+ *
240
  * @return void
241
  */
242
  public function customize_enqueue_scripts( $deps = array() ) {
inc/classes/parts/class-part-title.php ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class HappyForms_Part_Title extends HappyForms_Form_Part {
4
+
5
+ public $type = 'title';
6
+ public $template_id = 'happyforms-title-template';
7
+
8
+ public function __construct() {
9
+ $this->label = __( 'Title', 'happyforms' );
10
+ $this->description = __( 'For displaying personal honorifics.', 'happyforms' );
11
+ }
12
+
13
+ /**
14
+ * Get all part meta fields defaults.
15
+ *
16
+ * @since 1.0.0.
17
+ *
18
+ * @return array
19
+ */
20
+ public function get_customize_fields() {
21
+ return array(
22
+ 'type' => array(
23
+ 'default' => $this->type,
24
+ 'sanitize' => 'sanitize_text_field',
25
+ ),
26
+ 'label' => array(
27
+ 'default' => __( 'Title', 'happyforms' ),
28
+ 'sanitize' => 'sanitize_text_field',
29
+ ),
30
+ 'label_placement' => array(
31
+ 'default' => 'above',
32
+ 'sanitize' => 'sanitize_text_field'
33
+ ),
34
+ 'description' => array(
35
+ 'default' => '',
36
+ 'sanitize' => 'sanitize_text_field'
37
+ ),
38
+ 'tooltip_description' => array(
39
+ 'default' => 0,
40
+ 'sanitize' => 'happyforms_sanitize_checkbox'
41
+ ),
42
+ 'width' => array(
43
+ 'default' => 'full',
44
+ 'sanitize' => 'sanitize_key'
45
+ ),
46
+ 'css_class' => array(
47
+ 'default' => '',
48
+ 'sanitize' => 'sanitize_text_field'
49
+ ),
50
+ 'required' => array(
51
+ 'default' => 1,
52
+ 'sanitize' => 'happyforms_sanitize_checkbox',
53
+ )
54
+ );
55
+ }
56
+
57
+ /**
58
+ * Get template for part item in customize pane.
59
+ *
60
+ * @since 1.0.0.
61
+ *
62
+ * @return string
63
+ */
64
+ public function customize_template() {
65
+ ?>
66
+ <p>
67
+ <label for="<%= instance.id %>_title"><?php _e( 'Title', 'happyforms' ); ?></label>
68
+ <input type="text" id="<%= instance.id %>_title" class="widefat title" value="<%= instance.label %>" data-bind="label" />
69
+ </p>
70
+ <p>
71
+ <label for="<%= instance.id %>_label_placement"><?php _e( 'Title placement', 'happyforms' ); ?></label>
72
+ <select id="<%= instance.id %>_label_placement" data-bind="label_placement">
73
+ <option value="above"<%= (instance.label_placement == 'above') ? ' selected' : '' %>><?php _e( 'Above', 'happyforms' ); ?></option>
74
+ <option value="left"<%= (instance.label_placement == 'left') ? ' selected' : '' %>><?php _e( 'Left', 'happyforms' ); ?></option>
75
+ <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
76
+ </select>
77
+ </p>
78
+ <p class="label_placement-options" style="display: none">
79
+ <label>
80
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
81
+ </label>
82
+ </p>
83
+ <p>
84
+ <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
85
+ <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
86
+ </p>
87
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
88
+ <label>
89
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
90
+ </label>
91
+ </p>
92
+ <p>
93
+ <label for="<%= instance.id %>_width"><?php _e( 'Width', 'happyforms' ); ?></label>
94
+ <select id="<%= instance.id %>_width" name="width" data-bind="width" class="widefat">
95
+ <option value="full"<%= (instance.width == 'full') ? ' selected' : '' %>><?php _e( 'Full', 'happyforms' ); ?></option>
96
+ <option value="half"<%= (instance.width == 'half') ? ' selected' : '' %>><?php _e( 'Half', 'happyforms' ); ?></option>
97
+ <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
98
+ </select>
99
+ </p>
100
+ <p class="width-options" style="display: none">
101
+ <label>
102
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
103
+ </label>
104
+ </p>
105
+ <p>
106
+ <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
107
+ <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
108
+ </p>
109
+ <p>
110
+ <label>
111
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.required ) { %>checked="checked"<% } %> data-bind="required" /> <?php _e( 'This is a required field', 'happyforms' ); ?>
112
+ </label>
113
+ </p>
114
+ <?php
115
+ }
116
+
117
+ /**
118
+ * Get front end part template with parsed data.
119
+ *
120
+ * @since 1.0.0.
121
+ *
122
+ * @param array $part_data Form part data.
123
+ * @param array $form_data Form (post) data.
124
+ *
125
+ * @return string Markup for the form part.
126
+ */
127
+ public function frontend_template( $part_data = array(), $form_data = array() ) {
128
+ $part_data = wp_parse_args( $part_data, $this->get_customize_defaults() );
129
+ $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
130
+ $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
131
+
132
+ $classes = array('happyforms-part--select');
133
+
134
+ if ( $part_data['width'] ) {
135
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
136
+ }
137
+
138
+ if ( $part_data['label_placement'] ) {
139
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
140
+ }
141
+
142
+ if ( !empty( $part_data['css_class'] ) ) {
143
+ $classes[] = $part_data['css_class'];
144
+ }
145
+
146
+ $classes = implode( ' ', $classes );
147
+ ?>
148
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
149
+ <div class="happyforms-part__wrap">
150
+ <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
151
+ <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
152
+ <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
153
+ <span class="happyforms-required"> <?php echo $required_text; ?></span>
154
+ <?php endif; ?>
155
+ </label>
156
+ <div class="happyforms-part__select-wrap">
157
+ <select id="<?php echo esc_attr( $html_id ); ?>" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" class="happyforms-part__el"<?php if ( 1 === $part_data['required'] ) : ?> required aria-required="true"<?php endif; ?>>
158
+ <option value="">- <?php _e( 'Select', 'happyforms' ); ?> -</option>
159
+ <?php
160
+ $honorifics = $this->get_honorifics();
161
+
162
+ foreach ( $honorifics as $title ) {
163
+ ?>
164
+ <option value="<?php echo $title; ?>"><?php echo $title; ?></option>
165
+ <?php
166
+ }
167
+ ?>
168
+ </select>
169
+ </div>
170
+ <?php happyforms_print_part_description( $part_data ); ?>
171
+ <?php
172
+ if ( $form_data ) :
173
+ happyforms_message_notices( $form_data, $part_data['id'] );
174
+ endif;
175
+ ?>
176
+ </div>
177
+ </div>
178
+ <?php
179
+ }
180
+
181
+ /**
182
+ * Get honorifics as possible options for the dropdown.
183
+ *
184
+ * @since 1.1.0.
185
+ *
186
+ * @return array List of honorifics.
187
+ */
188
+ public function get_honorifics() {
189
+ return array(
190
+ __('Mr.', 'happyforms' ),
191
+ __('Mrs.', 'happyforms' ),
192
+ __('Ms.', 'happyforms' ),
193
+ __('Miss', 'happyforms' ),
194
+ __('Prof.', 'happyforms' ),
195
+ __('Dr.', 'happyforms' )
196
+ );
197
+ }
198
+
199
+ /**
200
+ * Enqueue scripts in customizer area.
201
+ *
202
+ * @since 1.0.0.
203
+ *
204
+ * @param array List of dependencies.
205
+ *
206
+ * @return void
207
+ */
208
+ public function customize_enqueue_scripts( $deps = array() ) {
209
+ wp_enqueue_script(
210
+ 'part-title',
211
+ happyforms_get_plugin_url() . 'assets/js/parts/part-title.js',
212
+ $deps,
213
+ false,
214
+ true
215
+ );
216
+ }
217
+
218
+ /**
219
+ * Get all possible messages definitions.
220
+ *
221
+ * @since 1.0.0.
222
+ *
223
+ * @return array Associative array, specifying message type and copy.
224
+ */
225
+ public function get_message_definitions() {
226
+ return array(
227
+ 'missing_required_field' => array(
228
+ 'type' => 'error',
229
+ 'message' => __( 'This field is required.', 'happyforms' ),
230
+ ),
231
+ 'not_valid_value' => array(
232
+ 'type' => 'error',
233
+ 'message' => __( 'Values is not valid.', 'happyforms' )
234
+ )
235
+ );
236
+ }
237
+
238
+ /**
239
+ * Sanitize submitted value before storing it.
240
+ *
241
+ * @since 1.0.0.
242
+ *
243
+ * @param array $part_data Form part data.
244
+ *
245
+ * @return string
246
+ */
247
+ public function sanitize_value( $part_data = array() ) {
248
+ $sanitized_value = $this->get_default_value();
249
+ $part_id = $part_data['id'];
250
+
251
+ if ( isset( $_REQUEST[$part_id] ) ) {
252
+ $sanitized_value = sanitize_text_field( $_REQUEST[$part_id] );
253
+
254
+ return $sanitized_value;
255
+ }
256
+ }
257
+
258
+ /**
259
+ * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
260
+ *
261
+ * @since 1.0.0.
262
+ *
263
+ * @param array $part_data Form part data.
264
+ * @param string $value Submitted value.
265
+ *
266
+ * @return string|object
267
+ */
268
+ public function validate_value( $part_data, $value ) {
269
+ $part_id = $part_data['id'];
270
+ $validated_value = $value;
271
+
272
+ if ( 1 === $part_data['required'] && empty( $validated_value ) ) {
273
+ $validated_value = new WP_Error( $part_id, 'missing_required_field' );
274
+ }
275
+
276
+ // Check for possible options entered when creating a form. If there's no such option, return WP_Error
277
+ $possible_options = $this->get_honorifics();
278
+
279
+ if ( !in_array( $validated_value, $possible_options ) ) {
280
+ $validated_value = new WP_Error( $part_id, 'not_valid_value' );
281
+ }
282
+
283
+ return $validated_value;
284
+ }
285
+
286
+ }
inc/classes/parts/class-part-website-url.php CHANGED
@@ -12,9 +12,9 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
- *
16
  * @since 1.0.0.
17
- *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
@@ -35,6 +35,10 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
 
 
 
 
38
  'placeholder' => array(
39
  'default' => 'http://',
40
  'sanitize' => 'sanitize_text_field',
@@ -56,9 +60,9 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
56
 
57
  /**
58
  * Get template for part item in customize pane.
59
- *
60
  * @since 1.0.0.
61
- *
62
  * @return string
63
  */
64
  public function customize_template() {
@@ -75,10 +79,20 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
75
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
76
  </select>
77
  </p>
 
 
 
 
 
78
  <p>
79
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
80
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
81
  </p>
 
 
 
 
 
82
  <p>
83
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
84
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
@@ -91,6 +105,11 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
91
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
92
  </select>
93
  </p>
 
 
 
 
 
94
  <p>
95
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
96
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
@@ -105,12 +124,12 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
105
 
106
  /**
107
  * Get front end part template with parsed data.
108
- *
109
  * @since 1.0.0.
110
- *
111
  * @param array $part_data Form part data.
112
  * @param array $form_data Form (post) data.
113
- *
114
  * @return string Markup for the form part.
115
  */
116
  public function frontend_template( $part_data = array(), $form_data = array() ) {
@@ -118,35 +137,37 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
118
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
119
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
120
 
121
- $classes = ' ';
122
 
123
  if ( $part_data['width'] ) {
124
- $classes .= 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
125
  }
126
 
127
  if ( $part_data['label_placement'] ) {
128
- $classes .= 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
129
  }
130
 
131
  if ( !empty( $part_data['css_class'] ) ) {
132
- $classes .= $part_data['css_class'];
133
  }
 
 
134
  ?>
135
- <div class="happyforms-part happyforms-part-editable<?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>" data-happyforms-field-name="label">
136
- <?php
137
- if ( $form_data ) :
138
- happyforms_message_notices( $form_data, $part_data['id'] );
139
- endif;
140
- ?>
141
  <div class="happyforms-part__wrap">
142
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
143
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
144
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
145
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
146
  <?php endif; ?>
147
- <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
148
  </label>
149
- <input id="<?php echo esc_attr( $html_id ); ?>" type="text" name="<?php echo esc_attr( $part_data['id'] ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" class="happyforms-part__el happyforms-part__el--text-input" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> />
 
 
 
 
 
 
150
  </div>
151
  </div>
152
  <?php
@@ -154,9 +175,9 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
154
 
155
  /**
156
  * Get all possible messages definitions.
157
- *
158
  * @since 1.0.0.
159
- *
160
  * @return array Associative array, specifying message type and copy.
161
  */
162
  public function get_message_definitions() {
@@ -174,11 +195,11 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
174
 
175
  /**
176
  * Sanitize submitted value before storing it.
177
- *
178
  * @since 1.0.0.
179
- *
180
  * @param array $part_data Form part data.
181
- *
182
  * @return string
183
  */
184
  public function sanitize_value( $part_data = array() ) {
@@ -194,12 +215,12 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
194
 
195
  /**
196
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
197
- *
198
  * @since 1.0.0.
199
- *
200
  * @param array $part_data Form part data.
201
  * @param string $value Submitted value.
202
- *
203
  * @return string|object
204
  */
205
  public function validate_value( $part_data, $value ) {
@@ -219,11 +240,11 @@ class HappyForms_Part_WebsiteUrl extends HappyForms_Form_Part {
219
 
220
  /**
221
  * Enqueue scripts in customizer area.
222
- *
223
  * @since 1.0.0.
224
- *
225
  * @param array List of dependencies.
226
- *
227
  * @return void
228
  */
229
  public function customize_enqueue_scripts( $deps = array() ) {
12
 
13
  /**
14
  * Get all part meta fields defaults.
15
+ *
16
  * @since 1.0.0.
17
+ *
18
  * @return array
19
  */
20
  public function get_customize_fields() {
35
  'default' => '',
36
  'sanitize' => 'sanitize_text_field'
37
  ),
38
+ 'tooltip_description' => array(
39
+ 'default' => 0,
40
+ 'sanitize' => 'happyforms_sanitize_checkbox'
41
+ ),
42
  'placeholder' => array(
43
  'default' => 'http://',
44
  'sanitize' => 'sanitize_text_field',
60
 
61
  /**
62
  * Get template for part item in customize pane.
63
+ *
64
  * @since 1.0.0.
65
+ *
66
  * @return string
67
  */
68
  public function customize_template() {
79
  <option value="below"<%= (instance.label_placement == 'below') ? ' selected' : '' %>><?php _e( 'Below', 'happyforms' ); ?></option>
80
  </select>
81
  </p>
82
+ <p class="label_placement-options" style="display: none">
83
+ <label>
84
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="label_placement" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
85
+ </label>
86
+ </p>
87
  <p>
88
  <label for="<%= instance.id %>_description"><?php _e( 'Description', 'happyforms' ); ?></label>
89
  <textarea id="<%= instance.id %>_description" data-bind="description"><%= instance.description %></textarea>
90
  </p>
91
+ <p class="tooltip-description-wrap" style="display: <%= (instance.description != '') ? 'block' : 'none' %>">
92
+ <label>
93
+ <input type="checkbox" class="checkbox" value="1" <% if ( instance.tooltip_description ) { %>checked="checked"<% } %> data-bind="tooltip_description" /> <?php _e( 'Show description in a tooltip', 'happyforms' ); ?>
94
+ </label>
95
+ </p>
96
  <p>
97
  <label for="<%= instance.id %>_placeholder"><?php _e( 'Placeholder', 'happyforms' ); ?></label>
98
  <input type="text" id="<%= instance.id %>_placeholder" class="widefat title" value="<%= instance.placeholder %>" data-bind="placeholder" />
105
  <option value="third"<%= (instance.width == 'third') ? ' selected' : '' %>><?php _e( 'One third', 'happyforms' ); ?></option>
106
  </select>
107
  </p>
108
+ <p class="width-options" style="display: none">
109
+ <label>
110
+ <input type="checkbox" class="checkbox apply-all-check" value="" data-apply-to="width" /> <?php _e( 'Apply to all parts', 'happyforms' ); ?>
111
+ </label>
112
+ </p>
113
  <p>
114
  <label for="<%= instance.id %>_css_class"><?php _e( 'Custom CSS class', 'happyforms' ); ?></label>
115
  <input type="text" id="<%= instance.id %>_css_class" class="widefat title" value="<%= instance.css_class %>" data-bind="css_class" />
124
 
125
  /**
126
  * Get front end part template with parsed data.
127
+ *
128
  * @since 1.0.0.
129
+ *
130
  * @param array $part_data Form part data.
131
  * @param array $form_data Form (post) data.
132
+ *
133
  * @return string Markup for the form part.
134
  */
135
  public function frontend_template( $part_data = array(), $form_data = array() ) {
137
  $required_text = ($form_data && $form_data['ID'] != 0) ? get_post_meta( $form_data['ID'], 'hf_style_required_text', true ) : '<%= hf_style_required_text %>';
138
  $html_id = 'happyforms-' . $form_data['ID'] . '_' . esc_attr( $part_data['id'] );
139
 
140
+ $classes = array('happyforms-part--url');
141
 
142
  if ( $part_data['width'] ) {
143
+ $classes[] = 'happyforms-part--width-' . esc_attr( $part_data['width'] ) . ' ';
144
  }
145
 
146
  if ( $part_data['label_placement'] ) {
147
+ $classes[] = 'happyforms-part--label-' . esc_attr( $part_data['label_placement'] ) . ' ';
148
  }
149
 
150
  if ( !empty( $part_data['css_class'] ) ) {
151
+ $classes[] = $part_data['css_class'];
152
  }
153
+
154
+ $classes = implode( ' ', $classes );
155
  ?>
156
+ <div class="happyforms-part happyforms-part-editable <?php echo esc_attr( $classes ); ?>" data-happyforms-id="<?php echo esc_attr( $part_data['id'] ); ?>">
 
 
 
 
 
157
  <div class="happyforms-part__wrap">
158
  <label for="<?php echo esc_attr( $html_id ); ?>" class="happyforms-part__label">
159
  <span class="label"><?php echo esc_html( $part_data['label'] ); ?></span>
160
  <?php if ( 1 === intval( $part_data['required'] ) ) : ?>
161
  <span class="happyforms-required"> <?php echo $required_text; ?></span>
162
  <?php endif; ?>
 
163
  </label>
164
+ <input id="<?php echo esc_attr( $html_id ); ?>" type="text" name="<?php echo esc_attr( happyforms_get_part_name( $part_data['id'], $form_data['ID'] ) ); ?>" placeholder="<?php echo esc_attr( $part_data['placeholder'] ); ?>" class="happyforms-part__el happyforms-part__el--text-input" <?php if ( 1 === $part_data['required'] ) : ?>required aria-required="true"<?php endif; ?> />
165
+ <?php happyforms_print_part_description( $part_data ); ?>
166
+ <?php
167
+ if ( $form_data ) :
168
+ happyforms_message_notices( $form_data, $part_data['id'] );
169
+ endif;
170
+ ?>
171
  </div>
172
  </div>
173
  <?php
175
 
176
  /**
177
  * Get all possible messages definitions.
178
+ *
179
  * @since 1.0.0.
180
+ *
181
  * @return array Associative array, specifying message type and copy.
182
  */
183
  public function get_message_definitions() {
195
 
196
  /**
197
  * Sanitize submitted value before storing it.
198
+ *
199
  * @since 1.0.0.
200
+ *
201
  * @param array $part_data Form part data.
202
+ *
203
  * @return string
204
  */
205
  public function sanitize_value( $part_data = array() ) {
215
 
216
  /**
217
  * Validate value before submitting it. If it fails validation, return WP_Error object, showing respective error message.
218
+ *
219
  * @since 1.0.0.
220
+ *
221
  * @param array $part_data Form part data.
222
  * @param string $value Submitted value.
223
+ *
224
  * @return string|object
225
  */
226
  public function validate_value( $part_data, $value ) {
240
 
241
  /**
242
  * Enqueue scripts in customizer area.
243
+ *
244
  * @since 1.0.0.
245
+ *
246
  * @param array List of dependencies.
247
+ *
248
  * @return void
249
  */
250
  public function customize_enqueue_scripts( $deps = array() ) {
inc/helpers/helper-activation.php CHANGED
@@ -35,8 +35,10 @@ function happyforms_first_run() {
35
 
36
  // Create a new form
37
  $form = $form_controller->create();
 
38
  // Get the new form default data
39
  $form_data = $form_controller->get( $form->ID );
 
40
  $form_data['post_title'] = __( 'Sample Contact Form', 'happyforms' );
41
 
42
  // Prepare age dropdown options
35
 
36
  // Create a new form
37
  $form = $form_controller->create();
38
+
39
  // Get the new form default data
40
  $form_data = $form_controller->get( $form->ID );
41
+
42
  $form_data['post_title'] = __( 'Sample Contact Form', 'happyforms' );
43
 
44
  // Prepare age dropdown options
inc/helpers/helper-form-templates.php CHANGED
@@ -164,7 +164,7 @@ function happyforms_maybe_output_honeypot( $honeypot, $current_position, $part,
164
  }
165
 
166
  $part_id = $honeypot['part_id'];
167
- $label = $part['label'];
168
  $type = 'single_line_text';
169
 
170
  $part = array(
@@ -218,16 +218,108 @@ if ( ! function_exists( 'happyforms_message_notices' ) ):
218
  function happyforms_message_notices( $form, $location = 'top' ) {
219
  $notices = happyforms_get_message_notices()->get_messages( $form, $location );
220
 
221
- if ( ! empty( $notices ) ): ?>
222
- <div class="happyforms-message-notices">
223
- <?php foreach( $notices as $notice ): ?>
224
- <div class="happyforms-message-notice <?php echo esc_attr( $notice['type'] ); ?>">
225
- <h2><?php echo $notice['message']; ?></h2>
 
 
226
  </div>
227
- <?php endforeach; ?>
228
- </div>
229
- <?php
230
  endif;
231
  }
232
 
233
  endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
165
 
166
  $part_id = $honeypot['part_id'];
167
+ $label = ( isset( $part['label'] ) ) ? $part['label'] : '';
168
  $type = 'single_line_text';
169
 
170
  $part = array(
218
  function happyforms_message_notices( $form, $location = 'top' ) {
219
  $notices = happyforms_get_message_notices()->get_messages( $form, $location );
220
 
221
+ if ( ! empty( $notices ) ) : ?>
222
+ <div class="happyforms-message-notices">
223
+ <?php foreach( $notices as $notice ): ?>
224
+ <div class="happyforms-message-notice <?php echo esc_attr( $notice['type'] ); ?>">
225
+ <h2><?php echo $notice['message']; ?></h2>
226
+ </div>
227
+ <?php endforeach; ?>
228
  </div>
229
+ <?php
 
 
230
  endif;
231
  }
232
 
233
  endif;
234
+
235
+ if ( ! function_exists( 'happyforms_print_part_description' ) ):
236
+ /**
237
+ * Output description of the part.
238
+ *
239
+ * @since 1.1
240
+ *
241
+ * @param array $part_data Form part data.
242
+ *
243
+ * @return void
244
+ */
245
+ function happyforms_print_part_description( $part_data ) {
246
+ if ( 1 === intval( $part_data['tooltip_description'] ) || is_customize_preview() ) : ?>
247
+ <span class="happyforms-part__tooltip happyforms-tooltip"<?php if ( empty( $part_data['tooltip_description'] ) ) : ?> style="display: none"<?php endif; ?>>
248
+ <span class="happyforms-tooltip__trigger">?</span>
249
+ <span class="happyforms-part__description"><?php echo esc_html( $part_data['description'] ); ?></span>
250
+ </span>
251
+ <?php endif; ?>
252
+ <?php if ( 0 === intval( $part_data['tooltip_description'] ) || is_customize_preview() ) : ?>
253
+ <span class="happyforms-part__description"<?php if ( is_customize_preview() && 1 === intval( $part_data['tooltip_description'] ) ) : ?> style="display: none"<?php endif; ?>><?php echo esc_html( $part_data['description'] ); ?></span>
254
+ <?php endif;
255
+ }
256
+
257
+ endif;
258
+
259
+ if ( ! function_exists( 'happyforms_get_form_action' ) ):
260
+ /**
261
+ * Returns the action for this form.
262
+ *
263
+ * @since 1.1
264
+ *
265
+ * @param array $form_id Current form id.
266
+ *
267
+ * @return string
268
+ */
269
+ function happyforms_get_form_action( $form_id ) {
270
+ /**
271
+ * Filter the action for this form.
272
+ *
273
+ * @since 1.1
274
+ *
275
+ * @param string $value The default action, an empty string.
276
+ *
277
+ * @return string The filtered action value.
278
+ */
279
+ return apply_filters( 'happyforms_form_action', '', $form_id );
280
+ }
281
+
282
+ endif;
283
+
284
+ if ( ! function_exists( 'happyforms_form_action' ) ):
285
+ /**
286
+ * Prints the action for this form.
287
+ *
288
+ * @since 1.1
289
+ *
290
+ * @param array $form_id Current form id.
291
+ *
292
+ * @return void
293
+ */
294
+ function happyforms_form_action( $form_id ) {
295
+ echo happyforms_get_form_action( $form_id );
296
+ }
297
+
298
+ endif;
299
+
300
+ if ( ! function_exists( 'happyforms_get_part_name' ) ):
301
+ /**
302
+ * Returns the current form part field name.
303
+ *
304
+ * @since 1.1
305
+ *
306
+ * @param array $part_id Current form part id.
307
+ * @param array $form_id Current form id.
308
+ *
309
+ * @return string
310
+ */
311
+ function happyforms_get_part_name( $part_id, $form_id ) {
312
+ /**
313
+ * Filter the field name for this form part.
314
+ *
315
+ * @since 1.1
316
+ *
317
+ * @param string $value The default name.
318
+ * @param string $form_id The part form id.
319
+ *
320
+ * @return string The filtered part name.
321
+ */
322
+ return apply_filters( 'happyforms_part_name', $part_id, $form_id );
323
+ }
324
+
325
+ endif;
inc/helpers/helper-misc.php CHANGED
@@ -169,3 +169,319 @@ function happyforms_admin_footer() {
169
  }
170
 
171
  endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  }
170
 
171
  endif;
172
+
173
+ if ( ! function_exists( 'happyforms_previous_message_edit_link' ) ):
174
+ /**
175
+ * Outputs a link to the previous unread message edit screen.
176
+ *
177
+ * @since 1.1
178
+ *
179
+ * @return void
180
+ */
181
+ function happyforms_previous_message_edit_link( $post_id, $text ) {
182
+ global $happyforms_message_nav;
183
+
184
+ if ( array_search( $post_id, $happyforms_message_nav ) > 0 ) {
185
+ edit_post_link( $text, '', '', $happyforms_message_nav[0] );
186
+ }
187
+ }
188
+
189
+ endif;
190
+
191
+ if ( ! function_exists( 'happyforms_next_message_edit_link' ) ):
192
+ /**
193
+ * Outputs a link to the next unread message edit screen.
194
+ *
195
+ * @since 1.1
196
+ *
197
+ * @return void
198
+ */
199
+ function happyforms_next_message_edit_link( $post_id, $text ) {
200
+ global $happyforms_message_nav;
201
+
202
+ if ( array_search( $post_id, $happyforms_message_nav )
203
+ === count( $happyforms_message_nav ) - 2 ) {
204
+
205
+ edit_post_link( $text, '', '', $happyforms_message_nav[2] );
206
+ }
207
+ }
208
+
209
+ endif;
210
+
211
+ if ( ! function_exists( 'happyforms_get_countries' ) ):
212
+ /**
213
+ * Outputs an array of country names.
214
+ *
215
+ * @since 1.1
216
+ *
217
+ * @return void
218
+ */
219
+ function happyforms_get_countries() {
220
+ return array(
221
+ __( 'Afghanistan', 'happyforms' ),
222
+ __( 'Albania', 'happyforms' ),
223
+ __( 'Algeria', 'happyforms' ),
224
+ __( 'American Samoa', 'happyforms' ),
225
+ __( 'Andorra', 'happyforms' ),
226
+ __( 'Angola', 'happyforms' ),
227
+ __( 'Anguilla', 'happyforms' ),
228
+ __( 'Antarctica', 'happyforms' ),
229
+ __( 'Antigua and Barbuda', 'happyforms' ),
230
+ __( 'Argentina', 'happyforms' ),
231
+ __( 'Armenia', 'happyforms' ),
232
+ __( 'Aruba', 'happyforms' ),
233
+ __( 'Australia', 'happyforms' ),
234
+ __( 'Austria', 'happyforms' ),
235
+ __( 'Azerbaijan', 'happyforms' ),
236
+ __( 'Bahamas', 'happyforms' ),
237
+ __( 'Bahrain', 'happyforms' ),
238
+ __( 'Bangladesh', 'happyforms' ),
239
+ __( 'Barbados', 'happyforms' ),
240
+ __( 'Belarus', 'happyforms' ),
241
+ __( 'Belgium', 'happyforms' ),
242
+ __( 'Belize', 'happyforms' ),
243
+ __( 'Benin', 'happyforms' ),
244
+ __( 'Bermuda', 'happyforms' ),
245
+ __( 'Bhutan', 'happyforms' ),
246
+ __( 'Bolivia', 'happyforms' ),
247
+ __( 'Bosnia and Herzegowina', 'happyforms' ),
248
+ __( 'Botswana', 'happyforms' ),
249
+ __( 'Bouvet Island', 'happyforms' ),
250
+ __( 'Brazil', 'happyforms' ),
251
+ __( 'British Indian Ocean Territory', 'happyforms' ),
252
+ __( 'Brunei Darussalam', 'happyforms' ),
253
+ __( 'Bulgaria', 'happyforms' ),
254
+ __( 'Burkina Faso', 'happyforms' ),
255
+ __( 'Burundi', 'happyforms' ),
256
+ __( 'Cambodia', 'happyforms' ),
257
+ __( 'Cameroon', 'happyforms' ),
258
+ __( 'Canada', 'happyforms' ),
259
+ __( 'Cape Verde', 'happyforms' ),
260
+ __( 'Cayman Islands', 'happyforms' ),
261
+ __( 'Central African Republic', 'happyforms' ),
262
+ __( 'Chad', 'happyforms' ),
263
+ __( 'Chile', 'happyforms' ),
264
+ __( 'China', 'happyforms' ),
265
+ __( 'Christmas Island', 'happyforms' ),
266
+ __( 'Cocos (Keeling) Islands', 'happyforms' ),
267
+ __( 'Colombia', 'happyforms' ),
268
+ __( 'Comoros', 'happyforms' ),
269
+ __( 'Congo', 'happyforms' ),
270
+ __( 'Congo, the Democratic Republic of the', 'happyforms' ),
271
+ __( 'Cook Islands', 'happyforms' ),
272
+ __( 'Costa Rica', 'happyforms' ),
273
+ __( 'Cote d\'Ivoire', 'happyforms' ),
274
+ __( 'Croatia (Hrvatska)', 'happyforms' ),
275
+ __( 'Cuba', 'happyforms' ),
276
+ __( 'Cyprus', 'happyforms' ),
277
+ __( 'Czech Republic', 'happyforms' ),
278
+ __( 'Denmark', 'happyforms' ),
279
+ __( 'Djibouti', 'happyforms' ),
280
+ __( 'Dominica', 'happyforms' ),
281
+ __( 'Dominican Republic', 'happyforms' ),
282
+ __( 'East Timor', 'happyforms' ),
283
+ __( 'Ecuador', 'happyforms' ),
284
+ __( 'Egypt', 'happyforms' ),
285
+ __( 'El Salvador', 'happyforms' ),
286
+ __( 'Equatorial Guinea', 'happyforms' ),
287
+ __( 'Eritrea', 'happyforms' ),
288
+ __( 'Estonia', 'happyforms' ),
289
+ __( 'Ethiopia', 'happyforms' ),
290
+ __( 'Falkland Islands (Malvinas)', 'happyforms' ),
291
+ __( 'Faroe Islands', 'happyforms' ),
292
+ __( 'Fiji', 'happyforms' ),
293
+ __( 'Finland', 'happyforms' ),
294
+ __( 'France', 'happyforms' ),
295
+ __( 'France Metropolitan', 'happyforms' ),
296
+ __( 'French Guiana', 'happyforms' ),
297
+ __( 'French Polynesia', 'happyforms' ),
298
+ __( 'French Southern Territories', 'happyforms' ),
299
+ __( 'Gabon', 'happyforms' ),
300
+ __( 'Gambia', 'happyforms' ),
301
+ __( 'Georgia', 'happyforms' ),
302
+ __( 'Germany', 'happyforms' ),
303
+ __( 'Ghana', 'happyforms' ),
304
+ __( 'Gibraltar', 'happyforms' ),
305
+ __( 'Greece', 'happyforms' ),
306
+ __( 'Greenland', 'happyforms' ),
307
+ __( 'Grenada', 'happyforms' ),
308
+ __( 'Guadeloupe', 'happyforms' ),
309
+ __( 'Guam', 'happyforms' ),
310
+ __( 'Guatemala', 'happyforms' ),
311
+ __( 'Guinea', 'happyforms' ),
312
+ __( 'Guinea-Bissau', 'happyforms' ),
313
+ __( 'Guyana', 'happyforms' ),
314
+ __( 'Haiti', 'happyforms' ),
315
+ __( 'Heard and Mc Donald Islands', 'happyforms' ),
316
+ __( 'Holy See (Vatican City State)', 'happyforms' ),
317
+ __( 'Honduras', 'happyforms' ),
318
+ __( 'Hong Kong', 'happyforms' ),
319
+ __( 'Hungary', 'happyforms' ),
320
+ __( 'Iceland', 'happyforms' ),
321
+ __( 'India', 'happyforms' ),
322
+ __( 'Indonesia', 'happyforms' ),
323
+ __( 'Iran (Islamic Republic of)', 'happyforms' ),
324
+ __( 'Iraq', 'happyforms' ),
325
+ __( 'Ireland', 'happyforms' ),
326
+ __( 'Israel', 'happyforms' ),
327
+ __( 'Italy', 'happyforms' ),
328
+ __( 'Jamaica', 'happyforms' ),
329
+ __( 'Japan', 'happyforms' ),
330
+ __( 'Jordan', 'happyforms' ),
331
+ __( 'Kazakhstan', 'happyforms' ),
332
+ __( 'Kenya', 'happyforms' ),
333
+ __( 'Kiribati', 'happyforms' ),
334
+ __( 'Korea, Democratic People\'s Republic of', 'happyforms' ),
335
+ __( 'Korea, Republic of', 'happyforms' ),
336
+ __( 'Kuwait', 'happyforms' ),
337
+ __( 'Kyrgyzstan', 'happyforms' ),
338
+ __( 'Lao, People\'s Democratic Republic', 'happyforms' ),
339
+ __( 'Latvia', 'happyforms' ),
340
+ __( 'Lebanon', 'happyforms' ),
341
+ __( 'Lesotho', 'happyforms' ),
342
+ __( 'Liberia', 'happyforms' ),
343
+ __( 'Libyan Arab Jamahiriya', 'happyforms' ),
344
+ __( 'Liechtenstein', 'happyforms' ),
345
+ __( 'Lithuania', 'happyforms' ),
346
+ __( 'Luxembourg', 'happyforms' ),
347
+ __( 'Macau', 'happyforms' ),
348
+ __( 'Macedonia, The Former Yugoslav Republic of', 'happyforms' ),
349
+ __( 'Madagascar', 'happyforms' ),
350
+ __( 'Malawi', 'happyforms' ),
351
+ __( 'Malaysia', 'happyforms' ),
352
+ __( 'Maldives', 'happyforms' ),
353
+ __( 'Mali', 'happyforms' ),
354
+ __( 'Malta', 'happyforms' ),
355
+ __( 'Marshall Islands', 'happyforms' ),
356
+ __( 'Martinique', 'happyforms' ),
357
+ __( 'Mauritania', 'happyforms' ),
358
+ __( 'Mauritius', 'happyforms' ),
359
+ __( 'Mayotte', 'happyforms' ),
360
+ __( 'Mexico', 'happyforms' ),
361
+ __( 'Micronesia, Federated States of', 'happyforms' ),
362
+ __( 'Moldova, Republic of', 'happyforms' ),
363
+ __( 'Monaco', 'happyforms' ),
364
+ __( 'Mongolia', 'happyforms' ),
365
+ __( 'Montserrat', 'happyforms' ),
366
+ __( 'Morocco', 'happyforms' ),
367
+ __( 'Mozambique', 'happyforms' ),
368
+ __( 'Myanmar', 'happyforms' ),
369
+ __( 'Namibia', 'happyforms' ),
370
+ __( 'Nauru', 'happyforms' ),
371
+ __( 'Nepal', 'happyforms' ),
372
+ __( 'Netherlands', 'happyforms' ),
373
+ __( 'Netherlands Antilles', 'happyforms' ),
374
+ __( 'New Caledonia', 'happyforms' ),
375
+ __( 'New Zealand', 'happyforms' ),
376
+ __( 'Nicaragua', 'happyforms' ),
377
+ __( 'Niger', 'happyforms' ),
378
+ __( 'Nigeria', 'happyforms' ),
379
+ __( 'Niue', 'happyforms' ),
380
+ __( 'Norfolk Island', 'happyforms' ),
381
+ __( 'Northern Mariana Islands', 'happyforms' ),
382
+ __( 'Norway', 'happyforms' ),
383
+ __( 'Oman', 'happyforms' ),
384
+ __( 'Pakistan', 'happyforms' ),
385
+ __( 'Palau', 'happyforms' ),
386
+ __( 'Panama', 'happyforms' ),
387
+ __( 'Papua New Guinea', 'happyforms' ),
388
+ __( 'Paraguay', 'happyforms' ),
389
+ __( 'Peru', 'happyforms' ),
390
+ __( 'Philippines', 'happyforms' ),
391
+ __( 'Pitcairn', 'happyforms' ),
392
+ __( 'Poland', 'happyforms' ),
393
+ __( 'Portugal', 'happyforms' ),
394
+ __( 'Puerto Rico', 'happyforms' ),
395
+ __( 'Qatar', 'happyforms' ),
396
+ __( 'Reunion', 'happyforms' ),
397
+ __( 'Romania', 'happyforms' ),
398
+ __( 'Russian Federation', 'happyforms' ),
399
+ __( 'Rwanda', 'happyforms' ),
400
+ __( 'Saint Kitts and Nevis', 'happyforms' ),
401
+ __( 'Saint Lucia', 'happyforms' ),
402
+ __( 'Saint Vincent and the Grenadines', 'happyforms' ),
403
+ __( 'Samoa', 'happyforms' ),
404
+ __( 'San Marino', 'happyforms' ),
405
+ __( 'Sao Tome and Principe', 'happyforms' ),
406
+ __( 'Saudi Arabia', 'happyforms' ),
407
+ __( 'Senegal', 'happyforms' ),
408
+ __( 'Seychelles', 'happyforms' ),
409
+ __( 'Sierra Leone', 'happyforms' ),
410
+ __( 'Singapore', 'happyforms' ),
411
+ __( 'Slovakia (Slovak Republic)', 'happyforms' ),
412
+ __( 'Slovenia', 'happyforms' ),
413
+ __( 'Solomon Islands', 'happyforms' ),
414
+ __( 'Somalia', 'happyforms' ),
415
+ __( 'South Africa', 'happyforms' ),
416
+ __( 'South Georgia and the South Sandwich Islands', 'happyforms' ),
417
+ __( 'Spain', 'happyforms' ),
418
+ __( 'Sri Lanka', 'happyforms' ),
419
+ __( 'St. Helena', 'happyforms' ),
420
+ __( 'St. Pierre and Miquelon', 'happyforms' ),
421
+ __( 'Sudan', 'happyforms' ),
422
+ __( 'Suriname', 'happyforms' ),
423
+ __( 'Svalbard and Jan Mayen Islands', 'happyforms' ),
424
+ __( 'Swaziland', 'happyforms' ),
425
+ __( 'Sweden', 'happyforms' ),
426
+ __( 'Switzerland', 'happyforms' ),
427
+ __( 'Syrian Arab Republic', 'happyforms' ),
428
+ __( 'Taiwan, Province of China', 'happyforms' ),
429
+ __( 'Tajikistan', 'happyforms' ),
430
+ __( 'Tanzania, United Republic of', 'happyforms' ),
431
+ __( 'Thailand', 'happyforms' ),
432
+ __( 'Togo', 'happyforms' ),
433
+ __( 'Tokelau', 'happyforms' ),
434
+ __( 'Tonga', 'happyforms' ),
435
+ __( 'Trinidad and Tobago', 'happyforms' ),
436
+ __( 'Tunisia', 'happyforms' ),
437
+ __( 'Turkey', 'happyforms' ),
438
+ __( 'Turkmenistan', 'happyforms' ),
439
+ __( 'Turks and Caicos Islands', 'happyforms' ),
440
+ __( 'Tuvalu', 'happyforms' ),
441
+ __( 'Uganda', 'happyforms' ),
442
+ __( 'Ukraine', 'happyforms' ),
443
+ __( 'United Arab Emirates', 'happyforms' ),
444
+ __( 'United Kingdom', 'happyforms' ),
445
+ __( 'United States', 'happyforms' ),
446
+ __( 'United States Minor Outlying Islands', 'happyforms' ),
447
+ __( 'Uruguay', 'happyforms' ),
448
+ __( 'Uzbekistan', 'happyforms' ),
449
+ __( 'Vanuatu', 'happyforms' ),
450
+ __( 'Venezuela', 'happyforms' ),
451
+ __( 'Vietnam', 'happyforms' ),
452
+ __( 'Virgin Islands (British)', 'happyforms' ),
453
+ __( 'Virgin Islands (U.S.)', 'happyforms' ),
454
+ __( 'Wallis and Futuna Islands', 'happyforms' ),
455
+ __( 'Western Sahara', 'happyforms' ),
456
+ __( 'Yemen', 'happyforms' ),
457
+ __( 'Yugoslavia', 'happyforms' ),
458
+ __( 'Zambia', 'happyforms' ),
459
+ __( 'Zimbabwe', 'happyforms' ),
460
+ );
461
+ }
462
+
463
+ endif;
464
+
465
+ if ( ! function_exists( 'happyforms_unread_messages_badge' ) ):
466
+ /**
467
+ * Outputs the unread messages badge, if there are any.
468
+ *
469
+ * @since 1.1
470
+ *
471
+ * @return void
472
+ */
473
+ function happyforms_unread_messages_badge() {
474
+ $count = get_transient( 'happyforms_unread_messages' );
475
+ $badge = '';
476
+
477
+ if ( $count ) {
478
+ $badge = sprintf(
479
+ ' <span class="awaiting-mod count-1"><span class="pending-count">%s</span></span>',
480
+ $count
481
+ );
482
+ }
483
+
484
+ return $badge;
485
+ }
486
+
487
+ endif;
inc/helpers/helper-validation.php CHANGED
@@ -107,3 +107,23 @@ function happyforms_sanitize_emails( $emails ) {
107
  }
108
 
109
  endif;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
  }
108
 
109
  endif;
110
+
111
+ if ( ! function_exists( 'happyforms_sanitize_choice' ) ):
112
+ /**
113
+ * Sanitize a single choice value.
114
+ *
115
+ * @since 1.0
116
+ *
117
+ * @param string $value Original value.
118
+ *
119
+ * @return string
120
+ */
121
+ function happyforms_sanitize_choice( $value, $choices = array() ) {
122
+ if ( ! in_array( $value, $choices ) ) {
123
+ $value = $choices[0];
124
+ }
125
+
126
+ return $value;
127
+ }
128
+
129
+ endif;
inc/templates/admin-message-edit.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ global $message, $form;
3
+
4
+ if ( ! $form ) {
5
+ return;
6
+ }
7
+ ?>
8
+ <table class="form-table happyforms-message-data-table">
9
+ <tbody>
10
+ <?php
11
+ $tr = 0;
12
+ foreach ( $form['parts'] as $part_data ):
13
+ $part = happyforms_get_part_library()->get_part( $part_data['type'] );
14
+ $part_id = $part_data['id'];
15
+ $label = happyforms_get_part_label( $part_data );
16
+ $value = happyforms_get_message_part_value( $message['parts'][$part_id] );
17
+ ?>
18
+ <tr <?php if ($tr % 2 == 0) : ?>class="alternate"<?php endif; ?>>
19
+ <th scope="row"><?php echo esc_html( $label ); ?></th>
20
+ <td><?php echo esc_html( $value ); ?></td>
21
+ </tr>
22
+ <?php $tr ++; endforeach; ?>
23
+ </tbody>
24
+ </table>
25
+ <p class="happyforms-message-nav">
26
+ <?php happyforms_previous_message_edit_link( $post->ID, __( 'Previous message' ) ); ?>
27
+ <span class="divider">|</span>
28
+ <?php happyforms_next_message_edit_link( $post->ID, __( 'Next message' ) ); ?>
29
+ </p>
inc/{admin/page-tracking.php → templates/admin-tracking.php} RENAMED
@@ -14,10 +14,10 @@ $status = $tracking->get_status();
14
  <h2><?php _e( 'Setup communication', 'happyforms' ); ?></h2>
15
  <form action="<?php echo esc_attr( $tracking->monitor_action ); ?>" method="post" id="happyforms-tracking">
16
  <p class="about-description"><?php _e( 'Just one more step before you get started:', 'happyforms' ); ?></p>
17
- <p><?php _e( 'Let\'s setup HappyForms! Enter your email below to agree to notification and to share some data about your usage with', 'happyforms' ); ?> <a href="https://thethemefoundry.com" target="_blank">thethemefoundry.com</a></p>
18
  <input name="<?php echo esc_attr( $tracking->monitor_email_field ); ?>" type="email" placeholder="<?php _e( 'Email address', 'happyforms' ); ?>" required >
19
  <input name="<?php echo esc_attr( $tracking->monitor_status_field ); ?>" type="hidden" value="active" />
20
- <button type="submit" class="button button-primary button-hero"><?php _e( 'Allow and setup HappyForms', 'happyforms' ); ?></button>
21
  </form>
22
  <?php } ?>
23
  </div>
14
  <h2><?php _e( 'Setup communication', 'happyforms' ); ?></h2>
15
  <form action="<?php echo esc_attr( $tracking->monitor_action ); ?>" method="post" id="happyforms-tracking">
16
  <p class="about-description"><?php _e( 'Just one more step before you get started:', 'happyforms' ); ?></p>
17
+ <p><?php _e( 'Let\'s set up HappyForms! Enter your email below to agree to notification and to share some data about your usage with', 'happyforms' ); ?> <a href="https://thethemefoundry.com" target="_blank">thethemefoundry.com</a></p>
18
  <input name="<?php echo esc_attr( $tracking->monitor_email_field ); ?>" type="email" placeholder="<?php _e( 'Email address', 'happyforms' ); ?>" required >
19
  <input name="<?php echo esc_attr( $tracking->monitor_status_field ); ?>" type="hidden" value="active" />
20
+ <button type="submit" class="button button-primary button-hero"><?php _e( 'Allow and set up HappyForms', 'happyforms' ); ?></button>
21
  </form>
22
  <?php } ?>
23
  </div>
inc/templates/customize-form-build.php CHANGED
@@ -6,10 +6,18 @@
6
  </div>
7
 
8
  <div class="customize-control">
9
- <label class="customize-control-title"><?php _e( 'Form Builder', 'happyforms' ); ?></label>
 
 
 
 
 
10
  <div class="happyforms-parts-placeholder">
11
- <img src="<?php echo happyforms_get_plugin_url(); ?>assets/svg/welcome.svg" alt="">
12
- <p><?php _e( 'Click to add parts from the sidebar to your new form. Once a part is added, drag and drop to re-order it as you like.' ); ?></p>
 
 
 
13
  </div>
14
  <ul class="happyforms-form-widgets"></ul>
15
  </div>
6
  </div>
7
 
8
  <div class="customize-control">
9
+ <label class="customize-control-title">
10
+ <?php _e( 'Form Builder', 'happyforms' ); ?>
11
+ <span class="happyforms-parts-expand-collapse-wrap">
12
+ <a href="#" class="expand-collapse-all collapse" data-collapse-text="<?php _e( 'Collapse all', 'happyforms' ); ?>" data-expand-text="<?php _e( 'Expand all', 'happyforms' ); ?>"><?php _e( 'Collapse all', 'happyforms' ); ?></a>
13
+ </span>
14
+ </label>
15
  <div class="happyforms-parts-placeholder">
16
+ <p><b><?php _e( 'Ready to get started?', 'happyforms' ); ?></b></p>
17
+ <p><?php _e( 'Click any part from the sidebar to add it to your new form. Then, drag parts into order.', 'happyforms' ); ?></p>
18
+ <div class="happyforms-parts-placeholder__placeholder"></div>
19
+ <div class="happyforms-parts-placeholder__placeholder"></div>
20
+ <div class="happyforms-parts-placeholder__placeholder"></div>
21
  </div>
22
  <ul class="happyforms-form-widgets"></ul>
23
  </div>
inc/templates/customize-form-style.php CHANGED
@@ -1,75 +1,106 @@
1
- <script type="text/template" id="happyforms-form-style-template">
2
- <div class="happyforms-stack-view">
3
- <?php
4
- $styles = happyforms_get_styles();
5
- $style_fields = $styles->get_styles();
6
- ?>
7
 
 
 
8
  <ul class="happyforms-form-widgets happyforms-style-controls">
9
- <?php if ( !empty( $style_fields ) ) : ?>
10
- <?php
11
- foreach ( $style_fields as $key => $field ) :
12
- $extra_classes = ' ';
13
-
14
- if ( $field[ 'type' ] === 'range' ) {
15
- $extra_classes .= 'happyforms-range-control';
16
- }
17
- ?>
18
- <li class="customize-control<?php echo esc_attr( $extra_classes ); ?>">
19
- <?php if ( $field['type'] === 'divider' ) { ?>
20
- <?php echo $field['html']; ?>
21
- <?php } else { ?>
22
- <?php if ( $field['type'] !== 'checkbox' && $field['type'] !== 'buttonset' ) : ?>
23
- <label class="customize-control-title" for="<?php echo esc_attr( $key ); ?>"><?php echo $field[ 'label' ]; ?></label>
24
- <?php endif; ?>
25
- <?php if ( $field[ 'type' ] === 'range' ) : ?>
26
- <input type="number" name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>" min="<?php echo $field[ 'min' ]; ?>" max="<?php echo $field[ 'max' ]; ?>" step="1" value="<% if (typeof <?php echo esc_attr( $key ); ?> !== 'undefined' && <?php echo esc_attr( $key ); ?>) { %><%= <?php echo esc_attr( $key ); ?> %><% } else { %><?php echo $field[ 'default' ]; ?><% } %>" data-attribute="<?php echo esc_attr( $key ); ?>">
27
- <?php endif; ?>
28
- <div class="customize-control-content">
29
- <?php if ( $field[ 'type' ] === 'checkbox' ) : ?>
 
 
 
 
 
 
 
30
  <label>
31
- <input type="checkbox" name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>" value="1" data-attribute="<?php echo esc_attr( $key ); ?>"<% if (typeof <?php echo esc_attr( $key ); ?> !== 'undefined' && <?php echo esc_attr( $key ); ?>) { %> checked="checked"<% } %>> <?php echo $field['label']; ?>
32
  </label>
33
- <?php endif; ?>
34
- <?php if ( $field[ 'type' ] === 'buttonset' ) : ?>
35
- <label class="customize-control-title" for="<?php echo esc_attr( $key ); ?>"><?php echo $field['label']; ?></label>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  <div class="happyforms-buttonset-container">
37
- <?php foreach ( $field[ 'options' ] as $option_key => $option ) : ?>
38
- <input type="radio" class="happyforms-buttonset" name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>_<?php echo esc_attr( $option_key ); ?>" value="<?php echo esc_attr( $option_key ); ?>" data-attribute="<?php echo esc_attr( $key ); ?>"<% if (typeof <?php echo esc_attr( $key ); ?> !== 'undefined' && <?php echo esc_attr( $key ); ?> === '<?php echo esc_attr( $option_key ); ?>') { %> checked="checked"<% } %>>
39
- <label for="<?php echo esc_attr( $key ); ?>_<?php echo esc_attr( $option_key ); ?>">
40
- <span class="ui-button-text"></span><?php echo esc_attr( $option ); ?></span>
41
- </label>
42
- <?php endforeach; ?>
43
- </div>
44
- <?php endif; ?>
45
- <?php if ( $field[ 'type' ] === 'color' ) : ?>
46
- <input type="text" name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>" class="happyforms-color-input" data-attribute="<?php echo esc_attr( $key ); ?>" value="<% if (typeof <?php echo esc_attr( $key ); ?> !== 'undefined' && <?php echo esc_attr( $key ); ?>) { %><%= <?php echo esc_attr( $key ); ?> %><% } else { %><?php echo $field[ 'default' ]; ?><% } %>" data-default="<?php echo $field['default']; ?>">
47
- <?php endif; ?>
48
- <?php if ( $field[ 'type' ] === 'text' ) : ?>
49
- <input type="text" name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>" data-attribute="<?php echo esc_attr( $key ); ?>" value="<% if (typeof <?php echo esc_attr( $key ); ?> !== 'undefined' && <?php echo esc_attr( $key ); ?>) { %><%= <?php echo esc_attr( $key ); ?> %><% } else { %><?php echo $field[ 'default' ]; ?><% } %>">
50
- <?php endif; ?>
51
- <?php if ( $field[ 'type' ] === 'select' ) : ?>
52
- <select name="<?php echo esc_attr( $key ); ?>" id="<?php echo esc_attr( $key ); ?>" data-attribute="<?php echo esc_attr( $key ); ?>" class="widefat">
53
- <?php
54
- $options = $field['options'];
55
-
56
- foreach ( $options as $option_key => $option ) {
57
- ?>
58
- <option value="<?php echo esc_attr( $option_key ); ?>"<%= (<?php echo esc_attr( $key ); ?> === '<?php echo esc_attr( $option_key ); ?>') ? 'selected' : '' %>><?php echo esc_attr( $option ); ?></option>
59
- <?php
60
- }
61
- ?>
62
- </select>
63
- <?php endif; ?>
64
- <?php if ( $field[ 'type' ] === 'range' ) : ?>
65
- <div class="happyforms-range-slider">
66
- </div>
67
- <?php endif; ?>
68
- </div>
69
- <?php } ?>
70
- </li>
71
- <?php endforeach; ?>
72
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
73
  </ul>
74
  </div>
75
  </script>
1
+ <?php
2
+ $styles = happyforms_get_styles();
3
+ $style_fields = $styles->get_styles();
4
+ ?>
 
 
5
 
6
+ <script type="text/template" id="happyforms-form-style-template">
7
+ <div class="happyforms-stack-view happyforms-style-view">
8
  <ul class="happyforms-form-widgets happyforms-style-controls">
9
+ <?php
10
+ $f = 0;
11
+ foreach ( $style_fields as $name => $field ) :
12
+ $type = $field['type'];
13
+ $name = esc_attr( $name );
14
+ $label = isset( $field['label'] ) ? $field['label'] : '';
15
+ $control_class = esc_attr( "happyforms-{$type}-control" );
16
+
17
+ if ( 'divider' === $type ) : ?>
18
+
19
+ <?php if ( $f > 0 ): ?></ul></li><?php endif; ?>
20
+
21
+ <li class="customize-control control-section <?php echo $control_class; ?>">
22
+ <h3 class="accordion-section-title"><?php echo $label; ?></h3>
23
+ <ul class="happyforms-style-controls-group inactive">
24
+ <li class="panel-meta customize-info accordion-section">
25
+ <button class="customize-panel-back" tabindex="0">
26
+ <span class="screen-reader-text"><?php _e( 'Back', 'happyforms' ); ?></span>
27
+ </button>
28
+ <div class="accordion-section-title">
29
+ <span class="preview-notice"><?php _e( 'You are customizing', 'happyforms' ); ?> <strong class="panel-title"><?php echo $label; ?></strong></span>
30
+ </div>
31
+ </li>
32
+
33
+ <?php elseif ( 'checkbox' === $type ) : ?>
34
+
35
+ <li class="customize-control <?php echo $control_class; ?>">
36
+ <div class="customize-control-content">
37
  <label>
38
+ <input type="checkbox" name="<?php echo $name; ?>" id="<?php echo $name; ?>" value="1" data-attribute="<?php echo $name; ?>" <% if (<?php echo $name; ?>) { %>checked="checked"<% } %>> <?php echo $label; ?>
39
  </label>
40
+ </div>
41
+ </li>
42
+
43
+ <?php elseif ( 'range' === $type ) : ?>
44
+
45
+ <li class="customize-control <?php echo $control_class; ?>">
46
+ <label class="customize-control-title" for="<?php echo $name; ?>"><?php echo $label; ?></label>
47
+ <input type="number" name="<?php echo $name; ?>" id="<?php echo $name; ?>" min="<?php echo $field[ 'min' ]; ?>" max="<?php echo $field[ 'max' ]; ?>" step="1" value="<%= <?php echo $name; ?> %>" data-attribute="<?php echo $name; ?>">
48
+ <div class="customize-control-content">
49
+ <div class="happyforms-range-slider"></div>
50
+ </div>
51
+ </li>
52
+
53
+ <?php elseif ( 'buttonset' === $type ) : ?>
54
+
55
+ <li class="customize-control <?php echo $control_class; ?>">
56
+ <div class="customize-control-content">
57
+ <label class="customize-control-title" for="<?php echo $name; ?>"><?php echo $label; ?></label>
58
  <div class="happyforms-buttonset-container">
59
+ <?php foreach ( $field[ 'options' ] as $option_key => $option ) : ?>
60
+ <input type="radio" class="happyforms-buttonset" name="<?php echo $name; ?>" id="<?php echo $name; ?>_<?php echo esc_attr( $option_key ); ?>" value="<?php echo esc_attr( $option_key ); ?>" data-attribute="<?php echo $name; ?>" <% if (<?php echo $name; ?> === '<?php echo esc_attr( $option_key ); ?>') { %>checked="checked"<% } %>>
61
+ <label for="<?php echo $name; ?>_<?php echo esc_attr( $option_key ); ?>">
62
+ <span class="ui-button-text"></span><?php echo esc_attr( $option ); ?></span>
63
+ </label>
64
+ <?php endforeach; ?>
65
+ </div>
66
+ </div>
67
+ </li>
68
+
69
+ <?php elseif ( 'color' === $type ) : ?>
70
+
71
+ <li class="customize-control <?php echo $control_class; ?>">
72
+ <label class="customize-control-title" for="<?php echo $name; ?>"><?php echo $label; ?></label>
73
+ <div class="customize-control-content">
74
+ <input type="text" name="<?php echo $name; ?>" id="<?php echo $name; ?>" class="happyforms-color-input" data-attribute="<?php echo $name; ?>" value="<%= <?php echo $name; ?> %>" data-default="<?php echo $field['default']; ?>">
75
+ </div>
76
+ </li>
77
+
78
+ <?php elseif ( 'text' === $type ) : ?>
79
+
80
+ <li class="customize-control <?php echo $control_class; ?>">
81
+ <label class="customize-control-title" for="<?php echo $name; ?>"><?php echo $label; ?></label>
82
+ <div class="customize-control-content">
83
+ <input type="text" name="<?php echo $name; ?>" id="<?php echo $name; ?>" data-attribute="<?php echo $name; ?>" value="<%= <?php echo $name; ?> %>">
84
+ </div>
85
+ </li>
86
+
87
+ <?php elseif ( 'text' === $type ) : ?>
88
+
89
+ <li class="customize-control <?php echo $control_class; ?>">
90
+ <label class="customize-control-title" for="<?php echo $name; ?>"><?php echo $label; ?></label>
91
+ <div class="customize-control-content">
92
+ <select name="<?php echo $name; ?>" id="<?php echo $name; ?>" data-attribute="<?php echo $name; ?>" class="widefat">
93
+ <?php
94
+ foreach ( $field['options'] as $option_key => $option ) : ?>
95
+ <option value="<?php echo esc_attr( $option_key ); ?>" <% if (<?php echo $name; ?> === '<?php echo esc_attr( $option_key ); ?>') {%><%= 'selected' %><% } %>><?php echo esc_attr( $option ); ?></option>
96
+ <?php endforeach; ?>
97
+ </select>
98
+ </div>
99
+ </li>
100
+
101
+ <?php endif; ?>
102
+ <?php $f ++; endforeach; ?>
103
+ </ul></li>
104
  </ul>
105
  </div>
106
  </script>
inc/templates/frontend-form.php CHANGED
@@ -5,7 +5,7 @@
5
  <?php $honeypot = happyforms_get_honeypot( $form ); ?>
6
  <?php happyforms_honeypot_styles( $honeypot, $form ); ?>
7
 
8
- <form action="" id="happyforms-form-<?php echo esc_attr( $form['ID'] ); ?>" method="post">
9
  <?php happyforms_action_field(); ?>
10
  <?php happyforms_redirect_field( $form ); ?>
11
  <?php happyforms_form_field( $form['ID'] ); ?>
5
  <?php $honeypot = happyforms_get_honeypot( $form ); ?>
6
  <?php happyforms_honeypot_styles( $honeypot, $form ); ?>
7
 
8
+ <form action="<?php happyforms_form_action( $form['ID'] ); ?>" id="happyforms-form-<?php echo esc_attr( $form['ID'] ); ?>" method="post">
9
  <?php happyforms_action_field(); ?>
10
  <?php happyforms_redirect_field( $form ); ?>
11
  <?php happyforms_form_field( $form['ID'] ); ?>
inc/templates/preview-form-edit.php CHANGED
@@ -17,7 +17,17 @@
17
  <form>
18
  <div id="happyforms-app" class="happyforms-flex" data-happyforms-form-id="<?php echo esc_attr( $form['ID'] ); ?>">
19
  <div id="message" class="updated published notice notice-success">
20
- <p><?php _e( 'This is a preview of your new HappyForm. Once you’ve finished building, you can add this form to any Page, Post and Widget area. Have questions?', 'happyforms' ); ?> <a href="https://wordpress.org/support/plugin/happyforms" class="happyforms-ask-link" target="_blank"><?php _e( 'Ask for help in our support forums.', 'happyforms' ); ?></a></p>
 
 
 
 
 
 
 
 
 
 
21
  </div>
22
 
23
  <div class="happyforms-part happyforms-part-editable happyforms-form-title" data-happyforms-form-id="<?php echo esc_attr( $form['ID'] ); ?>" data-happyforms-field-name="post_title">
@@ -35,14 +45,14 @@
35
 
36
  <?php
37
  foreach( $form['parts'] as $part ) {
38
- happyforms_message_notices( $form, $part['id'] );
39
  echo happyforms_get_part_library()->get_part_template( $part, $form );
40
  }
41
  ?>
42
 
43
  <div class="happyforms-part happyforms-part--submit">
44
  <?php $submit_button_label = get_post_meta( $post->ID, 'submit_button_label', true ); ?>
45
- <button type="submit" class="happyforms-button happyforms-button--submit"><?php echo ( $submit_button_label ) ? $submit_button_label : __( 'Submit', 'happyforms' ); ?></button>
46
  </div>
47
 
48
  <div id="happyforms-preview-styles">
@@ -59,6 +69,12 @@
59
  $('.happyforms-ask-link').on('click', function() {
60
  window.open($(this).attr('href'));
61
  });
 
 
 
 
 
 
62
  });
63
  </script>
64
  </body>
17
  <form>
18
  <div id="happyforms-app" class="happyforms-flex" data-happyforms-form-id="<?php echo esc_attr( $form['ID'] ); ?>">
19
  <div id="message" class="updated published notice notice-success">
20
+ <p>
21
+ <?php
22
+ printf(
23
+ wp_kses(
24
+ __( 'This is a preview of your new HappyForm. Once you’ve finished building, you can add this form to any Page, Post and Widget area. Have questions? <a href="%s" class="happyforms-ask-link" target="_blank">Ask for help in our support forums.</a>', 'happyforms' ),
25
+ array( 'a' => array( 'class' => true, 'href' => true, 'target' => true ) )
26
+ ),
27
+ 'https://wordpress.org/support/plugin/happyforms'
28
+ );
29
+ ?>
30
+ </p>
31
  </div>
32
 
33
  <div class="happyforms-part happyforms-part-editable happyforms-form-title" data-happyforms-form-id="<?php echo esc_attr( $form['ID'] ); ?>" data-happyforms-field-name="post_title">
45
 
46
  <?php
47
  foreach( $form['parts'] as $part ) {
48
+ happyforms_message_notices( $form, $part['id'] );
49
  echo happyforms_get_part_library()->get_part_template( $part, $form );
50
  }
51
  ?>
52
 
53
  <div class="happyforms-part happyforms-part--submit">
54
  <?php $submit_button_label = get_post_meta( $post->ID, 'submit_button_label', true ); ?>
55
+ <button type="submit" class="happyforms-button happyforms-button--submit"><?php echo ( $submit_button_label ) ? $submit_button_label : __( 'Submit Form', 'happyforms' ); ?></button>
56
  </div>
57
 
58
  <div id="happyforms-preview-styles">
69
  $('.happyforms-ask-link').on('click', function() {
70
  window.open($(this).attr('href'));
71
  });
72
+
73
+ $('.happyforms-form').on('submit', function(e) {
74
+ e.preventDefault();
75
+
76
+ return false;
77
+ });
78
  });
79
  </script>
80
  </body>
inc/templates/preview-form-new.php CHANGED
@@ -14,7 +14,17 @@
14
  <form class="happyforms-form">
15
  <div id="happyforms-app" class="happyforms-flex" data-happyforms-form-id="0">
16
  <div id="message" class="updated published notice notice-success">
17
- <p><?php _e( 'This is a preview of your new HappyForm. Once you’ve finished building, you can add this form to any Page, Post and Widget area. Have questions?', 'happyforms' ); ?> <a href="https://wordpress.org/support/plugin/happyforms" class="happyforms-ask-link" target="_blank"><?php _e( 'Ask for help in our support forums.', 'happyforms' ); ?></a></p>
 
 
 
 
 
 
 
 
 
 
18
  </div>
19
 
20
  <div class="happyforms-part happyforms-part-editable happyforms-form-title" data-happyforms-form-id="0" data-happyforms-field-name="post_title">
@@ -25,7 +35,7 @@
25
  </div>
26
 
27
  <div class="happyforms-part happyforms-part--submit">
28
- <button type="submit" class="happyforms-button happyforms-button--submit"><?php _e( 'Submit', 'happyforms' ); ?></button>
29
  </div>
30
 
31
  <div id="happyforms-preview-styles">
@@ -42,6 +52,12 @@
42
  $('.happyforms-ask-link').on('click', function() {
43
  window.open($(this).attr('href'));
44
  });
 
 
 
 
 
 
45
  });
46
  </script>
47
  </body>
14
  <form class="happyforms-form">
15
  <div id="happyforms-app" class="happyforms-flex" data-happyforms-form-id="0">
16
  <div id="message" class="updated published notice notice-success">
17
+ <p>
18
+ <?php
19
+ printf(
20
+ wp_kses(
21
+ __( 'This is a preview of your new HappyForm. Once you’ve finished building, you can add this form to any Page, Post and Widget area. Have questions? <a href="%s" class="happyforms-ask-link" target="_blank">Ask for help in our support forums.</a>', 'happyforms' ),
22
+ array( 'a' => array( 'class' => true, 'href' => true, 'target' => true ) )
23
+ ),
24
+ 'https://wordpress.org/support/plugin/happyforms'
25
+ );
26
+ ?>
27
+ </p>
28
  </div>
29
 
30
  <div class="happyforms-part happyforms-part-editable happyforms-form-title" data-happyforms-form-id="0" data-happyforms-field-name="post_title">
35
  </div>
36
 
37
  <div class="happyforms-part happyforms-part--submit">
38
+ <button type="submit" class="happyforms-button happyforms-button--submit"><?php _e( 'Submit Form', 'happyforms' ); ?></button>
39
  </div>
40
 
41
  <div id="happyforms-preview-styles">
52
  $('.happyforms-ask-link').on('click', function() {
53
  window.open($(this).attr('href'));
54
  });
55
+
56
+ $('.happyforms-form').on('submit', function(e) {
57
+ e.preventDefault();
58
+
59
+ return false;
60
+ });
61
  });
62
  </script>
63
  </body>
inc/templates/preview-inline.css CHANGED
@@ -41,15 +41,22 @@ body::before, body::after {
41
  overflow: visible;
42
  }
43
  .happyforms-form h3.happyforms-form__title {
 
 
44
  padding: 0;
45
  }
46
  .happyforms-preview-badge {
 
47
  font-weight: 400;
48
- font-size: 22px;
49
  }
50
  .happyforms-part.highlighted {
51
  outline: 1px solid lightblue;
52
  }
53
  a.happyforms-ask-link {
54
  cursor: pointer !important;
 
 
 
 
55
  }
41
  overflow: visible;
42
  }
43
  .happyforms-form h3.happyforms-form__title {
44
+ display: flex !important;
45
+ align-items: center;
46
  padding: 0;
47
  }
48
  .happyforms-preview-badge {
49
+ padding-left: 10px;
50
  font-weight: 400;
51
+ font-size: 16px;
52
  }
53
  .happyforms-part.highlighted {
54
  outline: 1px solid lightblue;
55
  }
56
  a.happyforms-ask-link {
57
  cursor: pointer !important;
58
+ }
59
+ .happyforms-part .widget .customize-partial-edit-shortcut,
60
+ .customize-partial-edit-shortcut {
61
+ top: 0;
62
  }
readme.txt CHANGED
@@ -5,7 +5,7 @@ Tags: contact, contact form, email, feedback form, form, form builder, custom fo
5
  Requires at least: 4.8
6
  Tested up to: 4.9.2
7
  Requires PHP: 5.2.4
8
- Stable tag: 1.0
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
@@ -70,5 +70,32 @@ Absolutely! HappyForms gets out of the way and is designed to work with any them
70
 
71
  == Changelog ==
72
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  = 1.0.0 =
74
  * Initial release.
 
 
 
 
 
 
 
 
5
  Requires at least: 4.8
6
  Tested up to: 4.9.2
7
  Requires PHP: 5.2.4
8
+ Stable tag: 1.2
9
  License: GPLv2 or later
10
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
11
 
70
 
71
  == Changelog ==
72
 
73
+ = 1.2.0 =
74
+ * Bug fix: an error during the example form creation was preventing plugin activation.
75
+
76
+ = 1.1.0 =
77
+ * New feature: New form parts - Title, Legal, Scale.
78
+ * New feature: Show part description in a tooltip.
79
+ * New feature: Button for expanding and collapsing all parts in Form Builder.
80
+ * New feature: Added “Add HappyForms” button above visual editor for easier form embeds in page content.
81
+ * New feature: Added new fields to Single Choice part to allow for part option descriptions.
82
+ * Improved: Better message management.
83
+ * Improved: Country part is now Address and supports autocompletion.
84
+ * Improved: More controls and better organization of form style options.
85
+ * Improved: General form styles.
86
+ * Improved: Visual editors now support hyperlinks.
87
+ * Improved: Title placement and Width part settings can now be applied to all parts by checking a checkbox.
88
+ * Improved: Phone is now a standalone part with improved masking.
89
+ * Improved: Number part now supports min and max value attributes.
90
+ * Improved: Date part now displays inputs as dropdowns and also allows for time inputs.
91
+
92
  = 1.0.0 =
93
  * Initial release.
94
+
95
+ == Upgrade Notice ==
96
+
97
+ = 1.2.0 =
98
+ * Bug fix: an error during the example form creation was preventing plugin activation.
99
+
100
+ = 1.1.0 =
101
+ * Tons of new features and improvements.