Strong Testimonials - Version 2.31

Version Description

  • May 15, 2018 =
  • Add [testimonial_average_rating] shortcode.
  • Add compatibility option for script controller.
  • Add compatibility option for lazy loading images.
  • Minor template style tweaks for small screens.
  • Use empty star icon instead of full icon in different color.
  • Change default message "Required field" to "Required".
  • Improve exception handling.
  • Improve Pjax compatibility.
  • Apply JavaScript coding standard.
  • Add console logging for slider when SCRIPT_DEBUG enabled.
  • Minor admin style tweaks.
Download this release

Release Info

Developer cdillon27
Plugin Icon 128x128 Strong Testimonials
Version 2.31
Comparing to
See all releases

Code changes from version 2.30.9 to 2.31

Files changed (44) hide show
  1. admin/about/about.php +2 -1
  2. admin/about/class-strong-testimonials-about.php +3 -7
  3. admin/about/how-to.php +0 -10
  4. admin/about/whats-new.php +13 -0
  5. admin/class-strong-testimonials-admin-scripts.php +11 -0
  6. admin/class-strong-testimonials-defaults.php +16 -3
  7. admin/class-strong-testimonials-help.php +3 -3
  8. admin/class-strong-testimonials-page-shortcodes.php +288 -0
  9. admin/class-strong-testimonials-updater.php +44 -30
  10. admin/class-strong-views-list-table.php +12 -2
  11. admin/css/admin-compat.css +131 -153
  12. admin/css/admin.css +21 -2
  13. admin/css/views.css +10 -1
  14. admin/js/admin-compat.js +16 -1
  15. admin/menu/class-strong-testimonials-menu-shortcodes.php +55 -0
  16. admin/partials/views/view-shortcode.php +1 -1
  17. admin/scss/admin-compat.scss +26 -1
  18. admin/scss/views.scss +13 -0
  19. admin/settings/class-strong-testimonials-settings-compat.php +616 -305
  20. admin/settings/partials/licenses.php +1 -0
  21. includes/class-strong-testimonials-render.php +2 -2
  22. includes/class-strong-testimonials-shortcode-average.php +338 -0
  23. includes/class-strong-testimonials-shortcode-count.php +72 -0
  24. includes/{class-strong-testimonials-shortcodes.php → class-strong-testimonials-shortcode.php} +6 -60
  25. includes/class-strong-view-display.php +14 -4
  26. includes/class-strong-view-slideshow.php +38 -9
  27. includes/class-strong-view.php +18 -18
  28. includes/functions-template-form.php +2 -2
  29. includes/functions-template.php +1 -1
  30. includes/functions.php +46 -1
  31. includes/scripts.php +6 -2
  32. public/css/rating-display.css +85 -33
  33. public/css/rating-form.css +18 -29
  34. public/js/controller.js +75 -31
  35. public/js/controller.min.js +1 -1
  36. public/js/lib/form-validation/form-validation.js +50 -50
  37. public/js/lib/form-validation/form-validation.min.js +1 -1
  38. public/js/lib/strongpager/jquery.strongpager.js +80 -80
  39. public/js/lib/strongslider/jquery.strongslider.js +561 -533
  40. public/js/lib/strongslider/jquery.strongslider.min.js +2 -2
  41. readme.txt +22 -7
  42. strong-testimonials.php +14 -7
  43. templates-scss/bold/content.scss +20 -7
  44. templates/bold/content.css +11 -6
admin/about/about.php CHANGED
@@ -1,5 +1,6 @@
1
  <h2><?php _e( 'Flexible Features. Strong Support.', 'strong-testimonials' ); ?></h2>
2
- <p class="lead-description"><?php _e( 'The highest-rated free testimonials plugin trusted by more than 50,000 people keeps getting better.', 'strong-testimonials' ); ?></p>
 
3
  <div class="feature-section one-col">
4
  <div class="col">
5
  <p><?php _e( 'Your site is unique, right? So are your testimonials. This plugin is designed from the ground up to simplify the process of customizing your testimonials or reviews.', 'strong-testimonials' ); ?></p>
1
  <h2><?php _e( 'Flexible Features. Strong Support.', 'strong-testimonials' ); ?></h2>
2
+ <?php /* translators: %s is a formatted number */ ?>
3
+ <p class="lead-description"><?php printf( __( 'The highest-rated free testimonials plugin trusted by more than %s people keeps getting better.', 'strong-testimonials' ), number_format_i18n( 50000 ) ); ?></p>
4
  <div class="feature-section one-col">
5
  <div class="col">
6
  <p><?php _e( 'Your site is unique, right? So are your testimonials. This plugin is designed from the ground up to simplify the process of customizing your testimonials or reviews.', 'strong-testimonials' ); ?></p>
admin/about/class-strong-testimonials-about.php CHANGED
@@ -13,12 +13,6 @@ class Strong_Testimonials_About {
13
  $this->add_actions();
14
  }
15
 
16
- /**
17
- * Initialize.
18
- */
19
- public function init() {
20
- }
21
-
22
  /**
23
  * Add actions and filters.
24
  */
@@ -63,11 +57,13 @@ class Strong_Testimonials_About {
63
  ?>
64
  <div class="wrap about-wrap">
65
 
 
66
  <h1><?php printf( __( 'Welcome to Strong Testimonials %s', 'strong-testimonials' ), $major_minor ); ?></h1>
67
 
68
  <p class="about-text">
69
  <?php _e( 'Thank you for updating to the latest version!' ); ?>
70
- <?php printf( 'Strong Testimonials %s offers improved view options.', $major_minor ); ?>
 
71
  </p>
72
 
73
  <div class="wp-badge strong-testimonials"><?php printf( __( 'Version %s' ), $major_minor ); ?></div>
13
  $this->add_actions();
14
  }
15
 
 
 
 
 
 
 
16
  /**
17
  * Add actions and filters.
18
  */
57
  ?>
58
  <div class="wrap about-wrap">
59
 
60
+ <?php /* translators: %s is the plugin version number */ ?>
61
  <h1><?php printf( __( 'Welcome to Strong Testimonials %s', 'strong-testimonials' ), $major_minor ); ?></h1>
62
 
63
  <p class="about-text">
64
  <?php _e( 'Thank you for updating to the latest version!' ); ?>
65
+ <?php /* translators: %s is the plugin version number */ ?>
66
+ <?php printf( 'Strong Testimonials %s includes a shortcode for your average rating and improves compatibility with lazy loading images.', $major_minor ); ?>
67
  </p>
68
 
69
  <div class="wp-badge strong-testimonials"><?php printf( __( 'Version %s' ), $major_minor ); ?></div>
admin/about/how-to.php CHANGED
@@ -52,16 +52,6 @@ $add_the_view = __( 'Add the view to a page or sidebar using its unique shortcod
52
  <p>3. <?php echo $add_the_view; ?></p>
53
  </div>
54
 
55
- <div class="col">
56
- <h3><?php _e( 'How to Display the Number of Testimonials', 'strong-testimonials' ); ?></h3>
57
- <p><?php printf( __( 'Use the %s shortcode.', 'strong-testimonials' ), '<code>&#91;testimonial_count&#93;</code>' ); ?>
58
- <?php _e( 'For example:', 'strong-testimonials' ); ?></p>
59
- <p><span class="code"><?php printf( __( 'Read some of our %s testimonials!', 'strong-testimonials' ), '&#91;testimonial_count&#93;' ); ?></span></p>
60
- <p><?php printf( __( 'To count for a specific category, add the %s attribute with the category slug.', 'strong-testimonials' ), '<code>category</code>' ); ?>
61
- <?php _e( 'For example:', 'strong-testimonials' ); ?></p>
62
- <p><span class="code"><?php printf( __( 'Here\'s what %s local clients say', 'strong-testimonials' ), '&#91;testimonial_count category="local"&#93;' ); ?></span></p>
63
- </div>
64
-
65
  <div class="col">
66
  <h3><?php _e( 'How to Translate', 'strong-testimonials' ); ?></h3>
67
  <p><?php _e( 'Strong Testimonials is compatible with WPML, Polylang and WP Globus.', 'strong-testimonials' ); ?></p>
52
  <p>3. <?php echo $add_the_view; ?></p>
53
  </div>
54
 
 
 
 
 
 
 
 
 
 
 
55
  <div class="col">
56
  <h3><?php _e( 'How to Translate', 'strong-testimonials' ); ?></h3>
57
  <p><?php _e( 'Strong Testimonials is compatible with WPML, Polylang and WP Globus.', 'strong-testimonials' ); ?></p>
admin/about/whats-new.php CHANGED
@@ -1,6 +1,18 @@
1
 
2
  <h2>Now Even Stronger</h2>
3
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  <p class="lead-description">Version 2.30 adds highly requested features, improves compatibility and fixes bugs.</p>
5
 
6
  <div class="feature-section one-col">
@@ -30,6 +42,7 @@
30
  <li>Version 2.30.6</li>
31
  <li>Version 2.30.7</li>
32
  <li>Version 2.30.8</li>
 
33
  </ul>
34
 
35
  </div>
1
 
2
  <h2>Now Even Stronger</h2>
3
 
4
+ <p class="lead-description">Version 2.31 adds a highly requested feature and two more compatibility options.</p>
5
+
6
+ <div class="feature-section one-col">
7
+ <div class="col">
8
+ <p>NEW: Display your average rating with the <code>&#91;testimonial_average_rating&#93;</code> shortcode. Finally!</p>
9
+ <p>NEW: Use the Load Event option to potentially fix problems with sliders and Masonry in complex themes.</p>
10
+ <p>NEW: Use the Lazy Loading option to potentially fix problems with testimonial images being cut off.</p>
11
+ <p>IMPROVED: The star ratings now use an empty star instead of a gray full star. This is the more popular approach.</p>
12
+ <p>IMPROVED: Minor style tweaks in both admin and in some templates for small screens.</p>
13
+ </div>
14
+ </div>
15
+
16
  <p class="lead-description">Version 2.30 adds highly requested features, improves compatibility and fixes bugs.</p>
17
 
18
  <div class="feature-section one-col">
42
  <li>Version 2.30.6</li>
43
  <li>Version 2.30.7</li>
44
  <li>Version 2.30.8</li>
45
+ <li>Version 2.30.9</li>
46
  </ul>
47
 
48
  </div>
admin/class-strong-testimonials-admin-scripts.php CHANGED
@@ -28,6 +28,7 @@ class Strong_Testimonials_Admin_Scripts {
28
  add_action( 'admin_print_styles-wpm-testimonial_page_testimonial-fields', array( __CLASS__, 'admin_fields' ) );
29
  add_action( 'admin_print_styles-wpm-testimonial_page_testimonial-settings', array( __CLASS__, 'admin_settings' ) );
30
  add_action( 'admin_print_styles-wpm-testimonial_page_about-strong-testimonials', array( __CLASS__, 'admin_about' ) );
 
31
 
32
  add_action( 'load-edit.php', array( __CLASS__, 'admin_load_edit' ) );
33
  add_action( 'load-post.php', array( __CLASS__, 'admin_load_post' ) );
@@ -313,6 +314,16 @@ class Strong_Testimonials_Admin_Scripts {
313
  wp_enqueue_style( 'wpmtst-about-style' );
314
  }
315
 
 
 
 
 
 
 
 
 
 
 
316
  /**
317
  * List table
318
  */
28
  add_action( 'admin_print_styles-wpm-testimonial_page_testimonial-fields', array( __CLASS__, 'admin_fields' ) );
29
  add_action( 'admin_print_styles-wpm-testimonial_page_testimonial-settings', array( __CLASS__, 'admin_settings' ) );
30
  add_action( 'admin_print_styles-wpm-testimonial_page_about-strong-testimonials', array( __CLASS__, 'admin_about' ) );
31
+ add_action( 'admin_print_styles-wpm-testimonial_page_testimonial-shortcodes', array( __CLASS__, 'admin_shortcodes' ) );
32
 
33
  add_action( 'load-edit.php', array( __CLASS__, 'admin_load_edit' ) );
34
  add_action( 'load-post.php', array( __CLASS__, 'admin_load_post' ) );
314
  wp_enqueue_style( 'wpmtst-about-style' );
315
  }
316
 
317
+ /**
318
+ * Shortcodes
319
+ *
320
+ * @since 2.31.0
321
+ */
322
+ public static function admin_shortcodes() {
323
+ wp_enqueue_style( 'wpmtst-admin-style' );
324
+ wp_enqueue_style( 'wpmtst-rating-display' );
325
+ }
326
+
327
  /**
328
  * List table
329
  */
admin/class-strong-testimonials-defaults.php CHANGED
@@ -389,8 +389,8 @@ class Strong_Testimonials_Defaults {
389
  'required-field' => array(
390
  'order' => 1,
391
  /* translators: Settings > Form > Messages tab */
392
- 'description' => _x( 'Required Field', 'setting description', 'strong-testimonials' ),
393
- 'text' => _x( 'Required field', 'Default message for required notice at top of form.', 'strong-testimonials' ),
394
  'enabled' => 1,
395
  ),
396
  'captcha' => array(
@@ -762,7 +762,8 @@ class Strong_Testimonials_Defaults {
762
  * Compatibility options.
763
  *
764
  * @since 2.28.0
765
- *
 
766
  * @return array
767
  */
768
  public static function get_compat_options() {
@@ -778,6 +779,18 @@ class Strong_Testimonials_Defaults {
778
  'event' => '',
779
  'script' => '',
780
  ),
 
 
 
 
 
 
 
 
 
 
 
 
781
  );
782
 
783
  return $options;
389
  'required-field' => array(
390
  'order' => 1,
391
  /* translators: Settings > Form > Messages tab */
392
+ 'description' => _x( 'Required', 'setting description', 'strong-testimonials' ),
393
+ 'text' => _x( 'Required', 'Default message for required notice at top of form.', 'strong-testimonials' ),
394
  'enabled' => 1,
395
  ),
396
  'captcha' => array(
762
  * Compatibility options.
763
  *
764
  * @since 2.28.0
765
+ * @since 2.31.0 controller
766
+ * @since 2.31.0 lazyload
767
  * @return array
768
  */
769
  public static function get_compat_options() {
779
  'event' => '',
780
  'script' => '',
781
  ),
782
+ 'controller' => array(
783
+ 'initialize_on' => 'documentReady', // or windowLoad
784
+ ),
785
+ 'lazyload' => array(
786
+ 'enabled' => '',
787
+ 'classes' => array( // may be multiple pairs
788
+ array(
789
+ 'start' => '',
790
+ 'finish' => '',
791
+ )
792
+ ),
793
+ ),
794
  );
795
 
796
  return $options;
admin/class-strong-testimonials-help.php CHANGED
@@ -122,12 +122,12 @@ class Strong_Testimonials_Help {
122
  <p><?php _e( 'For example, imagine you have five services, a sales page for each service, and a testimonial category for each service. To display the testimonials on each service page, you can create five duplicate views, one for each category.', 'strong-testimonials' ); ?>
123
  <p><?php _e( 'Or you can configure one view as a pattern and add it to each service page with the <code>category</code> attribute.', 'strong-testimonials' ); ?>
124
  <p>
125
- <?php _e( '<code>[testimonial_view id=1 category="service-1"]</code>', 'strong-testimonials' ); ?>,
126
- <?php _e( '<code>[testimonial_view id=1 category="service-2"]</code>', 'strong-testimonials' ); ?>, etc.
127
  </p>
128
  <p>
129
  <?php _e( 'Attributes may be used in combination. For example:', 'strong-testimonials' ); ?>
130
- <?php _e( '<code>[testimonial_view id=1 category="service-3" order="random" count="5"]</code>', 'strong-testimonials' ); ?>
131
  </p>
132
  <p><?php _e( 'Using <code>post_ids</code> is the most specific method and it will override category and count (whether settings or attributes).', 'strong-testimonials' ); ?></p>
133
  </div>
122
  <p><?php _e( 'For example, imagine you have five services, a sales page for each service, and a testimonial category for each service. To display the testimonials on each service page, you can create five duplicate views, one for each category.', 'strong-testimonials' ); ?>
123
  <p><?php _e( 'Or you can configure one view as a pattern and add it to each service page with the <code>category</code> attribute.', 'strong-testimonials' ); ?>
124
  <p>
125
+ <?php _e( '<code>[testimonial_view id="1" category="service-1"]</code>', 'strong-testimonials' ); ?>,
126
+ <?php _e( '<code>[testimonial_view id="1" category="service-2"]</code>', 'strong-testimonials' ); ?>, etc.
127
  </p>
128
  <p>
129
  <?php _e( 'Attributes may be used in combination. For example:', 'strong-testimonials' ); ?>
130
+ <?php _e( '<code>[testimonial_view id="1" category="service-3" order="random" count="5"]</code>', 'strong-testimonials' ); ?>
131
  </p>
132
  <p><?php _e( 'Using <code>post_ids</code> is the most specific method and it will override category and count (whether settings or attributes).', 'strong-testimonials' ); ?></p>
133
  </div>
admin/class-strong-testimonials-page-shortcodes.php ADDED
@@ -0,0 +1,288 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Strong_Testimonials_Page_Shortcodes
5
+ *
6
+ * @since 2.31.0
7
+ */
8
+ class Strong_Testimonials_Page_Shortcodes {
9
+
10
+ /**
11
+ * Strong_Testimonials_Page_Shortcodes constructor.
12
+ */
13
+ private function __construct() {
14
+ }
15
+
16
+ /**
17
+ * Render the shortcode instructions page.
18
+ */
19
+ public static function render_page() {
20
+
21
+ $tags = array(
22
+ 'a' => array(
23
+ 'href' => array(),
24
+ 'target' => array(),
25
+ ),
26
+ );
27
+ ?>
28
+ <div class="wrap wpmtst shortcodes has-stars">
29
+
30
+ <h1><?php _e( 'Shortcodes', 'strong-testimonials' ); ?></h1>
31
+
32
+ <p><?php printf( wp_kses( __( 'Open a <a href="%s" target="_blank">support ticket</a> if you need help.', 'strong-testimonials' ), $tags ), esc_url( 'https://support.strongplugins.com/new-ticket/' ) ); ?></p>
33
+
34
+ <h2><?php _e( 'Testimonial Views', 'strong-testimonials' ); ?></h2>
35
+
36
+ <p>
37
+ <?php _e( 'Each view has a unique shortcode like <code>&#91;testimonial_view id="1"&#93;</code>.', 'strong-testimonials' ); ?>
38
+ <?php printf( '<a href="%s">%s</a>', esc_url( admin_url( 'edit.php?post_type=wpm-testimonial&page=testimonial-views' ) ), __( 'Go to views', 'strong-testimonials' ) ); ?>
39
+ </p>
40
+
41
+ <h2><?php _e( 'Testimonial Count', 'strong-testimonials' ); ?></h2>
42
+
43
+ <p><?php printf( __( 'Use %s to display the number of testimonials.', 'strong-testimonials' ), '<code>&#91;testimonial_count&#93;</code>' ); ?></p>
44
+
45
+ <table class="form-table shortcodes">
46
+ <tr>
47
+ <td>
48
+ <p><?php _e( 'Default', 'strong-testimonials' ); ?></p>
49
+ </td>
50
+ <td class="shortcode">
51
+ <?php /* translators: %s is a shortcode */ ?>
52
+ <p>
53
+ <?php printf( __( 'Read some of our %s testimonials!', 'strong-testimonials' ), '&#91;testimonial_count&#93;' ); ?>
54
+ </p>
55
+ </td>
56
+ </tr>
57
+ <tr>
58
+ <td>
59
+ <?php /* translators: %s is a shortcode attribute */ ?>
60
+ <p><?php printf( __( 'To count for a specific category, add the %s attribute with the category slug.', 'strong-testimonials' ), '<code>category</code>' ); ?>
61
+ </td>
62
+ <td class="shortcode">
63
+ <?php /* translators: %s is a shortcode */ ?>
64
+ <p>
65
+ <?php printf( __( 'Here\'s what %s local clients say', 'strong-testimonials' ), '&#91;testimonial_count category="local"&#93;' ); ?>
66
+ </p>
67
+ </td>
68
+ </tr>
69
+ </table>
70
+
71
+ <h2><?php _e( 'Average Rating', 'strong-testimonials' ); ?></h2>
72
+
73
+ <p>
74
+ <?php /* translators: %s is a shortcode */ ?>
75
+ <?php printf( __( 'If using a <strong>single</strong> rating field, use %s to display the average rating.', 'strong-testimonials' ), '<code>&#91;testimonial_average_rating&#93;</code>' ); ?>
76
+ </p>
77
+
78
+ <table class="form-table shortcodes aggregate">
79
+ <tr>
80
+ <td rowspan="2">
81
+ <p><?php _e( 'Default', 'strong-testimonials' ); ?></p>
82
+ <p class="description"><?php _e( 'You must use the closing slash <code>/</code> if using the shortcode with content elsewhere on your page.', 'strong-testimonials' ); ?></p>
83
+ </td>
84
+ <td class="shortcode">&#91;testimonial_average_rating /&#93;</td>
85
+ </tr>
86
+ <tr>
87
+ <td>
88
+ <div class="strong-rating-wrapper average">
89
+ <span class="strong-rating-title">Average Rating:</span>
90
+ <span class="strong-rating"><span class="star0 star"></span><span class="star"></span><span
91
+ class="star"></span><span class="star"></span><span class="star current half"></span><span
92
+ class="star"></span></span>
93
+ <span class="strong-rating-summary">4.3 stars (based on 9 ratings)</span>
94
+ </div>
95
+ </td>
96
+ </tr>
97
+ </table>
98
+
99
+ <table class="form-table shortcodes aggregate">
100
+ <tr>
101
+ <td rowspan="2">
102
+ <p><?php _e( 'Customize using content tags.', 'strong-testimonials' ); ?></p>
103
+ <p><?php _e( 'Default:', 'strong-testimonials' ); ?></p>
104
+ <p><code>{title}</code><br><code>{stars}</code><br><code>{summary}</code></p>
105
+ </td>
106
+ <td class="shortcode">&#91;testimonial_average_rating&#93;{title} {stars} {summary}&#91;/testimonial_average_rating&#93;</td>
107
+ </tr>
108
+ <tr>
109
+ <td>
110
+ <div class="strong-rating-wrapper average">
111
+ <span class="strong-rating-title">Average Rating:</span>
112
+ <span class="strong-rating"><span class="star0 star"></span><span class="star"></span><span
113
+ class="star"></span><span class="star"></span><span class="star current half"></span><span
114
+ class="star"></span></span>
115
+ <span class="strong-rating-summary">4.3 stars (based on 9 ratings)</span>
116
+ </div>
117
+ </td>
118
+ </tr>
119
+ </table>
120
+
121
+ <table class="form-table shortcodes aggregate">
122
+ <tr>
123
+ <td rowspan="2">
124
+ <p><?php _e( 'Alternate content tags.', 'strong-testimonials' ); ?></p>
125
+ <p><code>{title2}</code><br><code>{summary2}</code></p>
126
+ </td>
127
+ <td class="shortcode">&#91;testimonial_average_rating&#93;{title2} {stars} {summary2}&#91;/testimonial_average_rating&#93;</td>
128
+ </tr>
129
+ <tr>
130
+ <td>
131
+ <div class="strong-rating-wrapper average">
132
+ <span class="strong-rating-title">Average of 9 Ratings:</span>
133
+ <span class="strong-rating"><span class="star0 star"></span><span class="star"></span><span
134
+ class="star"></span><span class="star"></span><span class="star current half"></span><span
135
+ class="star"></span></span>
136
+ <span class="strong-rating-summary">4.3 stars</span>
137
+ </div>
138
+ </td>
139
+ </tr>
140
+ </table>
141
+
142
+ <table class="form-table shortcodes aggregate">
143
+ <tr>
144
+ <td rowspan="2">
145
+ <p><?php _e( 'Insert tags into your custom content.', 'strong-testimonials' ); ?></p>
146
+ <p class="description"><?php _e( '', 'strong-testimonials' ); ?></p>
147
+ </td>
148
+ <td class="shortcode">&#91;testimonial_average_rating&#93;{stars} Our average rating is &lt;b&gt;{summary2}&lt;/b&gt;&#91;/testimonial_average_rating&#93;</td>
149
+ </tr>
150
+ <tr>
151
+ <td>
152
+ <div class="strong-rating-wrapper average">
153
+ <span class="strong-rating">
154
+ <span class="star0 star"></span>
155
+ <span class="star"></span><span class="star"></span><span class="star"></span><span class="star current half"></span><span
156
+ class="star"></span>
157
+ </span>
158
+ Our average rating is <b><span class="strong-rating-summary">4.3 stars</span></b>
159
+ </div>
160
+ </td>
161
+ </tr>
162
+ </table>
163
+
164
+ <table class="form-table shortcodes aggregate">
165
+ <tr>
166
+ <td rowspan="2">
167
+ <p><code>{stars}</code></p>
168
+ </td>
169
+ <td class="shortcode">&#91;testimonial_average_rating&#93;{stars}&#91;/testimonial_average_rating&#93;</td>
170
+ </tr>
171
+ <tr>
172
+ <td>
173
+ <div class="strong-rating-wrapper average">
174
+ <span class="strong-rating"><span class="star0 star"></span><span class="star"></span><span
175
+ class="star"></span><span class="star"></span><span class="star current half"></span><span
176
+ class="star"></span></span>
177
+ </div>
178
+ </td>
179
+ </tr>
180
+ </table>
181
+
182
+ <table class="form-table shortcodes aggregate">
183
+ <tr>
184
+ <td rowspan="2">
185
+ <p><code>{average}</code></p>
186
+ </td>
187
+ <td class="shortcode">&#91;testimonial_average_rating&#93;{average}&#91;/testimonial_average_rating&#93;</td>
188
+ </tr>
189
+ <tr>
190
+ <td>
191
+ <div class="strong-rating-wrapper average"><span class="strong-rating-average">4.3</span></div>
192
+ </td>
193
+ </tr>
194
+ </table>
195
+
196
+ <table class="form-table shortcodes aggregate">
197
+ <tr>
198
+ <td rowspan="2">
199
+ <p><code>{count}</code></p>
200
+ </td>
201
+ <td class="shortcode">&#91;testimonial_average_rating&#93;{count}&#91;/testimonial_average_rating&#93;</td>
202
+ </tr>
203
+ <tr>
204
+ <td>
205
+ <div class="strong-rating-wrapper average"><span class="strong-rating-count">9</span></div>
206
+ </td>
207
+ </tr>
208
+ </table>
209
+
210
+ <table class="form-table shortcodes aggregate">
211
+ <tr>
212
+ <td rowspan="2">
213
+ <p><code>block</code></p>
214
+ </td>
215
+ <td class="shortcode">&#91;testimonial_average_rating block /&#93;</td>
216
+ </tr>
217
+ <tr>
218
+ <td>
219
+ <div class="strong-rating-wrapper average block"><span class="strong-rating-title">Average Rating:</span>
220
+ <span class="strong-rating">
221
+ <span class="star0 star"></span>
222
+ <span class="star"></span><span class="star"></span><span class="star"></span><span class="star current half"></span><span
223
+ class="star"></span></span>
224
+ <span class="strong-rating-summary">4.3 stars (based on 9 ratings)</span></div>
225
+ </td>
226
+ </tr>
227
+ </table>
228
+
229
+ <table class="form-table shortcodes aggregate">
230
+ <tr>
231
+ <td rowspan="2">
232
+ <p><code>centered</code></p>
233
+ </td>
234
+ <td class="shortcode">&#91;testimonial_average_rating centered /&#93;</td>
235
+ </tr>
236
+ <tr>
237
+ <td>
238
+ <div class="strong-rating-wrapper average centered"><span class="strong-rating-title">Average Rating:</span>
239
+ <span class="strong-rating">
240
+ <span class="star0 star"></span>
241
+ <span class="star"></span><span class="star"></span><span class="star"></span><span class="star current half"></span><span
242
+ class="star"></span></span>
243
+ <span class="strong-rating-summary">4.3 stars (based on 9 ratings)</span></div>
244
+ </td>
245
+ </tr>
246
+ </table>
247
+
248
+ <table class="form-table shortcodes aggregate">
249
+ <tr>
250
+ <td rowspan="2">
251
+ <p><code>block</code> and <code>centered</code></p>
252
+ </td>
253
+ <td class="shortcode">&#91;testimonial_average_rating block centered /&#93;</td>
254
+ </tr>
255
+ <tr>
256
+ <td>
257
+ <div class="strong-rating-wrapper average block centered"><span class="strong-rating-title">Average Rating:</span>
258
+ <span class="strong-rating">
259
+ <span class="star0 star"></span>
260
+ <span class="star"></span><span class="star"></span><span class="star"></span><span class="star current half"></span><span class="star"></span></span>
261
+ <span class="strong-rating-summary">4.3 stars (based on 9 ratings)</span></div>
262
+ </td>
263
+ </tr>
264
+ </table>
265
+
266
+ <table class="form-table shortcodes aggregate">
267
+ <tr>
268
+ <td rowspan="2">
269
+ <p><?php _e( 'The default container element is <code>div</code>. Select another element using <code>element</code>.', 'strong-testimonials' ); ?></p>
270
+ </td>
271
+ <td class="shortcode">&#91;testimonial_average_rating element="span" /&#93;</td>
272
+ </tr>
273
+ <tr>
274
+ <td>
275
+ <span class="strong-rating-wrapper average"><span class="strong-rating-title">Average Rating:</span> <span
276
+ class="strong-rating">
277
+ <span class="star0 star"></span>
278
+ <span class="star"></span><span class="star"></span><span class="star"></span><span class="star current half"></span><span class="star"></span></span>
279
+ <span class="strong-rating-summary">4.3 stars (based on 9 ratings)</span></span>
280
+ </td>
281
+ </tr>
282
+ </table>
283
+
284
+ </div>
285
+ <?php
286
+ }
287
+
288
+ }
admin/class-strong-testimonials-updater.php CHANGED
@@ -206,10 +206,14 @@ class Strong_Testimonials_Updater {
206
  */
207
  public function update_addons() {
208
  $addons = get_option( 'wpmtst_addons' );
209
- foreach ( $addons as $addon => $data ) {
210
- $addons[ $addon ]['file'] = plugin_basename( basename( $data['file'], '.php' ) . '/' . basename( $data['file'] ) );
 
 
 
 
 
211
  }
212
- update_option( 'wpmtst_addons', $addons );
213
  }
214
 
215
  /**
@@ -383,35 +387,15 @@ class Strong_Testimonials_Updater {
383
  }
384
 
385
  /**
386
- * Custom fields
 
 
 
387
  *
388
  * @return array
389
  */
390
  public function update_fields() {
391
- $fields = get_option( 'wpmtst_fields', array() );
392
- if ( ! $fields ) {
393
- return Strong_Testimonials_Defaults::get_fields();
394
- }
395
-
396
- /**
397
- * Updating from 1.x
398
- *
399
- * Copy current custom fields to the new default custom form which will be added in the next step.
400
- *
401
- * @since 2.0.1
402
- * @since 2.17 Added version check.
403
- */
404
- if ( version_compare( '2.0', $this->old_version ) ) {
405
- if ( isset( $fields['field_groups'] ) ) {
406
- $default_custom_forms[1]['fields'] = $fields['field_groups']['custom']['fields'];
407
- unset( $fields['field_groups'] );
408
- }
409
- if ( isset( $fields['current_field_group'] ) ) {
410
- unset( $fields['current_field_group'] );
411
- }
412
- }
413
-
414
- return $fields;
415
  }
416
 
417
  /**
@@ -639,9 +623,39 @@ class Strong_Testimonials_Updater {
639
 
640
  // Merge in new options.
641
  $defaults = Strong_Testimonials_Defaults::get_compat_options();
 
642
  // Merge nested arrays individually. Don't use array_merge_recursive.
643
- $options['ajax'] = array_merge( $defaults['ajax'], $options['ajax'] );
644
- $options = array_merge( $defaults, $options );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
645
 
646
  return $options;
647
  }
206
  */
207
  public function update_addons() {
208
  $addons = get_option( 'wpmtst_addons' );
209
+ if ( $addons ) {
210
+ foreach ( $addons as $addon => $data ) {
211
+ if ( isset( $addons[ $addon ]['file'] ) ) {
212
+ $addons[ $addon ]['file'] = plugin_basename( basename( $data['file'], '.php' ) . '/' . basename( $data['file'] ) );
213
+ }
214
+ }
215
+ update_option( 'wpmtst_addons', $addons );
216
  }
 
217
  }
218
 
219
  /**
387
  }
388
 
389
  /**
390
+ * Default custom fields.
391
+ *
392
+ * @since 2.31.0 There is a rare bug/conflict where the default fields are incomplete.
393
+ * Overwrite existing fields on every update to auto-repair.
394
  *
395
  * @return array
396
  */
397
  public function update_fields() {
398
+ return Strong_Testimonials_Defaults::get_fields();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  }
400
 
401
  /**
623
 
624
  // Merge in new options.
625
  $defaults = Strong_Testimonials_Defaults::get_compat_options();
626
+
627
  // Merge nested arrays individually. Don't use array_merge_recursive.
628
+
629
+ if ( isset( $options['controller'] ) ) {
630
+ $options['ajax'] = array_merge( $defaults['ajax'], $options['ajax'] );
631
+ } else {
632
+ $options['ajax'] = $defaults['ajax'];
633
+ }
634
+
635
+ /**
636
+ * Controller
637
+ *
638
+ * @since 2.31.0
639
+ */
640
+ if ( isset( $options['controller'] ) ) {
641
+ $options['controller'] = array_merge( $defaults['controller'], $options['controller'] );
642
+ } else {
643
+ $options['controller'] = $defaults['controller'];
644
+ }
645
+
646
+ /**
647
+ * Lazy load
648
+ *
649
+ * @since 2.31.0
650
+ */
651
+ if ( isset( $options['lazyload'] ) ) {
652
+ // first level only: enabled, classes (array)
653
+ $options['lazyload'] = array_merge( $defaults['lazyload'], $options['lazyload'] );
654
+ } else {
655
+ $options['lazyload'] = $defaults['lazyload'];
656
+ }
657
+
658
+ $options = array_merge( $defaults, $options );
659
 
660
  return $options;
661
  }
admin/class-strong-views-list-table.php CHANGED
@@ -2,13 +2,23 @@
2
  /**
3
  * Admin List Table
4
  *
5
- * @version 0.2.0
6
  */
7
 
8
  class Strong_Views_List_Table extends Strong_Testimonials_List_Table {
9
 
10
  public $stickies;
11
 
 
 
 
 
 
 
 
 
 
 
12
  public function prepare_list( $data = array() ) {
13
  $this->stickies = get_option( 'wpmtst_sticky_views', array() );
14
 
@@ -152,7 +162,7 @@ class Strong_Views_List_Table extends Strong_Testimonials_List_Table {
152
  if ( 'single_template' == $item['data']['mode'] ) {
153
  $text = '';
154
  } else {
155
- $text = "[testimonial_view id={$item['id']}]";
156
  }
157
  break;
158
  default:
2
  /**
3
  * Admin List Table
4
  *
5
+ * @version 0.2.1
6
  */
7
 
8
  class Strong_Views_List_Table extends Strong_Testimonials_List_Table {
9
 
10
  public $stickies;
11
 
12
+ /**
13
+ * Message to be displayed when there are no items
14
+ *
15
+ * @since 0.2.1
16
+ * @access public
17
+ */
18
+ public function no_items() {
19
+ _e( 'No views found.', 'strong-testimonials' );
20
+ }
21
+
22
  public function prepare_list( $data = array() ) {
23
  $this->stickies = get_option( 'wpmtst_sticky_views', array() );
24
 
162
  if ( 'single_template' == $item['data']['mode'] ) {
163
  $text = '';
164
  } else {
165
+ $text = '[testimonial_view id="' . $item['id'] . '"]';
166
  }
167
  break;
168
  default:
admin/css/admin-compat.css CHANGED
@@ -5,101 +5,92 @@
5
  * Basic structure
6
  */
7
  div.row {
8
- display: table-row;
9
- }
10
- div.row > div {
11
- display: table-cell;
12
- }
13
- div.row:not(:last-child) > div {
14
- padding-bottom: 0.5em;
15
- }
16
- div.row p {
17
- margin-bottom: 0.5em;
18
- }
19
- div.row.header p {
20
- margin-bottom: 1em;
21
- }
22
 
23
  /**
24
  * Elements
25
  */
26
  .wrap.wpmtst h2 {
27
- margin: 2em 0 1em;
28
- }
29
- .wrap.wpmtst h2.nav-tab-wrapper {
30
- margin-top: 6px;
31
- }
32
 
33
  input.element {
34
- width: 15em;
35
- }
36
 
37
  /**
38
  * Behavior
39
  */
40
  .hidden {
41
- display: none;
42
- }
43
 
44
  [data-sub] {
45
- display: none;
46
- }
47
 
48
  /**
49
  * Common scenarios table
50
  */
51
  div.scenarios div.row {
52
- border: 1px solid #DDD;
53
- }
54
- div.scenarios div.row > div {
55
- padding: 1em;
56
- }
57
- div.scenarios div.row > div:first-child {
58
- width: 35%;
59
- border-right: 1px dotted #DDD;
60
- }
61
- div.scenarios div.row > div:last-child {
62
- width: 30%;
63
- border-left: 1px dotted #DDD;
64
- }
65
- div.scenarios div.row p {
66
- font-size: 14px;
67
- margin: 0;
68
- }
69
- div.scenarios div.row p:not(:last-child) {
70
- margin-bottom: 1em;
71
- }
72
- div.scenarios div.row.header > div {
73
- font-weight: 600;
74
- padding: 0.5em 1em;
75
- }
76
 
77
  /**
78
  * Settings table
79
  */
80
  div.row:not(:last-child) > div:nth-child(2) {
81
- padding-bottom: 0.5em;
82
- }
83
- div.row > div:first-child {
84
- width: 180px;
85
- }
86
  div.row > div.radio-sub label {
87
  text-indent: 24px;
88
- }
89
  div.row p.about {
90
  display: inline-block;
91
- }
92
- div.row p.about.adjacent {
93
- margin-left: 0.5em;
94
- }
95
  div.row p.description {
96
  display: inline-block;
97
- font-size: 14px;
98
- }
99
  div.row label.current {
100
- font-weight: 600;
101
- }
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  /**
104
  * Number spinner
105
  */
@@ -108,93 +99,80 @@ div.row label.current {
108
  margin-right: 10px;
109
  /**
110
  * Disable text selection on buttons. Seems to help jittery pointers.
111
- */
112
- }
113
- .number-style input {
114
- margin: 0 5px;
115
- font-family: Consolas, Monaco, monospace;
116
- text-align: center;
117
- width: 4em;
118
- }
119
- .number-style > span {
120
- cursor: pointer;
121
- }
122
- .number-style > span.number-minus, .number-style > span.number-plus {
123
- height: 24px;
124
- width: 24px;
125
- display: inline-block;
126
- text-align: center;
127
- vertical-align: top;
128
- border-radius: 3px;
129
- background: #0085ba;
130
- border-width: 1px;
131
- border-style: solid;
132
- border-color: #0073aa #006799 #006799;
133
- -webkit-box-shadow: 0 1px 0 #006799;
134
- box-shadow: 0 1px 0 #006799;
135
- text-shadow: 0 -1px 1px #006799, 1px 0 1px #006799, 0 1px 1px #006799, -1px 0 1px #006799;
136
- color: #FFF;
137
- }
138
- .number-style > span.number-minus:hover, .number-style > span.number-plus:hover {
139
- background: #008ec2;
140
- }
141
- .number-style > span.number-minus:active, .number-style > span.number-plus:active {
142
- background: #0073aa;
143
- border-color: #006799;
144
- -webkit-box-shadow: inset 0 2px 0 #006799;
145
- box-shadow: inset 0 2px 0 #006799;
146
- -webkit-transform: translateY(1px);
147
- -ms-transform: translateY(1px);
148
- transform: translateY(1px);
149
- outline: none;
150
- }
151
- .number-style > span.number-minus.disabled, .number-style > span.number-plus.disabled {
152
- background: #AAA;
153
- border-color: #999 #777 #777;
154
- -webkit-box-shadow: 0 1px 0 #777;
155
- box-shadow: 0 1px 0 #777;
156
- text-shadow: 0 -1px 1px #777, 1px 0 1px #777, 0 1px 1px #777, -1px 0 1px #777;
157
- }
158
- .number-style > span.number-minus::after, .number-style > span.number-plus::after {
159
- font-family: dashicons;
160
- font-size: 24px;
161
- line-height: 24px;
162
- height: 24px;
163
- width: 24px;
164
- display: inline-block;
165
- color: #FFF;
166
- text-align: center;
167
- position: relative;
168
- left: -1px;
169
- }
170
- .number-style > span.number-minus::after {
171
- content: "\f140";
172
- }
173
- .number-style > span.number-plus::after {
174
- content: "\f142";
175
- }
176
- .number-style input[type='number'] {
177
- -moz-appearance: textfield;
178
- }
179
- .number-style input::-webkit-outer-spin-button,
180
- .number-style input::-webkit-inner-spin-button {
181
- -webkit-appearance: none;
182
- }
183
- .number-style .number-minus,
184
- .number-style .number-plus,
185
- .number-style .number-minus::after,
186
- .number-style .number-plus::after {
187
- -webkit-touch-callout: none;
188
- /* iOS Safari */
189
- -webkit-user-select: none;
190
- /* Safari */
191
- -khtml-user-select: none;
192
- /* Konqueror HTML */
193
- -moz-user-select: none;
194
- /* Firefox */
195
- -ms-user-select: none;
196
- /* Internet Explorer/Edge */
197
- user-select: none;
198
- /* Non-prefixed version, currently
199
- supported by Chrome and Opera */
200
- }
5
  * Basic structure
6
  */
7
  div.row {
8
+ display: table-row; }
9
+ div.row > div {
10
+ display: table-cell; }
11
+ div.row > div:first-child {
12
+ width: 200px; }
13
+ div.row:not(:last-child) > div {
14
+ padding-bottom: 0.5em; }
15
+ div.row p {
16
+ margin-bottom: 0.5em; }
17
+ div.row.header p {
18
+ margin-bottom: 1em; }
 
 
 
19
 
20
  /**
21
  * Elements
22
  */
23
  .wrap.wpmtst h2 {
24
+ margin: 2em 0 1em; }
25
+ .wrap.wpmtst h2.nav-tab-wrapper {
26
+ margin-top: 6px; }
 
 
27
 
28
  input.element {
29
+ width: 15em; }
 
30
 
31
  /**
32
  * Behavior
33
  */
34
  .hidden {
35
+ display: none; }
 
36
 
37
  [data-sub] {
38
+ display: none; }
 
39
 
40
  /**
41
  * Common scenarios table
42
  */
43
  div.scenarios div.row {
44
+ border: 1px solid #DDD; }
45
+ div.scenarios div.row > div {
46
+ padding: 1em; }
47
+ div.scenarios div.row > div:first-child {
48
+ width: 35%;
49
+ border-right: 1px dotted #DDD; }
50
+ div.scenarios div.row > div:last-child {
51
+ width: 30%;
52
+ border-left: 1px dotted #DDD; }
53
+ div.scenarios div.row p {
54
+ font-size: 14px;
55
+ margin: 0; }
56
+ div.scenarios div.row p:not(:last-child) {
57
+ margin-bottom: 1em; }
58
+ div.scenarios div.row.header > div {
59
+ font-weight: 600;
60
+ padding: 0.5em 1em; }
 
 
 
 
 
 
 
61
 
62
  /**
63
  * Settings table
64
  */
65
  div.row:not(:last-child) > div:nth-child(2) {
66
+ padding-bottom: 0.5em; }
 
 
 
 
67
  div.row > div.radio-sub label {
68
  text-indent: 24px;
69
+ width: 200px; }
70
  div.row p.about {
71
  display: inline-block;
72
+ vertical-align: middle; }
73
+ div.row p.about.adjacent {
74
+ margin-left: 0.5em; }
 
75
  div.row p.description {
76
  display: inline-block;
77
+ font-size: 14px; }
 
78
  div.row label.current {
79
+ font-weight: 600; }
 
80
 
81
+ /**
82
+ * Lazy load class name pairs
83
+ */
84
+ .pair-actions {
85
+ margin-top: 10px; }
86
+
87
+ .pair-sep {
88
+ margin-right: 1em; }
89
+
90
+ @media only screen and (max-width: 1024px) {
91
+ .lazyload-pairs .pair {
92
+ border: 1px solid #DDD;
93
+ padding: 5px 10px; } }
94
  /**
95
  * Number spinner
96
  */
99
  margin-right: 10px;
100
  /**
101
  * Disable text selection on buttons. Seems to help jittery pointers.
102
+ */ }
103
+ .number-style input {
104
+ margin: 0 5px;
105
+ font-family: Consolas, Monaco, monospace;
106
+ text-align: center;
107
+ width: 4em; }
108
+ .number-style > span {
109
+ cursor: pointer; }
110
+ .number-style > span.number-minus, .number-style > span.number-plus {
111
+ height: 24px;
112
+ width: 24px;
113
+ display: inline-block;
114
+ text-align: center;
115
+ vertical-align: top;
116
+ border-radius: 3px;
117
+ background: #0085ba;
118
+ border-width: 1px;
119
+ border-style: solid;
120
+ border-color: #0073aa #006799 #006799;
121
+ -webkit-box-shadow: 0 1px 0 #006799;
122
+ box-shadow: 0 1px 0 #006799;
123
+ text-shadow: 0 -1px 1px #006799, 1px 0 1px #006799, 0 1px 1px #006799, -1px 0 1px #006799;
124
+ color: #FFF; }
125
+ .number-style > span.number-minus:hover, .number-style > span.number-plus:hover {
126
+ background: #008ec2; }
127
+ .number-style > span.number-minus:active, .number-style > span.number-plus:active {
128
+ background: #0073aa;
129
+ border-color: #006799;
130
+ -webkit-box-shadow: inset 0 2px 0 #006799;
131
+ box-shadow: inset 0 2px 0 #006799;
132
+ -webkit-transform: translateY(1px);
133
+ -ms-transform: translateY(1px);
134
+ transform: translateY(1px);
135
+ outline: none; }
136
+ .number-style > span.number-minus.disabled, .number-style > span.number-plus.disabled {
137
+ background: #AAA;
138
+ border-color: #999 #777 #777;
139
+ -webkit-box-shadow: 0 1px 0 #777;
140
+ box-shadow: 0 1px 0 #777;
141
+ text-shadow: 0 -1px 1px #777, 1px 0 1px #777, 0 1px 1px #777, -1px 0 1px #777; }
142
+ .number-style > span.number-minus::after, .number-style > span.number-plus::after {
143
+ font-family: dashicons;
144
+ font-size: 24px;
145
+ line-height: 24px;
146
+ height: 24px;
147
+ width: 24px;
148
+ display: inline-block;
149
+ color: #FFF;
150
+ text-align: center;
151
+ position: relative;
152
+ left: -1px; }
153
+ .number-style > span.number-minus::after {
154
+ content: "\f140"; }
155
+ .number-style > span.number-plus::after {
156
+ content: "\f142"; }
157
+ .number-style input[type='number'] {
158
+ -moz-appearance: textfield; }
159
+ .number-style input::-webkit-outer-spin-button,
160
+ .number-style input::-webkit-inner-spin-button {
161
+ -webkit-appearance: none; }
162
+ .number-style .number-minus,
163
+ .number-style .number-plus,
164
+ .number-style .number-minus::after,
165
+ .number-style .number-plus::after {
166
+ -webkit-touch-callout: none;
167
+ /* iOS Safari */
168
+ -webkit-user-select: none;
169
+ /* Safari */
170
+ -khtml-user-select: none;
171
+ /* Konqueror HTML */
172
+ -moz-user-select: none;
173
+ /* Firefox */
174
+ -ms-user-select: none;
175
+ /* Internet Explorer/Edge */
176
+ user-select: none;
177
+ /* Non-prefixed version, currently
178
+ supported by Chrome and Opera */ }
 
 
 
 
 
 
 
 
 
 
 
 
 
admin/css/admin.css CHANGED
@@ -324,7 +324,7 @@ div.radio:hover {
324
  }
325
 
326
  .submit-buttons input.button {
327
- margin-right: 5px;
328
  }
329
 
330
  .custom-input {
@@ -777,4 +777,23 @@ ul.standard {
777
 
778
  .form-table p.error {
779
  margin: 0.5em 0;
780
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
324
  }
325
 
326
  .submit-buttons input.button {
327
+ margin-right: 10px;
328
  }
329
 
330
  .custom-input {
777
 
778
  .form-table p.error {
779
  margin: 0.5em 0;
780
+ }
781
+
782
+ /* shortcodes page */
783
+ .wpmtst.shortcodes.has-stars table {
784
+ margin-bottom: 1em;
785
+ }
786
+ .wpmtst.shortcodes.has-stars td:nth-child(2) {
787
+ width: 70%;
788
+ /*white-space: nowrap;*/
789
+ }
790
+ .wpmtst.shortcodes td {
791
+ padding: 10px;
792
+ }
793
+ .wpmtst.shortcodes tr.important td {
794
+ border: 1px solid #DDD;
795
+ }
796
+ .wpmtst.shortcodes tr:hover,
797
+ .wpmtst.shortcodes tr:hover + tr {
798
+ background: #FFF;
799
+ }
admin/css/views.css CHANGED
@@ -952,4 +952,13 @@ table.wpmtst-help-tab {
952
  right: 0;
953
  background: rgba(255, 255, 255, 0.7); }
954
 
955
- /*# sourceMappingURL=views.css.map */
 
 
 
 
 
 
 
 
 
952
  right: 0;
953
  background: rgba(255, 255, 255, 0.7); }
954
 
955
+ .form-table td p.description.normal {
956
+ font-style: normal; }
957
+
958
+ ul.description.normal {
959
+ margin-top: 0;
960
+ font-style: normal; }
961
+
962
+ ul.description li {
963
+ margin-bottom: 0;
964
+ line-height: 1.5; }
admin/js/admin-compat.js CHANGED
@@ -39,6 +39,7 @@
39
  }
40
 
41
  // Update available options --- not currently used
 
42
  function matchMethodSetting () {
43
  if ($('#prerender-current').is(':checked')) {
44
  saveCurrentSettings()
@@ -59,6 +60,7 @@
59
  }
60
  }
61
  }
 
62
 
63
  // UI
64
  function highlightRadioLabel () {
@@ -101,12 +103,25 @@
101
  })
102
 
103
  // Listen for presets
104
- $('#set-scenario-1').click(function(e) {
105
  $(this).blur()
106
  setScenario1()
107
  e.preventDefault()
108
  })
109
 
 
 
 
 
 
 
 
 
 
 
 
 
 
110
  // Start
111
  saveCurrentSettings()
112
  updateDisplay()
39
  }
40
 
41
  // Update available options --- not currently used
42
+ /*
43
  function matchMethodSetting () {
44
  if ($('#prerender-current').is(':checked')) {
45
  saveCurrentSettings()
60
  }
61
  }
62
  }
63
+ */
64
 
65
  // UI
66
  function highlightRadioLabel () {
103
  })
104
 
105
  // Listen for presets
106
+ $('#set-scenario-1').on('click', function(e) {
107
  $(this).blur()
108
  setScenario1()
109
  e.preventDefault()
110
  })
111
 
112
+ // Listen for [Add Row]
113
+ $('#add-pair').on('click', function (e) {
114
+ var $this = $(this);
115
+ var key = $this.closest('.lazyload-pairs').find('.pair').length;
116
+ var data = {
117
+ 'action': 'wpmtst_add_lazyload_pair',
118
+ 'key': key,
119
+ };
120
+ $.get(ajaxurl, data, function (response) {
121
+ $this.parent().before(response.data).prev().find('input').first().focus();
122
+ });
123
+ });
124
+
125
  // Start
126
  saveCurrentSettings()
127
  updateDisplay()
admin/menu/class-strong-testimonials-menu-shortcodes.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class Strong_Testimonials_Menu_Shortcodes
4
+ */
5
+ class Strong_Testimonials_Menu_Shortcodes {
6
+
7
+ /**
8
+ * Strong_Testimonials_Menu_Shortcodes constructor.
9
+ */
10
+ public function __construct() {}
11
+
12
+ /**
13
+ * Initialize.
14
+ */
15
+ public static function init() {
16
+ self::add_actions();
17
+ }
18
+
19
+ /**
20
+ * Add actions and filters.
21
+ */
22
+ public static function add_actions() {
23
+ add_filter( 'wpmtst_submenu_pages', array( __CLASS__, 'add_submenu' ) );
24
+ }
25
+
26
+ /**
27
+ * Add submenu page.
28
+ *
29
+ * @param $pages
30
+ *
31
+ * @return mixed
32
+ */
33
+ public static function add_submenu( $pages ) {
34
+ $pages[40] = self::get_submenu();
35
+ return $pages;
36
+ }
37
+
38
+ /**
39
+ * Return submenu page parameters.
40
+ *
41
+ * @return array
42
+ */
43
+ public static function get_submenu() {
44
+ return array(
45
+ 'page_title' => apply_filters( 'wpmtst_shortcodes_page_title', __( 'Shortcodes', 'strong-testimonials' ) ),
46
+ 'menu_title' => apply_filters( 'wpmtst_shortcodes_menu_title', __( 'Shortcodes', 'strong-testimonials' ) ),
47
+ 'capability' => 'strong_testimonials_options',
48
+ 'menu_slug' => 'testimonial-shortcodes',
49
+ 'function' => array( 'Strong_Testimonials_Page_Shortcodes', 'render_page' ),
50
+ );
51
+ }
52
+
53
+ }
54
+
55
+ Strong_Testimonials_Menu_Shortcodes::init();
admin/partials/views/view-shortcode.php CHANGED
@@ -2,7 +2,7 @@
2
  // avoiding the tab character before the shortcode for better copy-n-paste
3
  if ( 'edit' == $action ) {
4
  $shortcode = '<div class="saved">';
5
- $shortcode .= '<input id="view-shortcode" type="text" value="[testimonial_view id=' . $view_id . ']" readonly />';
6
  $shortcode .= '<input id="copy-shortcode" class="button small" type="button" value="' . __( 'copy to clipboard', 'strong-testimonials' ) . '" data-copytarget="#view-shortcode" />';
7
  $shortcode .= '<span id="copy-message">copied</span>';
8
  $shortcode .= '</div>';
2
  // avoiding the tab character before the shortcode for better copy-n-paste
3
  if ( 'edit' == $action ) {
4
  $shortcode = '<div class="saved">';
5
+ $shortcode .= '<input id="view-shortcode" type="text" value="[testimonial_view id=&quot;' . $view_id . '&quot;]" readonly />';
6
  $shortcode .= '<input id="copy-shortcode" class="button small" type="button" value="' . __( 'copy to clipboard', 'strong-testimonials' ) . '" data-copytarget="#view-shortcode" />';
7
  $shortcode .= '<span id="copy-message">copied</span>';
8
  $shortcode .= '</div>';
admin/scss/admin-compat.scss CHANGED
@@ -10,6 +10,10 @@ div.row {
10
 
11
  > div {
12
  display: table-cell;
 
 
 
 
13
  }
14
 
15
  &:not(:last-child) > div {
@@ -108,12 +112,12 @@ div.row {
108
  > div {
109
 
110
  &:first-child {
111
- width: 180px;
112
  }
113
 
114
  &.radio-sub {
115
  label {
116
  text-indent: 24px;
 
117
  }
118
  }
119
  }
@@ -121,6 +125,7 @@ div.row {
121
  p {
122
  &.about {
123
  display: inline-block;
 
124
 
125
  &.adjacent {
126
  margin-left: 0.5em;
@@ -138,4 +143,24 @@ div.row {
138
  }
139
  }
140
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
141
  @import "number-spinner.scss";
10
 
11
  > div {
12
  display: table-cell;
13
+
14
+ &:first-child {
15
+ width: 200px;
16
+ }
17
  }
18
 
19
  &:not(:last-child) > div {
112
  > div {
113
 
114
  &:first-child {
 
115
  }
116
 
117
  &.radio-sub {
118
  label {
119
  text-indent: 24px;
120
+ width: 200px;
121
  }
122
  }
123
  }
125
  p {
126
  &.about {
127
  display: inline-block;
128
+ vertical-align: middle;
129
 
130
  &.adjacent {
131
  margin-left: 0.5em;
143
  }
144
  }
145
 
146
+ /**
147
+ * Lazy load class name pairs
148
+ */
149
+ .pair-actions {
150
+ margin-top: 10px;
151
+ }
152
+
153
+ .pair-sep {
154
+ margin-right: 1em;
155
+ }
156
+
157
+ @media only screen and (max-width: 1024px) {
158
+ .lazyload-pairs {
159
+ .pair {
160
+ border: 1px solid #DDD;
161
+ padding: 5px 10px;
162
+ }
163
+ }
164
+ }
165
+
166
  @import "number-spinner.scss";
admin/scss/views.scss CHANGED
@@ -31,3 +31,16 @@ $grayedout: #888;
31
  @import "_partials/custom-fields";
32
  @import "_partials/help-tab";
33
  @import "_partials/sticky-views";
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  @import "_partials/custom-fields";
32
  @import "_partials/help-tab";
33
  @import "_partials/sticky-views";
34
+
35
+ // TODO Find a home for these in partials.
36
+ .form-table td p.description.normal {
37
+ font-style: normal;
38
+ }
39
+ ul.description.normal {
40
+ margin-top: 0;
41
+ font-style: normal;
42
+ }
43
+ ul.description li {
44
+ margin-bottom: 0;
45
+ line-height: 1.5;
46
+ }
admin/settings/class-strong-testimonials-settings-compat.php CHANGED
@@ -30,6 +30,7 @@ class Strong_Testimonials_Settings_Compat {
30
  add_action( 'wpmtst_register_settings', array( $this, 'register_settings' ) );
31
  add_action( 'wpmtst_settings_tabs', array( $this, 'register_tab' ), 3, 2 );
32
  add_filter( 'wpmtst_settings_callbacks', array( $this, 'register_settings_page' ) );
 
33
  }
34
 
35
  /**
@@ -70,18 +71,22 @@ class Strong_Testimonials_Settings_Compat {
70
  * Sanitize settings.
71
  *
72
  * @param $input
73
- *
 
 
74
  * @return array
75
  */
76
  public function sanitize_options( $input ) {
77
- $input['page_loading'] = sanitize_text_field( $input['page_loading'] );
 
78
  if ( 'general' == $input['page_loading'] ) {
79
  $input['prerender'] = 'all';
80
  $input['ajax']['method'] = 'universal';
81
- } else {
82
  $input['prerender'] = sanitize_text_field( $input['prerender'] );
83
  $input['ajax']['method'] = sanitize_text_field( $input['ajax']['method'] );
84
  }
 
85
  $input['ajax']['universal_timer'] = floatval( sanitize_text_field( $input['ajax']['universal_timer'] ) );
86
  $input['ajax']['observer_timer'] = floatval( sanitize_text_field( $input['ajax']['observer_timer'] ) );
87
  $input['ajax']['container_id'] = sanitize_text_field( $input['ajax']['container_id'] );
@@ -89,6 +94,19 @@ class Strong_Testimonials_Settings_Compat {
89
  $input['ajax']['event'] = sanitize_text_field( $input['ajax']['event'] );
90
  $input['ajax']['script'] = sanitize_text_field( $input['ajax']['script'] );
91
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  return $input;
93
  }
94
 
@@ -102,12 +120,17 @@ class Strong_Testimonials_Settings_Compat {
102
 
103
  /**
104
  * Compatibility settings
 
 
 
105
  */
106
  public function settings_top() {
107
  $this->settings_intro();
108
  $this->settings_page_loading();
109
  $this->settings_prerender();
110
  $this->settings_monitor();
 
 
111
  }
112
 
113
  /**
@@ -115,47 +138,76 @@ class Strong_Testimonials_Settings_Compat {
115
  */
116
  public function settings_intro() {
117
  ?>
118
- <h2><?php _e( 'Common Scenarios' ); ?></h2>
119
- <table class="form-table" cellpadding="0" cellspacing="0">
120
- <tr valign="top">
121
- <td>
122
-
123
- <div class="scenarios">
124
- <div class="row header">
125
- <div>
126
- <?php _e( 'Views Not Working', 'strong-testimonials' ); ?>
127
- </div>
128
- <div>
129
  <?php _e( 'Possible Cause', 'strong-testimonials' ); ?>
130
- </div>
131
- <div>
132
- <?php _e( 'Solution', 'strong-testimonials' ); ?>
133
- </div>
134
- </div>
135
-
136
- <div class="row">
137
- <div>
138
- <p><?php _e( 'A testimonial view does not look right the first time you view the page.', 'strong-testimonials' ); ?></p>
139
- <p><?php _e( 'For example, it does not seem to have any style, the slideshow has not started, or the pagination is missing.', 'strong-testimonials' ); ?></p>
140
- <p><?php _e( 'When you refresh the page, the view does appear correctly.', 'strong-testimonials' ); ?></p>
141
- </div>
142
- <div>
143
- <p><?php _e( 'Your site is using <strong>Ajax page loading</strong> &ndash; also known as page animations, transition effects or Pjax (pushState Ajax) &ndash; provided by your theme or another plugin.', 'strong-testimonials' ); ?></p>
144
- <p><?php _e( 'Instead of loading the entire page, this technique fetches only the new content.', 'strong-testimonials' ); ?></p>
145
- </div>
146
- <div>
147
- <p><strong><?php _e( 'Ajax Page Loading', 'strong-testimonials' ); ?>
148
- :</strong> <?php _e( 'General', 'strong-testimonials' ); ?></p>
149
- <p><a href="#"
150
- id="set-scenario-1"><?php _ex( 'Set this now', 'link text on Settings > Compatibility tab', 'strong-testimonials' ); ?></a>
151
- </p>
152
- </div>
153
- </div>
154
- </div>
155
-
156
- </td>
157
- </tr>
158
- </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
159
  <?php
160
  }
161
 
@@ -164,28 +216,26 @@ class Strong_Testimonials_Settings_Compat {
164
  */
165
  public function settings_page_loading() {
166
  ?>
167
- <h2><?php _e( 'Ajax Page Loading' ); ?></h2>
168
-
169
- <table class="form-table" cellpadding="0" cellspacing="0">
170
- <tr valign="top">
171
- <th scope="row">
172
- <?php _e( 'Type', 'strong-testimonials' ); ?>
173
- </th>
174
- <td>
175
- <div class="row header">
176
- <p>
177
  <?php _e( 'This does not perform Ajax page loading.', 'strong-testimonials' ); ?>
178
  <?php _e( 'It provides compatibility with themes and plugins that use Ajax to load pages, also known as page animation or transition effects.', 'strong-testimonials' ); ?>
179
- </p>
180
- </div>
181
- <fieldset data-radio-group="prerender">
182
  <?php $this->settings_page_loading_none(); ?>
183
  <?php $this->settings_page_loading_general(); ?>
184
  <?php $this->settings_page_loading_advanced(); ?>
185
- </fieldset>
186
- </td>
187
- </tr>
188
- </table>
189
  <?php
190
  }
191
 
@@ -193,21 +243,26 @@ class Strong_Testimonials_Settings_Compat {
193
  * None (default)
194
  */
195
  public function settings_page_loading_none() {
 
 
196
  ?>
197
- <div class="row">
198
- <div>
199
- <label for="page-loading-none">
200
- <input type="radio" id="page-loading-none" name="wpmtst_compat_options[page_loading]"
201
- value="" <?php checked( $this->options['page_loading'], '' ); ?>/>
 
 
 
202
  <?php _e( 'None', 'strong-testimonials' ); ?>
203
- <em><?php _e( '(default)', 'strong-testimonials' ); ?></em>
204
- </label>
205
- </div>
206
- <div>
207
- <p class="about"><?php _e( 'No compatibility needed.', 'strong-testimonials' ); ?></p>
208
- <p class="about"><?php _e( 'This works well for most themes.', 'strong-testimonials' ); ?></p>
209
- </div>
210
- </div>
211
  <?php
212
  }
213
 
@@ -215,20 +270,25 @@ class Strong_Testimonials_Settings_Compat {
215
  * General
216
  */
217
  public function settings_page_loading_general() {
 
 
218
  ?>
219
- <div class="row">
220
- <div>
221
- <label for="page-loading-general">
222
- <input type="radio" id="page-loading-general" name="wpmtst_compat_options[page_loading]"
223
- value="general" <?php checked( $this->options['page_loading'], 'general' ); ?>/>
 
 
 
224
  <?php _e( 'General', 'strong-testimonials' ); ?>
225
- </label>
226
- </div>
227
- <div>
228
- <p class="about"><?php _e( 'Be ready to render any view at any time.', 'strong-testimonials' ); ?></p>
229
- <p class="about"><?php _e( 'This works well with common Ajax methods.', 'strong-testimonials' ); ?></p>
230
- </div>
231
- </div>
232
  <?php
233
  }
234
 
@@ -236,20 +296,25 @@ class Strong_Testimonials_Settings_Compat {
236
  * Advanced
237
  */
238
  public function settings_page_loading_advanced() {
 
 
239
  ?>
240
- <div class="row">
241
- <div>
242
- <label for="page-loading-advanced">
243
- <input type="radio" id="page-loading-advanced" name="wpmtst_compat_options[page_loading]"
244
- value="advanced" <?php checked( $this->options['page_loading'], 'advanced' ); ?>
245
- data-group="advanced"/>
 
 
 
246
  <?php _e( 'Advanced', 'strong-testimonials' ); ?>
247
- </label>
248
- </div>
249
- <div>
250
- <p class="about"><?php _e( 'For specific configurations.', 'strong-testimonials' ); ?></p>
251
- </div>
252
- </div>
253
  <?php
254
  }
255
 
@@ -258,25 +323,25 @@ class Strong_Testimonials_Settings_Compat {
258
  */
259
  public function settings_prerender() {
260
  ?>
261
- <table class="form-table" cellpadding="0" cellspacing="0" data-sub="advanced">
262
- <tr valign="top">
263
- <th scope="row">
264
  <?php _e( 'Prerender', 'strong-testimonials' ); ?>
265
- </th>
266
- <td>
267
- <div class="row header">
268
- <p><?php _e( 'Load stylesheets and populate script variables up front.', 'strong-testimonials' ); ?>
269
- <a class="open-help-tab" href="#tab-panel-wpmtst-help-prerender"><?php _e( 'Help' ); ?></a>
270
- </p>
271
- </div>
272
- <fieldset data-radio-group="prerender">
273
  <?php $this->settings_prerender_current(); ?>
274
  <?php $this->settings_prerender_all(); ?>
275
  <?php $this->settings_prerender_none(); ?>
276
- </fieldset>
277
- </td>
278
- </tr>
279
- </table>
280
  <?php
281
  }
282
 
@@ -284,21 +349,26 @@ class Strong_Testimonials_Settings_Compat {
284
  * Current (default)
285
  */
286
  public function settings_prerender_current() {
 
 
287
  ?>
288
- <div class="row">
289
- <div>
290
- <label for="prerender-current">
291
- <input type="radio" id="prerender-current" name="wpmtst_compat_options[prerender]"
292
- value="current" <?php checked( $this->options['prerender'], 'current' ); ?>/>
 
 
 
293
  <?php _e( 'Current page', 'strong-testimonials' ); ?>
294
- <em><?php _e( '(default)', 'strong-testimonials' ); ?></em>
295
- </label>
296
- </div>
297
- <div>
298
- <p class="about"><?php _e( 'For the current page only.', 'strong-testimonials' ); ?></p>
299
- <p class="about"><?php _e( 'This works well for most themes.', 'strong-testimonials' ); ?></p>
300
- </div>
301
- </div>
302
  <?php
303
  }
304
 
@@ -306,20 +376,25 @@ class Strong_Testimonials_Settings_Compat {
306
  * All
307
  */
308
  public function settings_prerender_all() {
 
 
309
  ?>
310
- <div class="row">
311
- <div>
312
- <label for="prerender-all">
313
- <input type="radio" id="prerender-all" name="wpmtst_compat_options[prerender]"
314
- value="all" <?php checked( $this->options['prerender'], 'all' ); ?>/>
 
 
 
315
  <?php _e( 'All views', 'strong-testimonials' ); ?>
316
- </label>
317
- </div>
318
- <div>
319
- <p class="about"><?php _e( 'For all views. Required for Ajax page loading.', 'strong-testimonials' ); ?></p>
320
- <p class="about"><?php _e( 'Then select an option for <strong>Monitor</strong> below.', 'strong-testimonials' ); ?></p>
321
- </div>
322
- </div>
323
  <?php
324
  }
325
 
@@ -327,19 +402,24 @@ class Strong_Testimonials_Settings_Compat {
327
  * None
328
  */
329
  public function settings_prerender_none() {
 
 
330
  ?>
331
- <div class="row">
332
- <div>
333
- <label for="prerender-none">
334
- <input type="radio" id="prerender-none" name="wpmtst_compat_options[prerender]"
335
- value="none" <?php checked( $this->options['prerender'], 'none' ); ?>/>
 
 
 
336
  <?php _e( 'None', 'strong-testimonials' ); ?>
337
- </label>
338
- </div>
339
- <div>
340
- <p class="about"><?php _e( 'When the shortcode is rendered. May result in a flash of unstyled content.', 'strong-testimonials' ); ?></p>
341
- </div>
342
- </div>
343
  <?php
344
  }
345
 
@@ -348,25 +428,25 @@ class Strong_Testimonials_Settings_Compat {
348
  */
349
  public function settings_monitor() {
350
  ?>
351
- <table class="form-table" cellpadding="0" cellspacing="0" data-sub="advanced">
352
- <tr valign="top">
353
- <th scope="row">
354
  <?php _e( 'Monitor', 'strong-testimonials' ); ?>
355
- </th>
356
- <td>
357
- <div class="row header">
358
- <p><?php _e( 'Initialize slideshows, pagination and form validation as pages change.', 'strong-testimonials' ); ?></p>
359
- </div>
360
- <fieldset data-radio-group="method">
361
  <?php $this->settings_monitor_none(); ?>
362
  <?php $this->settings_monitor_universal(); ?>
363
  <?php $this->settings_monitor_observer(); ?>
364
  <?php $this->settings_monitor_event(); ?>
365
  <?php $this->settings_monitor_script(); ?>
366
- </fieldset>
367
- </td>
368
- </tr>
369
- </table>
370
  <?php
371
  }
372
 
@@ -374,20 +454,25 @@ class Strong_Testimonials_Settings_Compat {
374
  * None
375
  */
376
  public function settings_monitor_none() {
 
 
377
  ?>
378
- <div class="row">
379
- <div>
380
- <label for="method-none">
381
- <input type="radio" id="method-none" name="wpmtst_compat_options[ajax][method]" value=""
382
- <?php checked( $this->options['ajax']['method'], '' ); ?> />
 
 
 
383
  <?php _e( 'None', 'strong-testimonials' ); ?>
384
- <em><?php _e( '(default)', 'strong-testimonials' ); ?></em>
385
- </label>
386
- </div>
387
- <div>
388
- <p class="about"><?php _e( 'No compatibility needed.', 'strong-testimonials' ); ?></p>
389
- </div>
390
- </div>
391
  <?php
392
  }
393
 
@@ -395,37 +480,42 @@ class Strong_Testimonials_Settings_Compat {
395
  * Universal (timer)
396
  */
397
  public function settings_monitor_universal() {
 
 
398
  ?>
399
- <div class="row">
400
- <div>
401
- <label for="method-universal">
402
- <input type="radio"
403
- id="method-universal"
404
- name="wpmtst_compat_options[ajax][method]"
405
- value="universal"
406
- <?php checked( $this->options['ajax']['method'], 'universal' ); ?>
407
- data-group="universal"/>
408
  <?php _e( 'Universal', 'strong-testimonials' ); ?>
409
- </label>
410
- </div>
411
- <div>
412
- <p class="about"><?php _e( 'Watch for page changes on a timer.', 'strong-testimonials' ); ?></p>
413
- </div>
414
- </div>
415
-
416
- <div class="row" data-sub="universal">
417
- <div class="radio-sub">
418
- <label for="universal-timer">
419
  <?php _ex( 'Check every', 'timer setting', 'strong-testimonials' ); ?>
420
- </label>
421
- </div>
422
- <div>
423
- <input type="number" id="universal-timer" name="wpmtst_compat_options[ajax][universal_timer]"
424
- min=".1" max="5" step=".1" size="3"
425
- value="<?php echo $this->options['ajax']['universal_timer']; ?>"/>
 
 
 
426
  <?php _ex( 'seconds', 'timer setting', 'strong-testimonials' ); ?>
427
- </div>
428
- </div>
429
  <?php
430
  }
431
 
@@ -433,81 +523,92 @@ class Strong_Testimonials_Settings_Compat {
433
  * Observer
434
  */
435
  public function settings_monitor_observer() {
 
 
436
  ?>
437
- <div class="row">
438
- <div>
439
- <label for="method-observer">
440
- <input type="radio" id="method-observer" name="wpmtst_compat_options[ajax][method]" value="observer"
441
- <?php checked( $this->options['ajax']['method'], 'observer' ); ?>
442
- data-group="observer"/>
 
 
 
443
  <?php _e( 'Observer', 'strong-testimonials' ); ?>
444
- </label>
445
- </div>
446
- <div>
447
- <p class="about"><?php _e( 'React to changes in specific page elements.', 'strong-testimonials' ); ?></p>
448
- <p class="description"><?php _e( 'For advanced users.', 'strong-testimonials' ); ?></p>
449
- </div>
450
- </div>
451
 
452
  <?php
453
  /*
454
  * Timer
455
  */
456
  ?>
457
- <div class="row" data-sub="observer">
458
- <div class="radio-sub">
459
- <label for="observer-timer">
460
  <?php _ex( 'Check once after', 'timer setting', 'strong-testimonials' ); ?>
461
- </label>
462
- </div>
463
- <div>
464
- <input type="number" id="observer-timer"
465
- name="wpmtst_compat_options[ajax][observer_timer]"
466
- min=".1" max="5" step=".1" size="3"
467
- value="<?php echo $this->options['ajax']['observer_timer']; ?>"/>
 
 
468
  <?php _ex( 'seconds', 'timer setting', 'strong-testimonials' ); ?>
469
- </div>
470
- </div>
471
 
472
  <?php
473
  /*
474
  * Container element ID
475
  */
476
  ?>
477
- <div class="row" data-sub="observer">
478
- <div class="radio-sub">
479
- <label for="container-id">
480
  <?php _e( 'Container ID', 'strong-testimonials' ); ?>
481
- </label>
482
- </div>
483
- <div>
484
- <span class="code input-before">#</span>
485
- <input type="text" id="container-id" class="code element"
486
- name="wpmtst_compat_options[ajax][container_id]"
487
- value="<?php echo $this->options['ajax']['container_id']; ?>"/>
488
- <p class="about adjacent"><?php _e( 'the element to observe', 'strong-testimonials' ); ?></p>
489
- </div>
490
- </div>
 
 
491
 
492
  <?php
493
  /*
494
  * Added node ID
495
  */
496
  ?>
497
- <div class="row" data-sub="observer">
498
- <div class="radio-sub">
499
- <label for="addednode-id">
500
  <?php _e( 'Added node ID', 'strong-testimonials' ); ?>
501
- </label>
502
- </div>
503
- <div>
504
- <span class="code input-before">#</span>
505
- <input type="text" id="addednode-id" class="code element"
506
- name="wpmtst_compat_options[ajax][addednode_id]"
507
- value="<?php echo $this->options['ajax']['addednode_id']; ?>"/>
508
- <p class="about adjacent"><?php _e( 'the element being added', 'strong-testimonials' ); ?></p>
509
- </div>
510
- </div>
 
 
511
  <?php
512
  }
513
 
@@ -515,34 +616,41 @@ class Strong_Testimonials_Settings_Compat {
515
  * Custom event
516
  */
517
  public function settings_monitor_event() {
518
- ?>
519
- <div class="row">
520
- <div>
521
- <label for="method-event">
522
- <input type="radio" id="method-event" name="wpmtst_compat_options[ajax][method]" value="event"
523
- <?php checked( $this->options['ajax']['method'], 'event' ); ?>
524
- data-group="event"/>
 
 
 
 
525
  <?php _e( 'Custom event', 'strong-testimonials' ); ?>
526
- </label>
527
- </div>
528
- <div>
529
- <p class="about"><?php _e( 'Listen for specific events.', 'strong-testimonials' ); ?></p>
530
- <p class="description"><?php _e( 'For advanced users.', 'strong-testimonials' ); ?></p>
531
- </div>
532
- </div>
533
-
534
- <div class="row" data-sub="event">
535
- <div class="radio-sub">
536
- <label for="event-name">
537
  <?php _e( 'Event name', 'strong-testimonials' ); ?>
538
- </label>
539
- </div>
540
- <div>
541
- <input type="text" id="event-name" class="code"
542
- name="wpmtst_compat_options[ajax][event]"
543
- value="<?php echo $this->options['ajax']['event']; ?>" size="30"/>
544
- </div>
545
- </div>
 
 
 
546
  <?php
547
  }
548
 
@@ -550,41 +658,244 @@ class Strong_Testimonials_Settings_Compat {
550
  * Specific script
551
  */
552
  public function settings_monitor_script() {
 
 
553
  ?>
554
- <div class="row">
555
- <div>
556
- <label for="method-script">
557
- <input type="radio" id="method-script" name="wpmtst_compat_options[ajax][method]" value="script"
558
- <?php checked( $this->options['ajax']['method'], 'script' ); ?>
559
- data-group="script"/>
 
 
 
560
  <?php _e( 'Specific script', 'strong-testimonials' ); ?>
561
- </label>
562
- </div>
563
- <div>
564
- <p class="about"><?php _e( 'Register a callback for a specific Ajax script.', 'strong-testimonials' ); ?></p>
565
- <p class="description"><?php _e( 'For advanced users.', 'strong-testimonials' ); ?></p>
566
- </div>
567
- </div>
568
-
569
- <div class="row" data-sub="script">
570
- <div class="radio-sub">
571
- <label for="script-name">
572
  <?php _e( 'Script name', 'strong-testimonials' ); ?>
573
- </label>
574
- </div>
575
- <div>
576
- <select id="script-name" name="wpmtst_compat_options[ajax][script]">
577
- <option value="" <?php selected( $this->options['ajax']['script'], '' ); ?>>
578
  <?php _e( '&mdash; Select &mdash;' ); ?>
579
- </option>
580
- <option value="barba" <?php selected( $this->options['ajax']['script'], 'barba' ); ?>>Barba.js
581
- </option>
582
- </select>
583
- </div>
584
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
585
  <?php
586
  }
587
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
588
  }
589
 
590
  new Strong_Testimonials_Settings_Compat();
30
  add_action( 'wpmtst_register_settings', array( $this, 'register_settings' ) );
31
  add_action( 'wpmtst_settings_tabs', array( $this, 'register_tab' ), 3, 2 );
32
  add_filter( 'wpmtst_settings_callbacks', array( $this, 'register_settings_page' ) );
33
+ add_action( 'wp_ajax_wpmtst_add_lazyload_pair', array( $this, 'add_lazyload_pair' ) );
34
  }
35
 
36
  /**
71
  * Sanitize settings.
72
  *
73
  * @param $input
74
+ * @since 2.28.0
75
+ * @since 2.31.0 controller
76
+ * @since 2.31.0 lazyload
77
  * @return array
78
  */
79
  public function sanitize_options( $input ) {
80
+ $input['page_loading'] = sanitize_text_field( $input['page_loading'] );
81
+
82
  if ( 'general' == $input['page_loading'] ) {
83
  $input['prerender'] = 'all';
84
  $input['ajax']['method'] = 'universal';
85
+ }else {
86
  $input['prerender'] = sanitize_text_field( $input['prerender'] );
87
  $input['ajax']['method'] = sanitize_text_field( $input['ajax']['method'] );
88
  }
89
+
90
  $input['ajax']['universal_timer'] = floatval( sanitize_text_field( $input['ajax']['universal_timer'] ) );
91
  $input['ajax']['observer_timer'] = floatval( sanitize_text_field( $input['ajax']['observer_timer'] ) );
92
  $input['ajax']['container_id'] = sanitize_text_field( $input['ajax']['container_id'] );
94
  $input['ajax']['event'] = sanitize_text_field( $input['ajax']['event'] );
95
  $input['ajax']['script'] = sanitize_text_field( $input['ajax']['script'] );
96
 
97
+ $input['controller']['initialize_on'] = sanitize_text_field( $input['controller']['initialize_on'] );
98
+
99
+ $input['lazyload']['enabled'] = wpmtst_sanitize_checkbox( $input['lazyload'], 'enabled' );
100
+ // may be multiple pairs
101
+ foreach ( $input['lazyload']['classes'] as $key => $classes ) {
102
+ if ( $classes['start'] || $classes['finish'] ) {
103
+ $input['lazyload']['classes'][ $key ]['start'] = str_replace( '.', '', sanitize_text_field( $classes['start'] ) );
104
+ $input['lazyload']['classes'][ $key ]['finish'] = str_replace( '.', '', sanitize_text_field( $classes['finish'] ) );
105
+ } else {
106
+ unset( $input['lazyload']['classes'][ $key ] );
107
+ }
108
+ }
109
+
110
  return $input;
111
  }
112
 
120
 
121
  /**
122
  * Compatibility settings
123
+ *
124
+ * @since 2.31.0 controller
125
+ * @since 2.31.0 lazyload
126
  */
127
  public function settings_top() {
128
  $this->settings_intro();
129
  $this->settings_page_loading();
130
  $this->settings_prerender();
131
  $this->settings_monitor();
132
+ $this->settings_controller();
133
+ $this->settings_lazyload();
134
  }
135
 
136
  /**
138
  */
139
  public function settings_intro() {
140
  ?>
141
+ <h2><?php _e( 'Common Scenarios', 'strong-testimonials' ); ?></h2>
142
+ <table class="form-table" cellpadding="0" cellspacing="0">
143
+ <tr valign="top">
144
+ <td>
145
+ <div class="scenarios">
146
+
147
+ <div class="row header">
148
+ <div>
149
+ <?php _e( 'Symptom', 'strong-testimonials' ); ?>
150
+ </div>
151
+ <div>
152
  <?php _e( 'Possible Cause', 'strong-testimonials' ); ?>
153
+ </div>
154
+ <div>
155
+ <?php _e( 'Try', 'strong-testimonials' ); ?>
156
+ </div>
157
+ </div>
158
+
159
+ <div class="row">
160
+ <div>
161
+ <p><strong><?php _e( 'Views not working', 'strong-testimonials' ); ?></strong></p>
162
+ <p><?php _e( 'A testimonial view does not appear correctly the <strong>first time</strong> you view the page but it does when you <strong>refresh</strong> the page.', 'strong-testimonials' ); ?></p>
163
+ <p><?php _e( 'For example, it has no style, no pagination, or the slider has not started.', 'strong-testimonials' ); ?></p>
164
+ </div>
165
+ <div>
166
+ <p><?php _e( 'Your site uses <strong>Ajax page loading</strong> &ndash; also known as page animations, transition effects or Pjax (pushState Ajax) &ndash; provided by your theme or another plugin.', 'strong-testimonials' ); ?></p>
167
+ <p><?php _e( 'Instead of loading the entire page, this technique fetches only the new content.', 'strong-testimonials' ); ?></p>
168
+ </div>
169
+ <div>
170
+ <p><strong><?php _e( 'Ajax Page Loading', 'strong-testimonials' ); ?>:</strong> <?php _e( 'General', 'strong-testimonials' ); ?></p>
171
+ <p>
172
+ <a href="#" id="set-scenario-1">
173
+ <?php /* translators: link text on Settings > Compatibility tab */ _e( 'Set this now', 'strong-testimonials' ); ?>
174
+ </a>
175
+ </p>
176
+ </div>
177
+ </div>
178
+
179
+ <div class="row">
180
+ <div>
181
+ <p><strong><?php _e( 'Slider never starts', 'strong-testimonials' ); ?></strong></p>
182
+ <p><?php _e( 'A testimonial slider does not start or is missing navigation controls.', 'strong-testimonials' ); ?></p>
183
+ </div>
184
+ <div>
185
+ <p><?php _e( 'The page is very busy loading image galleries, other sliders or third-party resources like social media posts.', 'strong-testimonials' ); ?></p>
186
+ </div>
187
+ <div>
188
+ <p><strong><?php _e( 'Load Event', 'strong-testimonials' ); ?>:</strong> <?php _e( 'window load', 'strong-testimonials' ); ?></p>
189
+ </div>
190
+ </div>
191
+
192
+ <div class="row">
193
+ <div>
194
+ <p><strong><?php _e( 'Masonry layout not working', 'strong-testimonials' ); ?></strong></p>
195
+ <p><?php _e( 'A testimonial view with the Masonry layout has only one column or works inconsistently in different browsers or devices.', 'strong-testimonials' ); ?></p>
196
+ </div>
197
+ <div>
198
+ <p><?php _e( 'The page is very busy loading image galleries, other sliders or third-party resources like social media posts.', 'strong-testimonials' ); ?></p>
199
+ </div>
200
+ <div>
201
+ <p><strong><?php _e( 'Load Event', 'strong-testimonials' ); ?>:</strong> <?php _e( 'window load', 'strong-testimonials' ); ?></p>
202
+ </div>
203
+ </div>
204
+
205
+ </div><!-- .scenarios -->
206
+ </td>
207
+ </tr>
208
+ </table>
209
+
210
+ <h2><?php _e( 'Compatibility Settings', 'strong-testimonials' ); ?></h2>
211
  <?php
212
  }
213
 
216
  */
217
  public function settings_page_loading() {
218
  ?>
219
+ <table class="form-table" cellpadding="0" cellspacing="0">
220
+ <tr valign="top">
221
+ <th scope="row">
222
+ <?php _e( 'Ajax Page Loading', 'strong-testimonials' ); ?>
223
+ </th>
224
+ <td>
225
+ <div class="row header">
226
+ <p>
 
 
227
  <?php _e( 'This does not perform Ajax page loading.', 'strong-testimonials' ); ?>
228
  <?php _e( 'It provides compatibility with themes and plugins that use Ajax to load pages, also known as page animation or transition effects.', 'strong-testimonials' ); ?>
229
+ </p>
230
+ </div>
231
+ <fieldset data-radio-group="prerender">
232
  <?php $this->settings_page_loading_none(); ?>
233
  <?php $this->settings_page_loading_general(); ?>
234
  <?php $this->settings_page_loading_advanced(); ?>
235
+ </fieldset>
236
+ </td>
237
+ </tr>
238
+ </table>
239
  <?php
240
  }
241
 
243
  * None (default)
244
  */
245
  public function settings_page_loading_none() {
246
+ $checked = checked( $this->options['page_loading'], '', false );
247
+ $class = $checked ? ' class="current"' : '';
248
  ?>
249
+ <div class="row">
250
+ <div>
251
+ <label<?php echo $class; ?> for="page-loading-none">
252
+ <input id="page-loading-none"
253
+ name="wpmtst_compat_options[page_loading]"
254
+ type="radio"
255
+ value=""
256
+ <?php echo $checked; ?> />
257
  <?php _e( 'None', 'strong-testimonials' ); ?>
258
+ <em><?php _e( '(default)', 'strong-testimonials' ); ?></em>
259
+ </label>
260
+ </div>
261
+ <div>
262
+ <p class="about"><?php _e( 'No compatibility needed.', 'strong-testimonials' ); ?></p>
263
+ <p class="about"><?php _e( 'This works well for most themes.', 'strong-testimonials' ); ?></p>
264
+ </div>
265
+ </div>
266
  <?php
267
  }
268
 
270
  * General
271
  */
272
  public function settings_page_loading_general() {
273
+ $checked = checked( $this->options['page_loading'], 'general', false );
274
+ $class = $checked ? ' class="current"' : '';
275
  ?>
276
+ <div class="row">
277
+ <div>
278
+ <label<?php echo $class; ?> for="page-loading-general">
279
+ <input id="page-loading-general"
280
+ name="wpmtst_compat_options[page_loading]"
281
+ type="radio"
282
+ value="general"
283
+ <?php echo $checked; ?> />
284
  <?php _e( 'General', 'strong-testimonials' ); ?>
285
+ </label>
286
+ </div>
287
+ <div>
288
+ <p class="about"><?php _e( 'Be ready to render any view at any time.', 'strong-testimonials' ); ?></p>
289
+ <p class="about"><?php _e( 'This works well with common Ajax methods.', 'strong-testimonials' ); ?></p>
290
+ </div>
291
+ </div>
292
  <?php
293
  }
294
 
296
  * Advanced
297
  */
298
  public function settings_page_loading_advanced() {
299
+ $checked = checked( $this->options['page_loading'], 'advanced', false );
300
+ $class = $checked ? ' class="current"' : '';
301
  ?>
302
+ <div class="row">
303
+ <div>
304
+ <label<?php echo $class; ?> for="page-loading-advanced">
305
+ <input id="page-loading-advanced"
306
+ name="wpmtst_compat_options[page_loading]"
307
+ data-group="advanced"
308
+ type="radio"
309
+ value="advanced"
310
+ <?php echo $checked; ?> />
311
  <?php _e( 'Advanced', 'strong-testimonials' ); ?>
312
+ </label>
313
+ </div>
314
+ <div>
315
+ <p class="about"><?php _e( 'For specific configurations.', 'strong-testimonials' ); ?></p>
316
+ </div>
317
+ </div>
318
  <?php
319
  }
320
 
323
  */
324
  public function settings_prerender() {
325
  ?>
326
+ <table class="form-table" cellpadding="0" cellspacing="0" data-sub="advanced">
327
+ <tr valign="top">
328
+ <th scope="row">
329
  <?php _e( 'Prerender', 'strong-testimonials' ); ?>
330
+ </th>
331
+ <td>
332
+ <div class="row header">
333
+ <p><?php _e( 'Load stylesheets and populate script variables up front.', 'strong-testimonials' ); ?>
334
+ <a class="open-help-tab" href="#tab-panel-wpmtst-help-prerender"><?php _e( 'Help' ); ?></a>
335
+ </p>
336
+ </div>
337
+ <fieldset data-radio-group="prerender">
338
  <?php $this->settings_prerender_current(); ?>
339
  <?php $this->settings_prerender_all(); ?>
340
  <?php $this->settings_prerender_none(); ?>
341
+ </fieldset>
342
+ </td>
343
+ </tr>
344
+ </table>
345
  <?php
346
  }
347
 
349
  * Current (default)
350
  */
351
  public function settings_prerender_current() {
352
+ $checked = checked( $this->options['prerender'], 'current', false );
353
+ $class = $checked ? ' class="current"' : '';
354
  ?>
355
+ <div class="row">
356
+ <div>
357
+ <label<?php echo $class; ?> for="prerender-current">
358
+ <input id="prerender-current"
359
+ name="wpmtst_compat_options[prerender]"
360
+ type="radio"
361
+ value="current"
362
+ <?php echo $checked; ?> />
363
  <?php _e( 'Current page', 'strong-testimonials' ); ?>
364
+ <em><?php _e( '(default)', 'strong-testimonials' ); ?></em>
365
+ </label>
366
+ </div>
367
+ <div>
368
+ <p class="about"><?php _e( 'For the current page only.', 'strong-testimonials' ); ?></p>
369
+ <p class="about"><?php _e( 'This works well for most themes.', 'strong-testimonials' ); ?></p>
370
+ </div>
371
+ </div>
372
  <?php
373
  }
374
 
376
  * All
377
  */
378
  public function settings_prerender_all() {
379
+ $checked = checked( $this->options['prerender'], 'all', false );
380
+ $class = $checked ? ' class="current"' : '';
381
  ?>
382
+ <div class="row">
383
+ <div>
384
+ <label<?php echo $class; ?> for="prerender-all">
385
+ <input id="prerender-all"
386
+ type="radio"
387
+ name="wpmtst_compat_options[prerender]"
388
+ value="all"
389
+ <?php echo $checked; ?> />
390
  <?php _e( 'All views', 'strong-testimonials' ); ?>
391
+ </label>
392
+ </div>
393
+ <div>
394
+ <p class="about"><?php _e( 'For all views. Required for Ajax page loading.', 'strong-testimonials' ); ?></p>
395
+ <p class="about"><?php _e( 'Then select an option for <strong>Monitor</strong> below.', 'strong-testimonials' ); ?></p>
396
+ </div>
397
+ </div>
398
  <?php
399
  }
400
 
402
  * None
403
  */
404
  public function settings_prerender_none() {
405
+ $checked = checked( $this->options['prerender'], 'none', false );
406
+ $class = $checked ? ' class="current"' : '';
407
  ?>
408
+ <div class="row">
409
+ <div>
410
+ <label<?php echo $class; ?> for="prerender-none">
411
+ <input id="prerender-none"
412
+ type="radio"
413
+ name="wpmtst_compat_options[prerender]"
414
+ value="none"
415
+ <?php echo $checked; ?> />
416
  <?php _e( 'None', 'strong-testimonials' ); ?>
417
+ </label>
418
+ </div>
419
+ <div>
420
+ <p class="about"><?php _e( 'When the shortcode is rendered. May result in a flash of unstyled content.', 'strong-testimonials' ); ?></p>
421
+ </div>
422
+ </div>
423
  <?php
424
  }
425
 
428
  */
429
  public function settings_monitor() {
430
  ?>
431
+ <table class="form-table" cellpadding="0" cellspacing="0" data-sub="advanced">
432
+ <tr valign="top">
433
+ <th scope="row">
434
  <?php _e( 'Monitor', 'strong-testimonials' ); ?>
435
+ </th>
436
+ <td>
437
+ <div class="row header">
438
+ <p><?php _e( 'Initialize sliders, pagination and form validation as pages change.', 'strong-testimonials' ); ?></p>
439
+ </div>
440
+ <fieldset data-radio-group="method">
441
  <?php $this->settings_monitor_none(); ?>
442
  <?php $this->settings_monitor_universal(); ?>
443
  <?php $this->settings_monitor_observer(); ?>
444
  <?php $this->settings_monitor_event(); ?>
445
  <?php $this->settings_monitor_script(); ?>
446
+ </fieldset>
447
+ </td>
448
+ </tr>
449
+ </table>
450
  <?php
451
  }
452
 
454
  * None
455
  */
456
  public function settings_monitor_none() {
457
+ $checked = checked( $this->options['ajax']['method'], '', false );
458
+ $class = $checked ? ' class="current"' : '';
459
  ?>
460
+ <div class="row">
461
+ <div>
462
+ <label<?php echo $class; ?> for="method-none">
463
+ <input id="method-none"
464
+ type="radio"
465
+ name="wpmtst_compat_options[ajax][method]"
466
+ value=""
467
+ <?php echo $checked; ?> />
468
  <?php _e( 'None', 'strong-testimonials' ); ?>
469
+ <em><?php _e( '(default)', 'strong-testimonials' ); ?></em>
470
+ </label>
471
+ </div>
472
+ <div>
473
+ <p class="about"><?php _e( 'No compatibility needed.', 'strong-testimonials' ); ?></p>
474
+ </div>
475
+ </div>
476
  <?php
477
  }
478
 
480
  * Universal (timer)
481
  */
482
  public function settings_monitor_universal() {
483
+ $checked = checked( $this->options['ajax']['method'], 'universal', false );
484
+ $class = $checked ? ' class="current"' : '';
485
  ?>
486
+ <div class="row">
487
+ <div>
488
+ <label<?php echo $class; ?> for="method-universal">
489
+ <input id="method-universal"
490
+ name="wpmtst_compat_options[ajax][method]"
491
+ type="radio"
492
+ value="universal"
493
+ data-group="universal"
494
+ <?php echo $checked; ?> />
495
  <?php _e( 'Universal', 'strong-testimonials' ); ?>
496
+ </label>
497
+ </div>
498
+ <div>
499
+ <p class="about"><?php _e( 'Watch for page changes on a timer.', 'strong-testimonials' ); ?></p>
500
+ </div>
501
+ </div>
502
+
503
+ <div class="row" data-sub="universal">
504
+ <div class="radio-sub">
505
+ <label for="universal-timer">
506
  <?php _ex( 'Check every', 'timer setting', 'strong-testimonials' ); ?>
507
+ </label>
508
+ </div>
509
+ <div>
510
+ <input id="universal-timer"
511
+ name="wpmtst_compat_options[ajax][universal_timer]"
512
+ type="number"
513
+ min=".1" max="5" step=".1"
514
+ value="<?php echo $this->options['ajax']['universal_timer']; ?>"
515
+ size="3" />
516
  <?php _ex( 'seconds', 'timer setting', 'strong-testimonials' ); ?>
517
+ </div>
518
+ </div>
519
  <?php
520
  }
521
 
523
  * Observer
524
  */
525
  public function settings_monitor_observer() {
526
+ $checked = checked( $this->options['ajax']['method'], 'observer', false );
527
+ $class = $checked ? ' class="current"' : '';
528
  ?>
529
+ <div class="row">
530
+ <div>
531
+ <label<?php echo $class; ?> for="method-observer">
532
+ <input id="method-observer"
533
+ name="wpmtst_compat_options[ajax][method]"
534
+ data-group="observer"
535
+ type="radio"
536
+ value="observer"
537
+ <?php echo $checked; ?> />
538
  <?php _e( 'Observer', 'strong-testimonials' ); ?>
539
+ </label>
540
+ </div>
541
+ <div>
542
+ <p class="about"><?php _e( 'React to changes in specific page elements.', 'strong-testimonials' ); ?></p>
543
+ <p class="description"><?php _e( 'For advanced users.', 'strong-testimonials' ); ?></p>
544
+ </div>
545
+ </div>
546
 
547
  <?php
548
  /*
549
  * Timer
550
  */
551
  ?>
552
+ <div class="row" data-sub="observer">
553
+ <div class="radio-sub">
554
+ <label for="observer-timer">
555
  <?php _ex( 'Check once after', 'timer setting', 'strong-testimonials' ); ?>
556
+ </label>
557
+ </div>
558
+ <div>
559
+ <input id="observer-timer"
560
+ name="wpmtst_compat_options[ajax][observer_timer]"
561
+ type="number"
562
+ min=".1" max="5" step=".1"
563
+ value="<?php echo $this->options['ajax']['observer_timer']; ?>"
564
+ size="3" />
565
  <?php _ex( 'seconds', 'timer setting', 'strong-testimonials' ); ?>
566
+ </div>
567
+ </div>
568
 
569
  <?php
570
  /*
571
  * Container element ID
572
  */
573
  ?>
574
+ <div class="row" data-sub="observer">
575
+ <div class="radio-sub">
576
+ <label for="container-id">
577
  <?php _e( 'Container ID', 'strong-testimonials' ); ?>
578
+ </label>
579
+ </div>
580
+ <div>
581
+ <span class="code input-before">#</span>
582
+ <input class="code element"
583
+ id="container-id"
584
+ name="wpmtst_compat_options[ajax][container_id]"
585
+ type="text"
586
+ value="<?php echo $this->options['ajax']['container_id']; ?>" />
587
+ <p class="about adjacent"><?php _e( 'the element to observe', 'strong-testimonials' ); ?></p>
588
+ </div>
589
+ </div>
590
 
591
  <?php
592
  /*
593
  * Added node ID
594
  */
595
  ?>
596
+ <div class="row" data-sub="observer">
597
+ <div class="radio-sub">
598
+ <label for="addednode-id">
599
  <?php _e( 'Added node ID', 'strong-testimonials' ); ?>
600
+ </label>
601
+ </div>
602
+ <div>
603
+ <span class="code input-before">#</span>
604
+ <input class="code element"
605
+ id="addednode-id"
606
+ name="wpmtst_compat_options[ajax][addednode_id]"
607
+ type="text"
608
+ value="<?php echo $this->options['ajax']['addednode_id']; ?>" />
609
+ <p class="about adjacent"><?php _e( 'the element being added', 'strong-testimonials' ); ?></p>
610
+ </div>
611
+ </div>
612
  <?php
613
  }
614
 
616
  * Custom event
617
  */
618
  public function settings_monitor_event() {
619
+ $checked = checked( $this->options['ajax']['method'], 'event', false );
620
+ $class = $checked ? ' class="current"' : ''; ?>
621
+ <div class="row">
622
+ <div>
623
+ <label<?php echo $class; ?> for="method-event">
624
+ <input id="method-event"
625
+ name="wpmtst_compat_options[ajax][method]"
626
+ data-group="event"
627
+ type="radio"
628
+ value="event"
629
+ <?php echo $checked; ?> />
630
  <?php _e( 'Custom event', 'strong-testimonials' ); ?>
631
+ </label>
632
+ </div>
633
+ <div>
634
+ <p class="about"><?php _e( 'Listen for specific events.', 'strong-testimonials' ); ?></p>
635
+ <p class="description"><?php _e( 'For advanced users.', 'strong-testimonials' ); ?></p>
636
+ </div>
637
+ </div>
638
+
639
+ <div class="row" data-sub="event">
640
+ <div class="radio-sub">
641
+ <label for="event-name">
642
  <?php _e( 'Event name', 'strong-testimonials' ); ?>
643
+ </label>
644
+ </div>
645
+ <div>
646
+ <input class="code"
647
+ id="event-name"
648
+ name="wpmtst_compat_options[ajax][event]"
649
+ type="text"
650
+ value="<?php echo $this->options['ajax']['event']; ?>"
651
+ size="30" />
652
+ </div>
653
+ </div>
654
  <?php
655
  }
656
 
658
  * Specific script
659
  */
660
  public function settings_monitor_script() {
661
+ $checked = checked( $this->options['ajax']['method'], 'script', false );
662
+ $class = $checked ? ' class="current"' : '';
663
  ?>
664
+ <div class="row">
665
+ <div>
666
+ <label<?php echo $class; ?> for="method-script">
667
+ <input id="method-script"
668
+ name="wpmtst_compat_options[ajax][method]"
669
+ data-group="script"
670
+ type="radio"
671
+ value="script"
672
+ <?php echo $checked; ?> />
673
  <?php _e( 'Specific script', 'strong-testimonials' ); ?>
674
+ </label>
675
+ </div>
676
+ <div>
677
+ <p class="about"><?php _e( 'Register a callback for a specific Ajax script.', 'strong-testimonials' ); ?></p>
678
+ <p class="description"><?php _e( 'For advanced users.', 'strong-testimonials' ); ?></p>
679
+ </div>
680
+ </div>
681
+
682
+ <div class="row" data-sub="script">
683
+ <div class="radio-sub">
684
+ <label for="script-name">
685
  <?php _e( 'Script name', 'strong-testimonials' ); ?>
686
+ </label>
687
+ </div>
688
+ <div>
689
+ <select id="script-name" name="wpmtst_compat_options[ajax][script]">
690
+ <option value="" <?php selected( $this->options['ajax']['script'], '' ); ?>>
691
  <?php _e( '&mdash; Select &mdash;' ); ?>
692
+ </option>
693
+ <option value="barba" <?php selected( $this->options['ajax']['script'], 'barba' ); ?>>
694
+ Barba.js
695
+ </option>
696
+ </select>
697
+ </div>
698
+ </div>
699
+ <?php
700
+ }
701
+
702
+ /**
703
+ * Controller
704
+ *
705
+ * @since 2.31.0
706
+ */
707
+ public function settings_controller() {
708
+ ?>
709
+ <table class="form-table" cellpadding="0" cellspacing="0">
710
+ <tr valign="top">
711
+ <th scope="row">
712
+ <?php _e( 'Load Event', 'strong-testimonials' ); ?>
713
+ </th>
714
+ <td>
715
+ <div class="row header">
716
+ <p><?php _e( 'When to start sliders, Masonry, pagination and form validation.', 'strong-testimonials' ); ?></p>
717
+ </div>
718
+ <fieldset>
719
+ <?php $this->settings_page_controller_documentready(); ?>
720
+ <?php $this->settings_page_controller_windowload(); ?>
721
+ </fieldset>
722
+ </td>
723
+ </tr>
724
+ </table>
725
+ <?php
726
+ }
727
+
728
+ /**
729
+ * Document ready (default)
730
+ */
731
+ public function settings_page_controller_documentready() {
732
+ $checked = checked( $this->options['controller']['initialize_on'], 'documentReady', false );
733
+ $class = $checked ? ' class="current"' : '';
734
+ ?>
735
+ <div class="row">
736
+ <div>
737
+ <label<?php echo $class; ?> for="controller-documentready">
738
+ <input id="controller-documentready"
739
+ name="wpmtst_compat_options[controller][initialize_on]"
740
+ type="radio"
741
+ value="documentReady"
742
+ <?php echo $checked; ?> />
743
+ <?php _e( 'document ready', 'strong-testimonials' ); ?>
744
+ <em><?php _e( '(default)', 'strong-testimonials' ); ?></em>
745
+ </label>
746
+ </div>
747
+ <div>
748
+ <p class="about"><?php _e( 'This works well if your page load time is less than a few seconds.', 'strong-testimonials' ); ?></p>
749
+ </div>
750
+ </div>
751
+ <?php
752
+ }
753
+
754
+ /**
755
+ * Document ready (default)
756
+ */
757
+ public function settings_page_controller_windowload() {
758
+ $checked = checked( $this->options['controller']['initialize_on'], 'windowLoad', false );
759
+ $class = $checked ? ' class="current"' : '';
760
+ ?>
761
+ <div class="row">
762
+ <div>
763
+ <label<?php echo $class; ?> for="controller-windowload">
764
+ <input id="controller-windowload"
765
+ name="wpmtst_compat_options[controller][initialize_on]"
766
+ type="radio"
767
+ value="windowLoad"
768
+ <?php echo $checked; ?> />
769
+ <?php _e( 'window load', 'strong-testimonials' ); ?>
770
+ </label>
771
+ </div>
772
+ <div>
773
+ <p class="about"><?php _e( 'Try this if your page load time is more than a few seconds.', 'strong-testimonials' ); ?></p>
774
+ </div>
775
+ </div>
776
+ <?php
777
+ }
778
+
779
+ /**
780
+ * Lazy load
781
+ *
782
+ * @since 2.31.0
783
+ */
784
+ public function settings_lazyload() {
785
+ ?>
786
+ <table class="form-table" cellpadding="0" cellspacing="0">
787
+ <tr valign="top">
788
+ <th scope="row">
789
+ <?php _e( 'Lazy Loading Images', 'strong-testimonials' ); ?>
790
+ </th>
791
+ <td>
792
+ <div class="row header">
793
+ <p><?php _e( 'Watch for lazy loading images in themes and plugins.', 'strong-testimonials' ); ?></p>
794
+ </div>
795
+ <fieldset>
796
+ <?php $this->settings_page_lazyload_enabled(); ?>
797
+ <?php $this->settings_page_lazyload_classes(); ?>
798
+ </fieldset>
799
+ </td>
800
+ </tr>
801
+ </table>
802
  <?php
803
  }
804
 
805
+ /**
806
+ * Lazy load > Enabled
807
+ *
808
+ * @since 2.31.0
809
+ */
810
+ public function settings_page_lazyload_enabled() {
811
+ $checked = checked( $this->options['lazyload']['enabled'], 1, false );
812
+ ?>
813
+ <div class="row">
814
+ <div>
815
+ <label for="lazyload-enabled">
816
+ <input id="lazyload-enabled"
817
+ name="wpmtst_compat_options[lazyload][enabled]"
818
+ data-group="lazyload"
819
+ type="checkbox"
820
+ <?php echo $checked; ?> />
821
+ <?php _e( 'Enable watcher', 'strong-testimonials' ); ?>
822
+ </label>
823
+ </div>
824
+ <div data-sub="lazyload">
825
+ <p class="about"><?php _e( 'Most lazy loading techniques use one or two CSS class names to indicate which images to lazy load and when the lazy loading is finished.', 'strong-testimonials' ); ?></p>
826
+ <p class="about"><?php _e( 'Contact support for your theme or plugin to find out if it uses CSS class names and if so, what they are.', 'strong-testimonials' ); ?></p>
827
+ <p class="about"><?php printf( __( 'Or <a href="%s" target="_blank">open a support ticket here</a> and provide your system information.', 'strong-testimonials' ), esc_url( 'https://support.strongplugins.com/new-ticket/' ) ); ?></p>
828
+ </div>
829
+ </div>
830
+ <?php
831
+ }
832
+
833
+ /**
834
+ * Lazy load > CSS classes
835
+ *
836
+ * @since 2.31.0
837
+ */
838
+ public function settings_page_lazyload_classes() {
839
+ ?>
840
+ <div class="row" data-sub="lazyload">
841
+ <div>
842
+ <label>
843
+ <?php _e( 'CSS Class Names', 'strong-testimonials' ); ?>
844
+ </label>
845
+ </div>
846
+ <div class="lazyload-pairs">
847
+ <?php
848
+ foreach ( $this->options['lazyload']['classes'] as $key => $pair ) {
849
+ $this->settings_page_lazyload_class_inputs( $key, $pair );
850
+ }
851
+ ?>
852
+ <div class="pair-actions">
853
+ <input class="button"
854
+ id="add-pair"
855
+ value="<?php esc_attr_e( 'Add Classes', 'strong-testimonials' ); ?>"
856
+ type="button" />
857
+ </div>
858
+ </div>
859
+ </div>
860
+ <?php
861
+ }
862
+
863
+ /**
864
+ * Lazy load > CSS classes > Individual pair
865
+ *
866
+ * @since 2.31.0
867
+ */
868
+ private function settings_page_lazyload_class_inputs( $key, $pair ) {
869
+ ?>
870
+ <div class="pair">
871
+ <label>
872
+ <?php _ex( 'start', 'noun', 'strong-testimonials' ); ?>
873
+ <input class="element code"
874
+ name="wpmtst_compat_options[lazyload][classes][<?php echo $key; ?>][start]"
875
+ type="text"
876
+ value="<?php echo esc_attr( $pair['start'] ); ?>" />
877
+ </label>
878
+ <span class="pair-sep"></span>
879
+ <label>
880
+ <?php _ex( 'finish', 'noun', 'strong-testimonials' ); ?>
881
+ <input class="element code"
882
+ name="wpmtst_compat_options[lazyload][classes][<?php echo $key; ?>][finish]"
883
+ type="text"
884
+ value="<?php echo esc_attr( $pair['finish'] ); ?>" />
885
+ </label>
886
+ </div>
887
+ <?php
888
+ }
889
+
890
+ /**
891
+ * [Add Pair] Ajax receiver
892
+ */
893
+ public function add_lazyload_pair() {
894
+ ob_start();
895
+ $this->settings_page_lazyload_class_inputs( $_REQUEST['key'], array( 'start' => '', 'finish' => '' ) );
896
+ wp_send_json_success( ob_get_clean() );
897
+ }
898
+
899
  }
900
 
901
  new Strong_Testimonials_Settings_Compat();
admin/settings/partials/licenses.php CHANGED
@@ -8,6 +8,7 @@
8
  * TODO Add link to member account on website.
9
  */
10
  ?>
 
11
  <div class="tab-header">
12
  <p><?php _e( 'Valid license keys allow you to receive automatic updates and priority support.', 'strong-testimonials' ); ?></p>
13
  <p><?php _e( 'To transfer a license to another site or to uninstall the add-on, please deactivate the license here first.', 'strong-testimonials' ); ?></p>
8
  * TODO Add link to member account on website.
9
  */
10
  ?>
11
+ <h2><?php _e( 'Add-on Licenses', 'strong-testimonials' ); ?></h2>
12
  <div class="tab-header">
13
  <p><?php _e( 'Valid license keys allow you to receive automatic updates and priority support.', 'strong-testimonials' ); ?></p>
14
  <p><?php _e( 'To transfer a license to another site or to uninstall the add-on, please deactivate the license here first.', 'strong-testimonials' ); ?></p>
includes/class-strong-testimonials-render.php CHANGED
@@ -51,7 +51,7 @@ class Strong_Testimonials_Render {
51
  * Set shortcode.
52
  */
53
  public function set_shortcodes() {
54
- $this->shortcode = WPMST()->shortcodes->get_shortcode();
55
  }
56
 
57
  /**
@@ -576,7 +576,7 @@ class Strong_Testimonials_Render {
576
  /**
577
  * Prerender a view to gather styles, scripts, and script vars.
578
  *
579
- * Similar to Strong_Testimonials_Shortcodes::render_view().
580
  *
581
  * @param $atts
582
  *
51
  * Set shortcode.
52
  */
53
  public function set_shortcodes() {
54
+ $this->shortcode = WPMST()->shortcode->get_shortcode();
55
  }
56
 
57
  /**
576
  /**
577
  * Prerender a view to gather styles, scripts, and script vars.
578
  *
579
+ * Similar to Strong_Testimonials_View_Shortcode::render_view().
580
  *
581
  * @param $atts
582
  *
includes/class-strong-testimonials-shortcode-average.php ADDED
@@ -0,0 +1,338 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class Strong_Testimonials_Average_Shortcode
4
+ *
5
+ * @since 2.31.0
6
+ */
7
+
8
+ class Strong_Testimonials_Average_Shortcode {
9
+
10
+ /**
11
+ * @var string
12
+ */
13
+ public $shortcode = 'testimonial_average_rating';
14
+
15
+ public function __construct() {
16
+ add_shortcode( $this->shortcode, array( $this, 'testimonial_average_rating_shortcode' ) );
17
+ }
18
+
19
+ /**
20
+ * Return average rating.
21
+ *
22
+ * @param $atts
23
+ * @param null $content
24
+ * @since 2.31.0
25
+ * @return string
26
+ */
27
+ public function testimonial_average_rating_shortcode( $atts, $content = null ) {
28
+ $pairs = array(
29
+ // parts
30
+ 'average' => '',
31
+ 'count' => '',
32
+ 'stars' => '',
33
+ // style
34
+ 'block' => '',
35
+ 'centered' => '',
36
+ // HTML
37
+ 'element' => 'div', // span
38
+ 'class' => '', // on wrapper
39
+ // filters
40
+ 'category' => '',
41
+ );
42
+ $pairs = apply_filters( "wpmtst_shortcode_defaults__{$this->shortcode}", $pairs );
43
+
44
+ $atts = shortcode_atts( $pairs, normalize_empty_atts( $atts ), $this->shortcode );
45
+
46
+ // default phrases
47
+ $phrases = array(
48
+ /* translators: %s are numbers */
49
+ 'title' => __( 'Average Rating:', 'strong-testimonials-assignment' ),
50
+ 'summary' => __( '%s stars (based on %s ratings)', 'strong-testimonials-assignment' ),
51
+ 'title2' => __( 'Average of %s Ratings:', 'strong-testimonials-assignment' ),
52
+ 'summary2' => __( '%s stars', 'strong-testimonials-assignment' ),
53
+ );
54
+
55
+ // default parts
56
+ if ( ! $content ) {
57
+ $content = '{title} {stars} {summary}';
58
+ }
59
+
60
+ // set parts
61
+ preg_match_all( "#{(.*?)}#", $content, $parts );
62
+ /*
63
+ * Example:
64
+ *
65
+ * Array
66
+ * (
67
+ * [0] => Array
68
+ * (
69
+ * [0] => {title}
70
+ * [1] => {stars}
71
+ * [2] => {summary}
72
+ * )
73
+ *
74
+ * [1] => Array
75
+ * (
76
+ * [0] => title
77
+ * [1] => stars
78
+ * [2] => summary
79
+ * )
80
+ * )
81
+ */
82
+ $tag_list = $parts[0];
83
+ $tag_keys = $parts[1];
84
+ $parts = array_fill_keys( $tag_keys, '' );
85
+
86
+ // get posts
87
+ $args = array(
88
+ 'posts_per_page' => -1,
89
+ 'post_type' => 'wpm-testimonial',
90
+ 'post_status' => 'publish',
91
+ 'suppress_filters' => true,
92
+ );
93
+
94
+ // category
95
+ if ( $atts['category'] ) {
96
+
97
+ if ( is_numeric( $atts['category'] ) ) {
98
+
99
+ $args['tax_query'] = array(
100
+ array(
101
+ 'taxonomy' => 'wpm-testimonial-category',
102
+ 'field' => 'id',
103
+ 'terms' => $args['category'],
104
+ ),
105
+ );
106
+
107
+ } else {
108
+
109
+ $args['tax_query'] = array(
110
+ array(
111
+ 'taxonomy' => 'wpm-testimonial-category',
112
+ 'field' => 'slug',
113
+ 'terms' => $args['category'],
114
+ ),
115
+ );
116
+
117
+ }
118
+
119
+ }
120
+
121
+ $args = apply_filters( 'wpmtst_query_args', $args, $atts );
122
+ $posts_array = get_posts( $args );
123
+
124
+ // get summary
125
+ $summary = $this->get_summary( $posts_array );
126
+ /*
127
+ * Example:
128
+ *
129
+ * Array
130
+ * (
131
+ * [review_count] => 2
132
+ * [rating_count] => 2
133
+ * [rating_sum] => 10
134
+ * [rating_average] => 5
135
+ * [rating_detail] => Array
136
+ * (
137
+ * [5] => 2
138
+ * [4] => 0
139
+ * [3] => 0
140
+ * [2] => 0
141
+ * [1] => 0
142
+ * [0] => 0
143
+ * )
144
+ * )
145
+ */
146
+
147
+ // Want to build your own HTML? Return any truthy value to short-circuit this shortcode output.
148
+ $html = apply_filters( 'wpmtst_average_rating_pre_html', '', $atts, $summary );
149
+ if ( $html ) {
150
+ return $html;
151
+ }
152
+
153
+ // assemble classes
154
+ $class_list = array_filter( array_merge( array( 'strong-rating-wrapper', 'average' ), explode( ' ', $atts['class'] ) ) );
155
+ if ( $atts['block'] ) {
156
+ $class_list[] = 'block';
157
+ }
158
+ if ( $atts['centered'] ) {
159
+ $class_list[] = 'centered';
160
+ }
161
+
162
+ // title
163
+ if ( isset( $parts['title'] ) ) {
164
+ $parts['title'] = sprintf( '<span class="strong-rating-title">%s</span>', $phrases['title'] );
165
+ }
166
+ if ( isset( $parts['title2'] ) ) {
167
+ $parts['title2'] = sprintf( '<span class="strong-rating-title">%s</span>', sprintf( $phrases['title2'], $summary['rating_count'] ) );
168
+ }
169
+
170
+ // stars
171
+ if ( isset( $parts['stars'] ) ) {
172
+ $parts['stars'] = $this->print_stars( wpmtst_round_half( $summary['rating_average'] ) );
173
+ }
174
+
175
+ // average
176
+ if ( isset( $parts['average'] ) ) {
177
+ $parts['average'] = sprintf( '<span class="strong-rating-average">%s</span>', $summary['rating_average'] );
178
+ }
179
+
180
+ // count
181
+ if ( isset( $parts['count'] ) ) {
182
+ $parts['count'] = sprintf( '<span class="strong-rating-count">%s</span>', $summary['rating_count'] );
183
+ }
184
+
185
+ // summary phrase
186
+ if ( isset( $parts['summary'] ) ) {
187
+ $parts['summary'] = sprintf( '<span class="strong-rating-summary">%s</span>', sprintf( $phrases['summary'], $summary['rating_average'], $summary['rating_count'] ) );
188
+ }
189
+ if ( isset( $parts['summary2'] ) ) {
190
+ $parts['summary2'] = sprintf( '<span class="strong-rating-summary">%s</span>', sprintf( $phrases['summary2'], $summary['rating_average'] ) );
191
+ }
192
+
193
+ // replace tags
194
+ foreach ( $tag_list as $key => $tag ) {
195
+ $content = str_replace( $tag, $parts[ $tag_keys[ $key ] ], $content );
196
+ }
197
+
198
+ // assemble it
199
+ $html = sprintf( '<%s class="%s">%s</%s>', $atts['element'], join( ' ', $class_list ), $content, $atts['element'] );
200
+
201
+ wp_enqueue_style( 'wpmtst-rating-display' );
202
+
203
+ return apply_filters( 'wpmtst_average_rating_html', $html, $atts, $summary );
204
+ }
205
+
206
+ /**
207
+ * Calculate and return the average rating.
208
+ *
209
+ * @param $posts
210
+ * @since 1.1.0
211
+ * @return array|null
212
+ */
213
+ public function get_summary( $posts = null ) {
214
+ // Set a placeholder.
215
+ $average = array(
216
+ 'review_count' => null,
217
+ 'rating_count' => null,
218
+ 'rating_sum' => null,
219
+ 'rating_average' => null,
220
+ 'rating_detail' => null,
221
+ );
222
+
223
+ if ( $posts ) {
224
+
225
+ // initialize totals
226
+ $review_count = count( $posts );
227
+ $rating_count = 0;
228
+ $rating_sum = 0;
229
+ // initial values for each rating
230
+ $rating_detail = array_fill_keys( array( 5, 4, 3, 2, 1, 0 ), 0 );
231
+
232
+ foreach ( $posts as $post ) {
233
+ // get rating value
234
+ $value = $this->get_rating_value( $post );
235
+ // add to detail array
236
+ $rating_detail[ $value ]++;
237
+ // add to count and sum
238
+ if ( $value ) {
239
+ $rating_sum += $value;
240
+ $rating_count++;
241
+ }
242
+ }
243
+
244
+ if ( $rating_count ) {
245
+ $average = array(
246
+ 'review_count' => number_format( $review_count ),
247
+ 'rating_count' => number_format( $rating_count ),
248
+ 'rating_sum' => number_format( $rating_sum ),
249
+ 'rating_average' => trim( number_format( $rating_sum / $rating_count, 1 ), '.0' ),
250
+ 'rating_detail' => $rating_detail,
251
+ );
252
+ }
253
+
254
+ }
255
+
256
+ return $average;
257
+ }
258
+
259
+ /**
260
+ * Return the rating value for a single post.
261
+ *
262
+ * @param $post
263
+ * @since 1.1.0
264
+ * @return int|null
265
+ */
266
+ private function get_rating_value( $post ) {
267
+ $rating_field = $this->find_first_rating_field();
268
+
269
+ if ( $rating_field ) {
270
+ $possible = array(
271
+ intval( get_post_meta( $post->ID, $rating_field['name'], true ) ),
272
+ $rating_field['default_display_value'],
273
+ 0
274
+ );
275
+ $rating = max( $possible );
276
+ } else {
277
+ $rating = 5;
278
+ }
279
+
280
+ return $rating;
281
+ }
282
+
283
+ /**
284
+ * Find the first rating field.
285
+ *
286
+ * @since 1.1.0
287
+ * @return bool|int|string
288
+ */
289
+ private function find_first_rating_field() {
290
+ $fields = wpmtst_get_custom_fields();
291
+ foreach ( $fields as $key => $field ) {
292
+ if ( 'rating' == $field['input_type'] ) {
293
+ return $field;
294
+ }
295
+ }
296
+
297
+ return false;
298
+ }
299
+
300
+ /**
301
+ * Print the stars.
302
+ *
303
+ * @param double $rating
304
+ * @param string $class
305
+ * @since 2.31.0
306
+ * @return string
307
+ */
308
+ public function print_stars( $rating = 0.0, $class = 'strong-rating' ) {
309
+ $rating = (double) $rating;
310
+ $is_zero = ( 0 == $rating ) ? ' current' : '';
311
+ ob_start();
312
+ ?>
313
+ <span class="<?php echo esc_attr( $class ); ?>">
314
+ <span class="star0 star<?php echo $is_zero; ?>"></span>
315
+ <?php
316
+ if ( $is_zero ) {
317
+ echo str_repeat( '<span class="star"></span>', 5 );
318
+ } else {
319
+ for ( $i = 1; $i <= 5; $i++ ) {
320
+ $star_class = '';
321
+ if ( intval( $i ) == intval( $rating ) ) {
322
+ $star_class = ' current';
323
+ if ( $rating - $i ) {
324
+ $star_class .= ' half';
325
+ }
326
+ }
327
+ echo '<span class="star' . $star_class . '"></span>';
328
+ }
329
+ }
330
+ ?>
331
+ </span>
332
+ <?php
333
+ $html = apply_filters( 'wpmtst_average_rating_stars_html', ob_get_clean(), $rating );
334
+
335
+ return $html;
336
+ }
337
+
338
+ }
includes/class-strong-testimonials-shortcode-count.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class Strong_Testimonials_Count_Shortcode
4
+ *
5
+ * @since 2.28.0
6
+ */
7
+
8
+ class Strong_Testimonials_Count_Shortcode {
9
+
10
+ /**
11
+ * @var string
12
+ */
13
+ public $shortcode = 'testimonial_count';
14
+
15
+ public function __construct() {
16
+ add_shortcode( $this->shortcode, array( $this, 'testimonial_count_shortcode' ) );
17
+ }
18
+
19
+ /**
20
+ * A shortcode to display the number of testimonials.
21
+ *
22
+ * For all: [testimonial_count]
23
+ * For a specific category (by slug): [testimonial_count category="abc"]
24
+ * Unformatted: [testimonial_count unformatted]
25
+ *
26
+ * @param $atts
27
+ * @param null $content
28
+ *
29
+ * @since 2.19.0
30
+ * @since 2.30.0 unformatted attribute
31
+ *
32
+ * @return int
33
+ */
34
+ public function testimonial_count_shortcode( $atts, $content = null ) {
35
+ $pairs = array(
36
+ 'category' => '',
37
+ 'unformatted' => 0,
38
+ );
39
+ $pairs = apply_filters( "wpmtst_shortcode_defaults__{$this->shortcode}", $pairs );
40
+
41
+ $atts = shortcode_atts( $pairs, normalize_empty_atts( $atts ), $this->shortcode );
42
+
43
+ $args = array(
44
+ 'posts_per_page' => -1,
45
+ 'post_type' => 'wpm-testimonial',
46
+ 'post_status' => 'publish',
47
+ 'suppress_filters' => true,
48
+ );
49
+
50
+ if ( $atts['category'] ) {
51
+ $args['tax_query'] = array(
52
+ array(
53
+ 'taxonomy' => 'wpm-testimonial-category',
54
+ 'field' => 'slug',
55
+ 'terms' => $atts['category'],
56
+ )
57
+ );
58
+
59
+ }
60
+
61
+ $args = apply_filters( 'wpmtst_query_args', $args, $atts );
62
+ $posts_array = get_posts( $args );
63
+ $count = count( $posts_array );
64
+
65
+ if ( $atts['unformatted'] ) {
66
+ return $count;
67
+ }
68
+
69
+ return number_format_i18n( $count );
70
+ }
71
+
72
+ }
includes/{class-strong-testimonials-shortcodes.php → class-strong-testimonials-shortcode.php} RENAMED
@@ -1,22 +1,21 @@
1
  <?php
2
  /**
3
- * Class Strong_Testimonials_Shortcodes
4
  *
5
  * @since 2.28.0
6
  */
7
- class Strong_Testimonials_Shortcodes {
8
 
9
- public $shortcode = 'testimonial_view';
10
 
11
  /**
12
- * Strong_Testimonials_Shortcodes constructor.
13
  */
 
 
14
  public function __construct() {
15
  add_shortcode( $this->shortcode, array( $this, 'testimonial_view_shortcode' ) );
16
  add_filter( 'shortcode_atts_' . $this->shortcode, array( $this, 'testimonial_view_filter' ), 10, 3 );
17
 
18
- add_shortcode( 'testimonial_count', array( $this, 'testimonial_count_shortcode' ) );
19
-
20
  add_filter( 'widget_text', 'do_shortcode' );
21
  add_filter( 'no_texturize_shortcodes', array( $this, 'no_texturize_shortcodes' ) );
22
 
@@ -111,65 +110,12 @@ class Strong_Testimonials_Shortcodes {
111
  public function remove_whitespace( $html ) {
112
  $options = get_option( 'wpmtst_options' );
113
  if ( $options['remove_whitespace'] ) {
114
- $html = preg_replace( '~>\s+<~', '><', $html );
115
  }
116
 
117
  return $html;
118
  }
119
 
120
- /**
121
- * A shortcode to display the number of testimonials.
122
- *
123
- * For all: [testimonial_count]
124
- * For a specific category (by slug): [testimonial_count category="abc"]
125
- * Unformatted: [testimonial_count unformatted]
126
- *
127
- * @param $atts
128
- * @param null $content
129
- *
130
- * @since 2.19.0
131
- * @since 2.30.0 unformatted attribute
132
- *
133
- * @return int
134
- */
135
- public function testimonial_count_shortcode( $atts, $content = null ) {
136
- $shortcode = 'testimonial_count';
137
- $pairs = array(
138
- 'category' => '',
139
- 'unformatted' => 0,
140
- );
141
- $pairs = apply_filters( "wpmtst_shortcode_defaults__{$shortcode}", $pairs );
142
- $atts = shortcode_atts( $pairs, normalize_empty_atts( $atts ), $shortcode );
143
-
144
- $args = array(
145
- 'posts_per_page' => - 1,
146
- 'post_type' => 'wpm-testimonial',
147
- 'post_status' => 'publish',
148
- 'suppress_filters' => true,
149
- );
150
-
151
- if ( $atts['category'] ) {
152
- $args['tax_query'] = array(
153
- array(
154
- 'taxonomy' => 'wpm-testimonial-category',
155
- 'field' => 'slug',
156
- 'terms' => $atts['category'],
157
- )
158
- );
159
-
160
- }
161
-
162
- $args = apply_filters( 'wpmtst_query_args', $args, $atts );
163
- $posts_array = get_posts( $args );
164
- $count = count( $posts_array );
165
-
166
- if ( $atts['unformatted'] ) {
167
- return $count;
168
- }
169
-
170
- return number_format_i18n( $count );
171
- }
172
-
173
  /**
174
  * Do not texturize shortcode.
175
  *
1
  <?php
2
  /**
3
+ * Class Strong_Testimonials_View_Shortcode
4
  *
5
  * @since 2.28.0
6
  */
 
7
 
8
+ class Strong_Testimonials_View_Shortcode {
9
 
10
  /**
11
+ * @var string
12
  */
13
+ public $shortcode = 'testimonial_view';
14
+
15
  public function __construct() {
16
  add_shortcode( $this->shortcode, array( $this, 'testimonial_view_shortcode' ) );
17
  add_filter( 'shortcode_atts_' . $this->shortcode, array( $this, 'testimonial_view_filter' ), 10, 3 );
18
 
 
 
19
  add_filter( 'widget_text', 'do_shortcode' );
20
  add_filter( 'no_texturize_shortcodes', array( $this, 'no_texturize_shortcodes' ) );
21
 
110
  public function remove_whitespace( $html ) {
111
  $options = get_option( 'wpmtst_options' );
112
  if ( $options['remove_whitespace'] ) {
113
+ return wpmtst_strip_whitespace( $html );
114
  }
115
 
116
  return $html;
117
  }
118
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
119
  /**
120
  * Do not texturize shortcode.
121
  *
includes/class-strong-view-display.php CHANGED
@@ -35,6 +35,17 @@ class Strong_View_Display extends Strong_View {
35
  public function __construct( $atts = array() ) {
36
  parent::__construct( $atts );
37
  add_filter( 'wpmtst_build_query', array( $this, 'query_pagination' ) );
 
 
 
 
 
 
 
 
 
 
 
38
  }
39
 
40
  /**
@@ -69,13 +80,12 @@ class Strong_View_Display extends Strong_View {
69
  $this->has_pagination();
70
  $this->has_layouts();
71
 
72
- //$this->load_dependent_scripts();
73
  $this->load_extra_stylesheets();
74
 
75
- // If we can preprocess, we can add the inline style in the <head>.
76
  add_action( 'wp_enqueue_scripts', array( $this, 'add_custom_style' ), 20 );
77
 
78
- wp_reset_postdata();
79
  }
80
 
81
  /**
@@ -178,7 +188,7 @@ class Strong_View_Display extends Strong_View {
178
  */
179
  do_action( 'wpmtst_view_rendered', $this->atts );
180
 
181
- wp_reset_postdata();
182
 
183
  $this->html = apply_filters( 'strong_view_html', $html, $this );
184
 
35
  public function __construct( $atts = array() ) {
36
  parent::__construct( $atts );
37
  add_filter( 'wpmtst_build_query', array( $this, 'query_pagination' ) );
38
+ add_action( 'wpmtst_view_processed', array( $this, 'reset_view' ) );
39
+ }
40
+
41
+ /**
42
+ * Reset stuff after view is processed or rendered.
43
+ *
44
+ * @since 2.31.0
45
+ */
46
+ public function reset_view() {
47
+ wp_reset_postdata();
48
+ remove_filter( 'wpmtst_build_query', array( $this, 'query_pagination' ) );
49
  }
50
 
51
  /**
80
  $this->has_pagination();
81
  $this->has_layouts();
82
 
 
83
  $this->load_extra_stylesheets();
84
 
85
+ // If we can preprocess, we can add the inline style in <head>.
86
  add_action( 'wp_enqueue_scripts', array( $this, 'add_custom_style' ), 20 );
87
 
88
+ do_action( 'wpmtst_view_processed' );
89
  }
90
 
91
  /**
188
  */
189
  do_action( 'wpmtst_view_rendered', $this->atts );
190
 
191
+ do_action( 'wpmtst_view_processed' );
192
 
193
  $this->html = apply_filters( 'strong_view_html', $html, $this );
194
 
includes/class-strong-view-slideshow.php CHANGED
@@ -300,19 +300,43 @@ class Strong_View_Slideshow extends Strong_View_Display {
300
  * @return array
301
  */
302
  private function slideshow_args() {
303
- $options = get_option( 'wpmtst_options' );
304
- $view_options = apply_filters( 'wpmtst_view_options', get_option( 'wpmtst_view_options' ) );
 
305
 
306
  /**
307
  * Compatibility with lazy loading and use of imagesLoaded.
 
 
308
  */
309
- $compat = array();
310
- if ( class_exists( 'FL_LazyLoad_Images' ) && get_theme_mod('lazy_load_images') ) {
311
- $compat['flatsome'] = true;
312
- } else {
313
- $compat['flatsome'] = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314
  }
315
 
 
 
 
 
 
 
316
  $args = array(
317
  'mode' => $this->atts['slideshow_settings']['effect'],
318
  'speed' => $this->atts['slideshow_settings']['speed'] * 1000,
@@ -330,11 +354,14 @@ class Strong_View_Slideshow extends Strong_View_Display {
330
  'compat' => $compat,
331
  'touchEnabled' => $options['touch_enabled'],
332
  );
 
333
  if ( ! $this->atts['slideshow_settings']['adapt_height'] ) {
334
  $args['stretch'] = $this->atts['slideshow_settings']['stretch'] ? 1 : 0;
335
  }
336
 
337
- // Controls
 
 
338
  $options = $view_options['slideshow_nav_method']['controls'];
339
  $control_setting = $this->atts['slideshow_settings']['controls_type'];
340
  if ( ! $control_setting ) {
@@ -356,7 +383,9 @@ class Strong_View_Slideshow extends Strong_View_Display {
356
  }
357
  }
358
 
359
- // Pager
 
 
360
  $options = $view_options['slideshow_nav_method']['pager'];
361
  $pager_setting = $this->atts['slideshow_settings']['pager_type'];
362
  if ( ! $pager_setting ) {
300
  * @return array
301
  */
302
  private function slideshow_args() {
303
+ $options = get_option( 'wpmtst_options' );
304
+ $view_options = apply_filters( 'wpmtst_view_options', get_option( 'wpmtst_view_options' ) );
305
+ $compat_options = get_option( 'wpmtst_compat_options' );
306
 
307
  /**
308
  * Compatibility with lazy loading and use of imagesLoaded.
309
+ *
310
+ * @since 2.31.0 As user-configurable.
311
  */
312
+ $compat = array();
313
+ $enabled = false;
314
+ $pairs = array();
315
+
316
+ // Presets
317
+ // Flatsome theme
318
+ if ( class_exists( 'FL_LazyLoad_Images' ) && get_theme_mod( 'lazy_load_images' ) ) {
319
+ $enabled = true;
320
+ $pairs[] = array(
321
+ 'start' => 'lazy-load',
322
+ 'finish' => '',
323
+ );
324
+ }
325
+
326
+ // User settings
327
+ if ( $compat_options['lazyload']['enabled'] ) {
328
+ $enabled = true;
329
+ foreach ( $compat_options['lazyload']['classes'] as $key => $pair ) {
330
+ $pairs[] = $pair;
331
+ }
332
  }
333
 
334
+ // Bring together the presets and user settings.
335
+ $compat['lazyload'] = array(
336
+ 'active' => $enabled,
337
+ 'classes' => $pairs,
338
+ );
339
+
340
  $args = array(
341
  'mode' => $this->atts['slideshow_settings']['effect'],
342
  'speed' => $this->atts['slideshow_settings']['speed'] * 1000,
354
  'compat' => $compat,
355
  'touchEnabled' => $options['touch_enabled'],
356
  );
357
+
358
  if ( ! $this->atts['slideshow_settings']['adapt_height'] ) {
359
  $args['stretch'] = $this->atts['slideshow_settings']['stretch'] ? 1 : 0;
360
  }
361
 
362
+ /**
363
+ * Controls
364
+ */
365
  $options = $view_options['slideshow_nav_method']['controls'];
366
  $control_setting = $this->atts['slideshow_settings']['controls_type'];
367
  if ( ! $control_setting ) {
383
  }
384
  }
385
 
386
+ /**
387
+ * Pager
388
+ */
389
  $options = $view_options['slideshow_nav_method']['pager'];
390
  $pager_setting = $this->atts['slideshow_settings']['pager_type'];
391
  if ( ! $pager_setting ) {
includes/class-strong-view.php CHANGED
@@ -313,6 +313,7 @@ class Strong_View {
313
  return;
314
  }
315
 
 
316
  $c1 = '';
317
  $c2 = '';
318
 
@@ -348,34 +349,33 @@ class Strong_View {
348
  $gradient = self::gradient_rules( $c1, $c2 );
349
 
350
  if ( $this->is_form() ) {
351
- wp_add_inline_style( 'wpmtst-custom-style',
352
- "$view_el .strong-form-inner { $gradient }" );
353
- }
354
- else {
355
- wp_add_inline_style( 'wpmtst-custom-style',
356
- "$view_el .testimonial-inner { $gradient }" );
357
 
358
  if ( 'bold' == WPMST()->atts( 'template' ) ) {
359
- wp_add_inline_style( 'wpmtst-custom-style',
360
- "$view_el .readmore-page { background: $c2 }" );
361
  }
 
362
  }
363
 
364
- }
365
- elseif ( $c1 ) {
366
 
367
  if ( $this->is_form() ) {
368
- wp_add_inline_style( 'wpmtst-custom-style',
369
- "$view_el .strong-form-inner { background: $c1; }" );
370
- }
371
- else {
372
- wp_add_inline_style( 'wpmtst-custom-style',
373
- "$view_el .testimonial-inner { background: $c1; }" );
374
 
375
  if ( 'bold' == WPMST()->atts( 'template' ) ) {
376
- wp_add_inline_style( 'wpmtst-custom-style',
377
- "$view_el .readmore-page { background: $c1 }" );
378
  }
 
379
  }
380
 
381
  }
313
  return;
314
  }
315
 
316
+ $handle = 'wpmtst-custom-style';
317
  $c1 = '';
318
  $c2 = '';
319
 
349
  $gradient = self::gradient_rules( $c1, $c2 );
350
 
351
  if ( $this->is_form() ) {
352
+
353
+ wp_add_inline_style( $handle, "$view_el .strong-form-inner { $gradient }" );
354
+
355
+ } else {
356
+
357
+ wp_add_inline_style( $handle, "$view_el .testimonial-inner { $gradient }" );
358
 
359
  if ( 'bold' == WPMST()->atts( 'template' ) ) {
360
+ wp_add_inline_style( $handle, "$view_el .readmore-page { background: $c2 }" );
 
361
  }
362
+
363
  }
364
 
365
+ } elseif ( $c1 ) {
 
366
 
367
  if ( $this->is_form() ) {
368
+
369
+ wp_add_inline_style( $handle, "$view_el .strong-form-inner { background: $c1; }" );
370
+
371
+ } else {
372
+
373
+ wp_add_inline_style( $handle, "$view_el .testimonial-inner { background: $c1; }" );
374
 
375
  if ( 'bold' == WPMST()->atts( 'template' ) ) {
376
+ wp_add_inline_style( $handle, "$view_el .readmore-page { background: $c1 }" );
 
377
  }
378
+
379
  }
380
 
381
  }
includes/functions-template-form.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * FORM TEMPLATE FUNCTIONS
4
  */
5
 
6
  function wpmtst_form_info() {
@@ -275,7 +275,7 @@ function wpmtst_field_required_tag( $field ) {
275
  }
276
 
277
  /**
278
- * Print "Required field" notice.
279
  *
280
  * @since 2.23.0
281
  * @since 2.24.1 Print only if enabled.
1
  <?php
2
  /**
3
+ * Form template functions.
4
  */
5
 
6
  function wpmtst_form_info() {
275
  }
276
 
277
  /**
278
+ * Print "Required" notice.
279
  *
280
  * @since 2.23.0
281
  * @since 2.24.1 Print only if enabled.
includes/functions-template.php CHANGED
@@ -46,7 +46,7 @@ function strong_testimonials_view( $id = null ) {
46
  $atts = array( 'id' => $id );
47
  $out = WPMST()->render->parse_view( $out, $pairs, $atts );
48
 
49
- echo WPMST()->shortcodes->render_view( $out );
50
  }
51
 
52
  /**
46
  $atts = array( 'id' => $id );
47
  $out = WPMST()->render->parse_view( $out, $pairs, $atts );
48
 
49
+ echo WPMST()->shortcode->render_view( $out );
50
  }
51
 
52
  /**
includes/functions.php CHANGED
@@ -821,4 +821,49 @@ if ( ! function_exists( 'normalize_empty_atts' ) ) {
821
 
822
  return $atts;
823
  }
824
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
 
822
  return $atts;
823
  }
824
+ }
825
+
826
+ if ( ! function_exists( 'wpmtst_round_half' ) ) {
827
+ /**
828
+ * Round to the nearest half.
829
+ *
830
+ * @param $value
831
+ *
832
+ * @since 2.31.0
833
+ * @return float|int
834
+ */
835
+ function wpmtst_round_half( $value ) {
836
+ if ( is_string( $value ) ) {
837
+ $value = (float) str_replace( ',', '.', $value );
838
+ }
839
+ return round( (float) $value * 2 ) / 2;
840
+ }
841
+ }
842
+
843
+
844
+ if ( ! function_exists( 'wpmtst_strip_whitespace' ) ) {
845
+ /**
846
+ * Remove whitespace from HTML output.
847
+ *
848
+ * @param $html
849
+ *
850
+ * @return string
851
+ */
852
+ function wpmtst_strip_whitespace( $html ) {
853
+ return preg_replace( '~>\s+<~', '><', trim( $html ) );
854
+ }
855
+ }
856
+
857
+ if ( ! function_exists( 'wpmtst_current_url' ) ) {
858
+ /**
859
+ * Assemble and return the current URL.
860
+ *
861
+ * @since 2.31.0
862
+ * @return string
863
+ */
864
+ function wpmtst_current_url() {
865
+ global $wp;
866
+
867
+ return home_url( add_query_arg( array(), $wp->request ) );
868
+ }
869
+ }
includes/scripts.php CHANGED
@@ -35,8 +35,12 @@ function wpmtst_scripts() {
35
  *
36
  * Remember: array top level is converted to strings!
37
  */
38
- $ajax = $compat_options['ajax'];
 
 
 
39
  $parms = array(
 
40
  'method' => isset( $ajax['method'] ) ? $ajax['method'] : '',
41
  'universalTimer' => isset( $ajax['universal_timer'] ) ? $ajax['universal_timer'] * 1000 : 0,
42
  'observerTimer' => isset( $ajax['observer_timer'] ) ? $ajax['observer_timer'] * 1000 : 0,
@@ -44,7 +48,7 @@ function wpmtst_scripts() {
44
  'script' => isset( $ajax['script'] ) ? $ajax['script'] : '',
45
  'containerId' => isset( $ajax['container_id'] ) ? $ajax['container_id'] : '',
46
  'addedNodeId' => isset( $ajax['addednode_id'] ) ? $ajax['addednode_id'] : '',
47
- 'debug' => false,
48
  );
49
  wp_localize_script( 'wpmtst-controller', 'strongControllerParms', $parms );
50
 
35
  *
36
  * Remember: array top level is converted to strings!
37
  */
38
+ $ajax = $compat_options['ajax'];
39
+ $controller = $compat_options['controller'];
40
+
41
+ //TODO Use defaults + array_merge instead
42
  $parms = array(
43
+ 'initializeOn' => isset( $controller['initialize_on'] ) ? $controller['initialize_on'] : '',
44
  'method' => isset( $ajax['method'] ) ? $ajax['method'] : '',
45
  'universalTimer' => isset( $ajax['universal_timer'] ) ? $ajax['universal_timer'] * 1000 : 0,
46
  'observerTimer' => isset( $ajax['observer_timer'] ) ? $ajax['observer_timer'] * 1000 : 0,
48
  'script' => isset( $ajax['script'] ) ? $ajax['script'] : '',
49
  'containerId' => isset( $ajax['container_id'] ) ? $ajax['container_id'] : '',
50
  'addedNodeId' => isset( $ajax['addednode_id'] ) ? $ajax['addednode_id'] : '',
51
+ 'debug' => defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG,
52
  );
53
  wp_localize_script( 'wpmtst-controller', 'strongControllerParms', $parms );
54
 
public/css/rating-display.css CHANGED
@@ -9,82 +9,134 @@
9
  * http://codepen.io/jamesbarnett/pen/vlpkh
10
  */
11
 
12
- .strong-rating-wrapper {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  /* the fieldset */
15
  .strong-rating {
16
- border: none;
17
- display: inline-block;
18
  }
19
 
20
-
21
  /* the stars */
22
 
23
- .strong-rating span.star { display: inline-block; }
 
 
24
 
25
  .strong-rating span.star:before {
26
- font-family: FontAwesome;
27
- content: "\f005";
28
- display: inline-block;
29
- font-size: 1.25em;
30
- /* use padding not margin */
31
- padding: 0 5px;
32
- transition: color 0.3s ease;
33
- }
34
- .strong-rating span.star:first-child:before {
35
- padding-left: 0;
36
  }
37
- .strong-rating span.star:last-child:before {
38
- padding-right: 0;
 
39
  }
40
 
41
- .strong-rating span.star:hover { cursor: default; }
 
 
42
 
 
 
 
43
 
44
  /* fieldset tweaks */
45
 
46
  /* in a form */
47
  .strong-rating-wrapper.in-form .strong-rating {
48
- padding: 0;
49
  }
50
 
51
  /* in a view */
52
  .strong-rating-wrapper.in-view {
53
- display: inline-block;
54
  }
 
55
  .strong-rating-wrapper.in-view .strong-rating {
56
- margin: 0;
57
- padding: 0;
58
  }
59
 
60
  /* in the post editor */
61
  .strong-rating-wrapper.in-metabox {
62
- display: inline-block;
63
  }
64
 
65
  .strong-rating-wrapper.in-metabox .strong-rating span.star:before {
66
- font-size: 20px;
67
- line-height: 27px;
68
  }
69
 
70
  .strong-rating-wrapper.in-table-list .strong-rating span.star:before {
71
- /* use padding not margin */
72
- padding: 1px;
73
  }
74
 
75
-
76
  /* the magic */
77
 
78
  /* this is how we highlight stars before the checked one (siblings before): */
79
 
80
  /* hide the first label because our rating may be zero */
81
- .strong-rating span.star0 { display: none; }
 
 
82
 
83
  /* and turn all on */
84
- .strong-rating span.star:before { color: #FFB900; }
 
 
85
 
86
  /* then turn off stars after the current rating */
87
- .strong-rating span.current ~ span.star:before { color: #DDD; }
 
 
 
 
 
 
 
88
 
89
- /* and turn on the current rating */
90
- .strong-rating span.current:before { color: #FFB900; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  * http://codepen.io/jamesbarnett/pen/vlpkh
10
  */
11
 
12
+ /* the container */
13
+ .strong-rating-wrapper {
14
+ line-height: 1.7;
15
+ }
16
+
17
+ /* inline-block */
18
+ .strong-rating-wrapper.average > span {
19
+ display: inline-block;
20
+ }
21
+
22
+ /* block */
23
+ .strong-rating-wrapper.average.block > span {
24
+ display: block;
25
+ margin: 0;
26
+ }
27
+
28
+ /* centered */
29
+ .strong-rating-wrapper.average.centered {
30
+ text-align: center;
31
+ }
32
+
33
+ .strong-rating-title {
34
+ font-weight: 700;
35
+ }
36
 
37
  /* the fieldset */
38
  .strong-rating {
39
+ display: inline-block;
40
+ border: 0;
41
  }
42
 
 
43
  /* the stars */
44
 
45
+ .strong-rating span.star {
46
+ display: inline-block;
47
+ }
48
 
49
  .strong-rating span.star:before {
50
+ font-family: FontAwesome;
51
+ content: "\f005";
52
+ display: inline-block;
53
+ font-size: 1.25em;
54
+ /* use padding not margin */
55
+ padding: 0 4px;
56
+ transition: color 0.3s ease;
 
 
 
57
  }
58
+
59
+ .strong-rating-wrapper:not(.average) span.star:first-child:before {
60
+ padding-left: 0;
61
  }
62
 
63
+ .strong-rating-wrapper:not(.average) span.star:last-child:before {
64
+ padding-right: 0;
65
+ }
66
 
67
+ .strong-rating span.star:hover {
68
+ cursor: default;
69
+ }
70
 
71
  /* fieldset tweaks */
72
 
73
  /* in a form */
74
  .strong-rating-wrapper.in-form .strong-rating {
75
+ padding: 0;
76
  }
77
 
78
  /* in a view */
79
  .strong-rating-wrapper.in-view {
80
+ display: inline-block;
81
  }
82
+
83
  .strong-rating-wrapper.in-view .strong-rating {
84
+ margin: 0;
85
+ padding: 0;
86
  }
87
 
88
  /* in the post editor */
89
  .strong-rating-wrapper.in-metabox {
90
+ display: inline-block;
91
  }
92
 
93
  .strong-rating-wrapper.in-metabox .strong-rating span.star:before {
94
+ font-size: 20px;
95
+ line-height: 27px;
96
  }
97
 
98
  .strong-rating-wrapper.in-table-list .strong-rating span.star:before {
99
+ /* use padding not margin */
100
+ padding: 1px;
101
  }
102
 
 
103
  /* the magic */
104
 
105
  /* this is how we highlight stars before the checked one (siblings before): */
106
 
107
  /* hide the first label because our rating may be zero */
108
+ .strong-rating span.star0 {
109
+ display: none;
110
+ }
111
 
112
  /* and turn all on */
113
+ .strong-rating span.star:before {
114
+ color: #FFB900;
115
+ }
116
 
117
  /* then turn off stars after the current rating */
118
+ .strong-rating span.current ~ span.star:before {
119
+ content: "\f006";
120
+ }
121
+
122
+ /* turn on the current rating */
123
+ .strong-rating span.current:before {
124
+ color: #FFB900;
125
+ }
126
 
127
+ /* which may be a half star */
128
+ .strong-rating-wrapper.average span.current.half:before {
129
+ content: "\f123";
130
+ }
131
+
132
+ /* Responsive
133
+ --------------------------------------------------*/
134
+ @media only screen and (max-width: 480px) {
135
+ .strong-rating-wrapper > span {
136
+ display: block;
137
+ line-height: 30px;
138
+ vertical-align: middle;
139
+ margin: 0;
140
+ text-align: center;
141
+ }
142
+ }
public/css/rating-form.css CHANGED
@@ -9,6 +9,7 @@
9
  * http://codepen.io/jamesbarnett/pen/vlpkh
10
  */
11
 
 
12
  .strong-rating-wrapper {
13
  }
14
 
@@ -29,15 +30,18 @@
29
  display: none !important;
30
  }
31
 
 
 
 
 
32
  .strong-rating label:before {
33
  font-family: FontAwesome;
34
  content: "\f005";
35
  display: inline-block;
36
  font-size: 1.25em;
37
- /*line-height: 1.75;*/
38
  line-height: 1;
39
  /* use padding not margin */
40
- padding: 5px;
41
  transition: color 0.3s ease;
42
  }
43
 
@@ -57,14 +61,11 @@
57
  }
58
 
59
  /* in the post editor */
60
- .strong-rating-wrapper.in-metabox .strong-rating {
61
- padding: 0;
62
- }
63
-
64
  .strong-rating-wrapper.in-metabox .strong-rating > label:before {
65
  font-size: 20px;
66
  line-height: 27px;
67
- padding: 0 5px;
 
68
  }
69
 
70
  /* the magic */
@@ -84,38 +85,27 @@
84
 
85
  /* turn off stars after the one we're on */
86
  .strong-rating label:hover ~ label:before {
87
- color: #DDD;
88
  }
89
- /* but use different color if validation error */
90
  .error .strong-rating label:hover ~ label:before {
91
- color: #BBB;
92
  }
93
 
94
  /* turn off stars after the current rating */
95
  .strong-rating input:checked ~ label:before {
96
- color: #DDD;
97
  }
98
- /* but use different color if validation error */
99
  .error .strong-rating input:checked ~ label:before {
100
- color: #BBB;
101
  }
102
 
103
  /* turn on the current rating */
104
  .strong-rating input[type="radio"]:checked + label:before,
105
  .error .strong-rating input:checked + label:before {
106
- color: #FFB900;
107
- }
108
-
109
- /* option to clear rating in post editor */
110
- .strong-rating-wrapper.in-metabox .strong-rating label[for$="star0"]:before {
111
- content: "\f05e";
112
- color: #999 !important;
113
- position: relative;
114
- top: 1px;
115
  }
116
-
117
- .strong-rating-wrapper.in-metabox .strong-rating label[for$="star0"]:hover:before {
118
- color: #CD0000 !important;
119
  }
120
 
121
  /* when hovering the entire fieldset: */
@@ -123,7 +113,7 @@
123
  /* (1) turn all on */
124
  .strong-rating:hover input ~ label:before,
125
  .error .strong-rating:hover input ~ label:before {
126
- color: #FFB900;
127
  }
128
 
129
  /* (2) indicate current selection (optional) */
@@ -134,9 +124,8 @@
134
 
135
  /* (3) then turn off siblings after the hovered star */
136
  .strong-rating:hover label:hover ~ input:not(:checked) + label:before {
137
- color: #DDD;
138
  }
139
- /* but use different color if validation error */
140
  .error .strong-rating:hover label:hover ~ input:not(:checked) + label:before {
141
- color: #BBB;
142
  }
9
  * http://codepen.io/jamesbarnett/pen/vlpkh
10
  */
11
 
12
+ /* the container */
13
  .strong-rating-wrapper {
14
  }
15
 
30
  display: none !important;
31
  }
32
 
33
+ .strong-rating label {
34
+ font-weight: normal;
35
+ }
36
+
37
  .strong-rating label:before {
38
  font-family: FontAwesome;
39
  content: "\f005";
40
  display: inline-block;
41
  font-size: 1.25em;
 
42
  line-height: 1;
43
  /* use padding not margin */
44
+ padding: 4px;
45
  transition: color 0.3s ease;
46
  }
47
 
61
  }
62
 
63
  /* in the post editor */
 
 
 
 
64
  .strong-rating-wrapper.in-metabox .strong-rating > label:before {
65
  font-size: 20px;
66
  line-height: 27px;
67
+ padding: 0 4px;
68
+ color: #0073aa;
69
  }
70
 
71
  /* the magic */
85
 
86
  /* turn off stars after the one we're on */
87
  .strong-rating label:hover ~ label:before {
88
+ content: "\f006";
89
  }
90
+ /* maybe use different color if validation error */
91
  .error .strong-rating label:hover ~ label:before {
 
92
  }
93
 
94
  /* turn off stars after the current rating */
95
  .strong-rating input:checked ~ label:before {
96
+ content: "\f006";
97
  }
98
+ /* maybe use different color if validation error */
99
  .error .strong-rating input:checked ~ label:before {
 
100
  }
101
 
102
  /* turn on the current rating */
103
  .strong-rating input[type="radio"]:checked + label:before,
104
  .error .strong-rating input:checked + label:before {
105
+ content: "\f005";
 
 
 
 
 
 
 
 
106
  }
107
+ .strong-rating-wrapper.in-metabox input[type="radio"]:checked + label:before {
108
+ color: #00b9eb;
 
109
  }
110
 
111
  /* when hovering the entire fieldset: */
113
  /* (1) turn all on */
114
  .strong-rating:hover input ~ label:before,
115
  .error .strong-rating:hover input ~ label:before {
116
+ content: "\f005";
117
  }
118
 
119
  /* (2) indicate current selection (optional) */
124
 
125
  /* (3) then turn off siblings after the hovered star */
126
  .strong-rating:hover label:hover ~ input:not(:checked) + label:before {
127
+ content: "\f006";
128
  }
129
+ /* maybe use different color if validation error */
130
  .error .strong-rating:hover label:hover ~ input:not(:checked) + label:before {
 
131
  }
public/js/controller.js CHANGED
@@ -1,5 +1,8 @@
1
  /**
2
- * Component controller
 
 
 
3
  *
4
  * @namespace window.strongControllerParms
5
  */
@@ -12,7 +15,10 @@ var strongController = {
12
 
13
  grids: {},
14
 
 
 
15
  defaults: {
 
16
  method: '',
17
  universalTimer: 500,
18
  observerTimer: 500,
@@ -40,14 +46,14 @@ var strongController = {
40
  eventListenerSupported: window.addEventListener,
41
 
42
  checkInit: function () {
43
- return jQuery('.strong-view[data-state=\'idle\']').length;
44
  },
45
 
46
  /**
47
  * Initialize sliders.
48
  */
49
  initSliders: function () {
50
- var sliders = jQuery('.strong-view.slider-container[data-state=\'idle\']');
51
  if (debugit) console.log('sliders found:', sliders.length);
52
  if (sliders.length) {
53
  // Initialize independently
@@ -61,7 +67,7 @@ var strongController = {
61
  * Initialize paginated views.
62
  */
63
  initPagers: function () {
64
- var pagers = jQuery('.strong-pager[data-state=\'idle\']');
65
  if (debugit) console.log('pagers found:', pagers.length);
66
  if (pagers.length) {
67
  pagers.each(function () {
@@ -77,7 +83,7 @@ var strongController = {
77
  /*
78
  * Masonry
79
  */
80
- this.grids = jQuery('.strong-view[data-state=\'idle\'] .strong-masonry');
81
  if (debugit) console.log('Masonry found:', this.grids.length);
82
  if (this.grids.length) {
83
  // Add our element sizing.
@@ -102,7 +108,7 @@ var strongController = {
102
  * Initialize form validation.
103
  */
104
  initForm: function () {
105
- var forms = jQuery('.strong-form[data-state=\'idle\']');
106
  if (debugit) console.log('forms found:', forms.length);
107
  if (forms.length) {
108
  strongValidation.init();
@@ -110,6 +116,13 @@ var strongController = {
110
  }
111
  },
112
 
 
 
 
 
 
 
 
113
  /**
114
  * Create observer that reacts to nodes added or removed.
115
  *
@@ -189,17 +202,50 @@ var strongController = {
189
  * Initialize controller.
190
  */
191
  init: function () {
192
- jQuery(document).focus(); // if dev console open
193
  if (debugit) console.log('strongController init');
194
 
 
195
  var settings = {};
196
  if (typeof window.strongControllerParms !== 'undefined') {
197
  settings = window.strongControllerParms;
198
  } else {
199
  if (debugit) console.log('settings not found');
200
  }
 
 
201
  this.setup(settings);
202
  if (debugit) console.log('config', this.config);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  },
204
 
205
  /**
@@ -211,6 +257,7 @@ var strongController = {
211
  strongController.initPagers();
212
  strongController.initLayouts();
213
  strongController.initForm();
 
214
  },
215
 
216
  /**
@@ -274,32 +321,29 @@ var strongController = {
274
  listenForIframeReady: function () {
275
  if (debugit) console.log('listenForIframeReady');
276
 
277
- jQuery(window).on('load', function () {
278
- var $iframes = jQuery('iframe');
279
- if ($iframes.length && strongController.grids.length) {
280
- $iframes.ready(function () {
281
- // Still needs a moment to render
282
- setTimeout(function () { strongController.grids.masonry(); }, 500);
283
- // just in case
284
- setTimeout(function () { strongController.grids.masonry(); }, 2000);
285
- });
286
- }
287
- });
288
-
289
- }
290
-
291
- };
292
 
293
- jQuery(document).ready(function ($) {
294
 
295
- // Initialize controller.
296
- strongController.init();
297
 
298
- // Start components.
299
- strongController.start();
300
 
301
- // Listen.
302
- strongController.listen();
303
- strongController.listenForIframeReady();
304
 
305
- });
 
1
  /**
2
+ * Component Controller
3
+ *
4
+ * Version 1.1.0
5
+ * For Strong Testimonials version 2.31
6
  *
7
  * @namespace window.strongControllerParms
8
  */
15
 
16
  grids: {},
17
 
18
+ iframes: {},
19
+
20
  defaults: {
21
+ initializeOn: 'windowLoad',
22
  method: '',
23
  universalTimer: 500,
24
  observerTimer: 500,
46
  eventListenerSupported: window.addEventListener,
47
 
48
  checkInit: function () {
49
+ return jQuery('.strong-view[data-state="idle"]').length;
50
  },
51
 
52
  /**
53
  * Initialize sliders.
54
  */
55
  initSliders: function () {
56
+ var sliders = jQuery('.strong-view.slider-container[data-state="idle"]');
57
  if (debugit) console.log('sliders found:', sliders.length);
58
  if (sliders.length) {
59
  // Initialize independently
67
  * Initialize paginated views.
68
  */
69
  initPagers: function () {
70
+ var pagers = jQuery('.strong-pager[data-state="idle"]');
71
  if (debugit) console.log('pagers found:', pagers.length);
72
  if (pagers.length) {
73
  pagers.each(function () {
83
  /*
84
  * Masonry
85
  */
86
+ this.grids = jQuery('.strong-view[data-state="idle"] .strong-masonry');
87
  if (debugit) console.log('Masonry found:', this.grids.length);
88
  if (this.grids.length) {
89
  // Add our element sizing.
108
  * Initialize form validation.
109
  */
110
  initForm: function () {
111
+ var forms = jQuery('.strong-form[data-state="idle"]');
112
  if (debugit) console.log('forms found:', forms.length);
113
  if (forms.length) {
114
  strongValidation.init();
116
  }
117
  },
118
 
119
+ /**
120
+ * Look for iframes.
121
+ */
122
+ initIframes: function () {
123
+ this.iframes = jQuery('iframe');
124
+ },
125
+
126
  /**
127
  * Create observer that reacts to nodes added or removed.
128
  *
202
  * Initialize controller.
203
  */
204
  init: function () {
 
205
  if (debugit) console.log('strongController init');
206
 
207
+ // Get settings
208
  var settings = {};
209
  if (typeof window.strongControllerParms !== 'undefined') {
210
  settings = window.strongControllerParms;
211
  } else {
212
  if (debugit) console.log('settings not found');
213
  }
214
+
215
+ // Configure
216
  this.setup(settings);
217
  if (debugit) console.log('config', this.config);
218
+
219
+ /*
220
+ * Start on specific event
221
+ */
222
+ if ('documentReady' === this.config.initializeOn) {
223
+
224
+ jQuery(document).ready(function () {
225
+ if (debugit) console.log('document ready');
226
+ // Start components.
227
+ strongController.start();
228
+ // Listen.
229
+ strongController.listen();
230
+ });
231
+
232
+ } else { // Fail-safe
233
+
234
+ jQuery(window).on('load', function () {
235
+ if (debugit) console.log('window load');
236
+ // Start components.
237
+ strongController.start();
238
+ // Listen.
239
+ strongController.listen();
240
+ });
241
+
242
+ }
243
+
244
+ // Regardless of initializeOn setting, check for embeds in Masonry on window load.
245
+ jQuery(window).on('load', function () {
246
+ strongController.listenForIframeReady();
247
+ });
248
+
249
  },
250
 
251
  /**
257
  strongController.initPagers();
258
  strongController.initLayouts();
259
  strongController.initForm();
260
+ strongController.initIframes();
261
  },
262
 
263
  /**
321
  listenForIframeReady: function () {
322
  if (debugit) console.log('listenForIframeReady');
323
 
324
+ if (strongController.iframes.length && strongController.grids.length) {
325
+
326
+ strongController.iframes.ready(function () {
327
+ // still needs a moment to render
328
+ setTimeout(function () {
329
+ strongController.grids.masonry();
330
+ if (debugit) console.log('listenForIframeReady', 'timeout 1');
331
+ }, 1000);
332
+ // just in case
333
+ setTimeout(function () {
334
+ strongController.grids.masonry();
335
+ if (debugit) console.log('listenForIframeReady', 'timeout 2');
336
+ }, 2000);
337
+ });
 
338
 
339
+ } else {
340
 
341
+ if (debugit) console.log('listenForIframeReady', 'no iframes or Masonry found');
 
342
 
343
+ }
344
+ }
345
 
346
+ };
 
 
347
 
348
+ // Initialize controller.
349
+ strongController.init();
public/js/controller.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";var debugit=false;var strongController={grids:{},defaults:{method:"",universalTimer:500,observerTimer:500,containerId:"page",addedNodeId:"content",event:"",script:"",debug:false},config:{},setup:function(settings){settings.universalTimer=parseInt(settings.universalTimer);settings.observerTimer=parseInt(settings.observerTimer);settings.debug=!!settings.debug;debugit=settings.debug;this.config=jQuery.extend({},this.defaults,settings)},mutationObserver:window.MutationObserver||window.WebKitMutationObserver,eventListenerSupported:window.addEventListener,checkInit:function(){return jQuery(".strong-view[data-state='idle']").length},initSliders:function(){var sliders=jQuery(".strong-view.slider-container[data-state='idle']");if(debugit)console.log("sliders found:",sliders.length);if(sliders.length){sliders.each(function(){jQuery(this).strongSlider()})}},initPagers:function(){var pagers=jQuery(".strong-pager[data-state='idle']");if(debugit)console.log("pagers found:",pagers.length);if(pagers.length){pagers.each(function(){jQuery(this).strongPager()})}},initLayouts:function(){this.grids=jQuery(".strong-view[data-state='idle'] .strong-masonry");if(debugit)console.log("Masonry found:",this.grids.length);if(this.grids.length){this.grids.prepend('<div class="grid-sizer"></div><div class="gutter-sizer"></div>');this.grids.imagesLoaded(function(){strongController.grids.masonry({columnWidth:".grid-sizer",gutter:".gutter-sizer",itemSelector:".testimonial",percentPosition:true});strongController.grids.closest(".strong-view").attr("data-state","init")})}},initForm:function(){var forms=jQuery(".strong-form[data-state='idle']");if(debugit)console.log("forms found:",forms.length);if(forms.length){strongValidation.init()}},observer:function(obj,callback){if(this.mutationObserver){var obs=new this.mutationObserver(function(mutations){for(var i=0;i<mutations.length;i++){if(mutations[i].addedNodes.length){if(debugit)console.log("mutation observed",mutations);for(var j=0;j<mutations[i].addedNodes.length;j++){if(mutations[i].addedNodes[j].id===strongController.config.containerId){if(debugit)console.log("+",strongController.config.containerId);callback();return}}}}});obs.observe(obj,{childList:true,subtree:true})}else if(this.eventListenerSupported){obj.addEventListener("DOMNodeInserted",function(e){if(e.currentTarget.id===obj.id){if(debugit)console.log("DOMNodeInserted:",e.currentTarget.id);callback()}},false)}},intervalId:null,timeoutId:null,newInterval:function(){strongController.intervalId=setInterval(function tick(){if(debugit)console.log("tick > checkInit",strongController.checkInit());if(strongController.checkInit()){strongController.start()}},strongController.config.universalTimer)},newTimeout:function(){strongController.timeoutId=setTimeout(function tick(){if(debugit)console.log("tick > checkInit",strongController.checkInit());if(strongController.checkInit()){strongController.start()}},strongController.config.observerTimer)},init:function(){jQuery(document).focus();if(debugit)console.log("strongController init");var settings={};if(typeof window.strongControllerParms!=="undefined"){settings=window.strongControllerParms}else{if(debugit)console.log("settings not found")}this.setup(settings);if(debugit)console.log("config",this.config)},start:function(){if(debugit)console.log("start");strongController.initSliders();strongController.initPagers();strongController.initLayouts();strongController.initForm()},listen:function(){if(debugit)console.log("listen");switch(this.config.method){case"universal":this.newInterval();break;case"observer":this.observer(document.getElementById(this.config.containerId),this.newTimeout);break;case"event":document.addEventListener(this.config.event,this.start);break;case"script":switch(this.config.script){case"barba":if(typeof Barba==="object"&&Barba.hasOwnProperty("Dispatcher")){Barba.Dispatcher.on("transitionCompleted",this.start)}break;default:}break;default:}},listenForIframeReady:function(){if(debugit)console.log("listenForIframeReady");jQuery(window).on("load",function(){var $iframes=jQuery("iframe");if($iframes.length&&strongController.grids.length){$iframes.ready(function(){setTimeout(function(){strongController.grids.masonry()},500);setTimeout(function(){strongController.grids.masonry()},2e3)})}})}};jQuery(document).ready(function($){strongController.init();strongController.start();strongController.listen();strongController.listenForIframeReady()});
1
+ "use strict";var debugit=false;var strongController={grids:{},iframes:{},defaults:{initializeOn:"windowLoad",method:"",universalTimer:500,observerTimer:500,containerId:"page",addedNodeId:"content",event:"",script:"",debug:false},config:{},setup:function(settings){settings.universalTimer=parseInt(settings.universalTimer);settings.observerTimer=parseInt(settings.observerTimer);settings.debug=!!settings.debug;debugit=settings.debug;this.config=jQuery.extend({},this.defaults,settings)},mutationObserver:window.MutationObserver||window.WebKitMutationObserver,eventListenerSupported:window.addEventListener,checkInit:function(){return jQuery('.strong-view[data-state="idle"]').length},initSliders:function(){var sliders=jQuery('.strong-view.slider-container[data-state="idle"]');if(debugit)console.log("sliders found:",sliders.length);if(sliders.length){sliders.each(function(){jQuery(this).strongSlider()})}},initPagers:function(){var pagers=jQuery('.strong-pager[data-state="idle"]');if(debugit)console.log("pagers found:",pagers.length);if(pagers.length){pagers.each(function(){jQuery(this).strongPager()})}},initLayouts:function(){this.grids=jQuery('.strong-view[data-state="idle"] .strong-masonry');if(debugit)console.log("Masonry found:",this.grids.length);if(this.grids.length){this.grids.prepend('<div class="grid-sizer"></div><div class="gutter-sizer"></div>');this.grids.imagesLoaded(function(){strongController.grids.masonry({columnWidth:".grid-sizer",gutter:".gutter-sizer",itemSelector:".testimonial",percentPosition:true});strongController.grids.closest(".strong-view").attr("data-state","init")})}},initForm:function(){var forms=jQuery('.strong-form[data-state="idle"]');if(debugit)console.log("forms found:",forms.length);if(forms.length){strongValidation.init()}},initIframes:function(){this.iframes=jQuery("iframe")},observer:function(obj,callback){if(this.mutationObserver){var obs=new this.mutationObserver(function(mutations){for(var i=0;i<mutations.length;i++){if(mutations[i].addedNodes.length){if(debugit)console.log("mutation observed",mutations);for(var j=0;j<mutations[i].addedNodes.length;j++){if(mutations[i].addedNodes[j].id===strongController.config.containerId){if(debugit)console.log("+",strongController.config.containerId);callback();return}}}}});obs.observe(obj,{childList:true,subtree:true})}else if(this.eventListenerSupported){obj.addEventListener("DOMNodeInserted",function(e){if(e.currentTarget.id===obj.id){if(debugit)console.log("DOMNodeInserted:",e.currentTarget.id);callback()}},false)}},intervalId:null,timeoutId:null,newInterval:function(){strongController.intervalId=setInterval(function tick(){if(debugit)console.log("tick > checkInit",strongController.checkInit());if(strongController.checkInit()){strongController.start()}},strongController.config.universalTimer)},newTimeout:function(){strongController.timeoutId=setTimeout(function tick(){if(debugit)console.log("tick > checkInit",strongController.checkInit());if(strongController.checkInit()){strongController.start()}},strongController.config.observerTimer)},init:function(){if(debugit)console.log("strongController init");var settings={};if(typeof window.strongControllerParms!=="undefined"){settings=window.strongControllerParms}else{if(debugit)console.log("settings not found")}this.setup(settings);if(debugit)console.log("config",this.config);if("documentReady"===this.config.initializeOn){jQuery(document).ready(function(){if(debugit)console.log("document ready");strongController.start();strongController.listen()})}else{jQuery(window).on("load",function(){if(debugit)console.log("window load");strongController.start();strongController.listen()})}jQuery(window).on("load",function(){strongController.listenForIframeReady()})},start:function(){if(debugit)console.log("start");strongController.initSliders();strongController.initPagers();strongController.initLayouts();strongController.initForm();strongController.initIframes()},listen:function(){if(debugit)console.log("listen");switch(this.config.method){case"universal":this.newInterval();break;case"observer":this.observer(document.getElementById(this.config.containerId),this.newTimeout);break;case"event":document.addEventListener(this.config.event,this.start);break;case"script":switch(this.config.script){case"barba":if(typeof Barba==="object"&&Barba.hasOwnProperty("Dispatcher")){Barba.Dispatcher.on("transitionCompleted",this.start)}break;default:}break;default:}},listenForIframeReady:function(){if(debugit)console.log("listenForIframeReady");if(strongController.iframes.length&&strongController.grids.length){strongController.iframes.ready(function(){setTimeout(function(){strongController.grids.masonry();if(debugit)console.log("listenForIframeReady","timeout 1")},1e3);setTimeout(function(){strongController.grids.masonry();if(debugit)console.log("listenForIframeReady","timeout 2")},2e3)})}else{if(debugit)console.log("listenForIframeReady","no iframes or Masonry found")}}};strongController.init();
public/js/lib/form-validation/form-validation.js CHANGED
@@ -23,7 +23,7 @@ var strongValidation = {
23
  settings: {},
24
 
25
  setOpts: function (options) {
26
- this.settings = jQuery.extend({}, this.defaults, options)
27
  },
28
 
29
  rules: {},
@@ -36,7 +36,7 @@ var strongValidation = {
36
 
37
  if ('rating' === this.settings.fields[i].type) {
38
  if (1 === this.settings.fields[i].required) {
39
- this.rules[this.settings.fields[i].name] = {ratingRequired: true}
40
  }
41
  }
42
 
@@ -48,22 +48,22 @@ var strongValidation = {
48
  */
49
  init: function () {
50
 
51
- var strongForm = {}
52
  if (typeof window['strongForm'] !== 'undefined') {
53
- strongForm = window['strongForm']
54
  }
55
- this.setOpts(strongForm)
56
 
57
  if (this.settings.display.successMessage) {
58
 
59
- this.scrollOnSuccess()
60
 
61
  } else {
62
 
63
- this.setRules()
64
- this.changeEvents()
65
- this.customValidators()
66
- this.validateForm()
67
 
68
  }
69
 
@@ -73,25 +73,25 @@ var strongValidation = {
73
 
74
  // Trim blanks
75
  jQuery('input[type="text"], input[type="url"], input[type="email"], textarea', '#wpmtst-submission-form').on('change blur', function (e) {
76
- e.target.value = e.target.value.trim()
77
- })
78
 
79
  // Add protocol if missing
80
  // Thanks http://stackoverflow.com/a/36429927/51600
81
  jQuery('input[type=url]').change(function () {
82
  if (this.value.length && !/^https*:\/\//.test(this.value)) {
83
- this.value = 'http://' + this.value
84
  }
85
- })
86
 
87
  // Star ratings
88
- var ratings = document.getElementsByClassName('strong-rating')
89
  for (var i = 0; i < ratings.length; i++) {
90
  // Handle keystrokes
91
- ratings[i].addEventListener('click', this.handleRadioEvent, true)
92
- ratings[i].addEventListener('keyup', this.handleRadioEvent, true)
93
  // Validate on change
94
- ratings[i].addEventListener('change', function () { jQuery(this).valid() }, true)
95
  }
96
 
97
  },
@@ -99,8 +99,8 @@ var strongValidation = {
99
  handleRadioEvent: function (e) {
100
  // If key 0-5 fired the event, trigger click on that star (including hidden zero).
101
  if (e.keyCode >= 48 && e.keyCode <= 53) {
102
- var key = e.keyCode - 48
103
- jQuery(this).find('input[type=\'radio\'][value=' + key + ']').click()
104
  }
105
  },
106
 
@@ -116,8 +116,8 @@ var strongValidation = {
116
  * As of 6/10/2017
117
  */
118
  jQuery.validator.addMethod('ratingRequired', function (value, element) {
119
- return jQuery(element).find('input:checked').val() > 0
120
- }, jQuery.validator.messages.required)
121
  },
122
 
123
  validateForm: function () {
@@ -125,7 +125,7 @@ var strongValidation = {
125
  /**
126
  * Validate the form
127
  */
128
- var theForm = jQuery('#wpmtst-submission-form')
129
 
130
  theForm.validate({
131
 
@@ -135,17 +135,17 @@ var strongValidation = {
135
 
136
  invalidHandler: function (form, validator) {
137
  // Focus first invalid input
138
- var errors = validator.numberOfInvalids()
139
  if (errors) {
140
  if (strongValidation.settings.scroll.onError) {
141
  if (typeof validator.errorList[0] !== 'undefined') {
142
- var firstError = jQuery(validator.errorList[0].element)
143
- var fieldOffset = firstError.closest('.form-field').offset()
144
- var scrollTop = fieldOffset.top - strongValidation.settings.scroll.onErrorOffset
145
- jQuery('html, body').animate({scrollTop: scrollTop}, 800, function () { firstError.focus() })
146
  }
147
  } else {
148
- validator.errorList[0].element.focus()
149
  }
150
  }
151
  },
@@ -159,10 +159,10 @@ var strongValidation = {
159
  action: 'wpmtst_form2'
160
  },
161
  success: strongValidation.showResponse
162
- }
163
- jQuery(form).ajaxSubmit(formOptions)
164
  } else {
165
- form.submit()
166
  }
167
  },
168
 
@@ -174,30 +174,30 @@ var strongValidation = {
174
  rules: strongValidation.rules,
175
 
176
  errorPlacement: function (error, element) {
177
- error.appendTo(element.closest('div.form-field'))
178
  },
179
 
180
  highlight: function (element, errorClass, validClass) {
181
  if (element.type === 'checkbox') {
182
- jQuery(element).closest('.field-wrap').addClass(errorClass).removeClass(validClass)
183
  } else if ('rating' === jQuery(element).data('fieldType')) {
184
- jQuery(element).closest('.field-wrap').addClass(errorClass).removeClass(validClass)
185
  } else {
186
- jQuery(element).addClass(errorClass).removeClass(validClass)
187
  }
188
  },
189
 
190
  unhighlight: function (element, errorClass, validClass) {
191
  if (element.type === 'checkbox') {
192
- jQuery(element).closest('.field-wrap').removeClass(errorClass).addClass(validClass)
193
  } else if ('rating' === jQuery(element).data('fieldType')) {
194
- jQuery(element).closest('.field-wrap').removeClass(errorClass).addClass(validClass)
195
  } else {
196
- jQuery(element).removeClass(errorClass).addClass(validClass)
197
  }
198
  }
199
 
200
- })
201
 
202
  },
203
 
@@ -207,10 +207,10 @@ var strongValidation = {
207
  * @param response
208
  */
209
  showResponse: function (response) {
210
- var obj = JSON.parse(response)
211
  if (obj.success) {
212
- jQuery('#wpmtst-form').html(obj.message)
213
- strongValidation.scrollOnSuccess()
214
  } else {
215
  for (var key in obj.errors) {
216
  if (obj.errors.hasOwnProperty(key)) {
@@ -218,7 +218,7 @@ var strongValidation = {
218
  .find('span.error')
219
  .remove()
220
  .end()
221
- .append('<span class="error">' + obj.errors[key] + '</span>')
222
  }
223
  }
224
  }
@@ -229,16 +229,16 @@ var strongValidation = {
229
  */
230
  scrollOnSuccess: function () {
231
  if (strongValidation.settings.scroll.onSuccess) {
232
- var containerOffset, scrollTop
233
- containerOffset = jQuery('.testimonial-success').offset()
234
  if (containerOffset) {
235
- scrollTop = containerOffset.top - strongValidation.settings.scroll.onSuccessOffset
236
  // is WordPress admin bar showing?
237
  if (jQuery('#wpadminbar').length) {
238
- scrollTop -= 32
239
  }
240
- jQuery('html, body').animate({scrollTop: scrollTop}, 800)
241
  }
242
  }
243
  }
244
- }
23
  settings: {},
24
 
25
  setOpts: function (options) {
26
+ this.settings = jQuery.extend({}, this.defaults, options);
27
  },
28
 
29
  rules: {},
36
 
37
  if ('rating' === this.settings.fields[i].type) {
38
  if (1 === this.settings.fields[i].required) {
39
+ this.rules[this.settings.fields[i].name] = {ratingRequired: true};
40
  }
41
  }
42
 
48
  */
49
  init: function () {
50
 
51
+ var strongForm = {};
52
  if (typeof window['strongForm'] !== 'undefined') {
53
+ strongForm = window['strongForm'];
54
  }
55
+ this.setOpts(strongForm);
56
 
57
  if (this.settings.display.successMessage) {
58
 
59
+ this.scrollOnSuccess();
60
 
61
  } else {
62
 
63
+ this.setRules();
64
+ this.changeEvents();
65
+ this.customValidators();
66
+ this.validateForm();
67
 
68
  }
69
 
73
 
74
  // Trim blanks
75
  jQuery('input[type="text"], input[type="url"], input[type="email"], textarea', '#wpmtst-submission-form').on('change blur', function (e) {
76
+ e.target.value = e.target.value.trim();
77
+ });
78
 
79
  // Add protocol if missing
80
  // Thanks http://stackoverflow.com/a/36429927/51600
81
  jQuery('input[type=url]').change(function () {
82
  if (this.value.length && !/^https*:\/\//.test(this.value)) {
83
+ this.value = 'http://' + this.value;
84
  }
85
+ });
86
 
87
  // Star ratings
88
+ var ratings = document.getElementsByClassName('strong-rating');
89
  for (var i = 0; i < ratings.length; i++) {
90
  // Handle keystrokes
91
+ ratings[i].addEventListener('click', this.handleRadioEvent, true);
92
+ ratings[i].addEventListener('keyup', this.handleRadioEvent, true);
93
  // Validate on change
94
+ ratings[i].addEventListener('change', function () { jQuery(this).valid(); }, true);
95
  }
96
 
97
  },
99
  handleRadioEvent: function (e) {
100
  // If key 0-5 fired the event, trigger click on that star (including hidden zero).
101
  if (e.keyCode >= 48 && e.keyCode <= 53) {
102
+ var key = e.keyCode - 48;
103
+ jQuery(this).find('input[type="radio"][value=' + key + ']').click();
104
  }
105
  },
106
 
116
  * As of 6/10/2017
117
  */
118
  jQuery.validator.addMethod('ratingRequired', function (value, element) {
119
+ return jQuery(element).find('input:checked').val() > 0;
120
+ }, jQuery.validator.messages.required);
121
  },
122
 
123
  validateForm: function () {
125
  /**
126
  * Validate the form
127
  */
128
+ var theForm = jQuery('#wpmtst-submission-form');
129
 
130
  theForm.validate({
131
 
135
 
136
  invalidHandler: function (form, validator) {
137
  // Focus first invalid input
138
+ var errors = validator.numberOfInvalids();
139
  if (errors) {
140
  if (strongValidation.settings.scroll.onError) {
141
  if (typeof validator.errorList[0] !== 'undefined') {
142
+ var firstError = jQuery(validator.errorList[0].element);
143
+ var fieldOffset = firstError.closest('.form-field').offset();
144
+ var scrollTop = fieldOffset.top - strongValidation.settings.scroll.onErrorOffset;
145
+ jQuery('html, body').animate({scrollTop: scrollTop}, 800, function () { firstError.focus(); });
146
  }
147
  } else {
148
+ validator.errorList[0].element.focus();
149
  }
150
  }
151
  },
159
  action: 'wpmtst_form2'
160
  },
161
  success: strongValidation.showResponse
162
+ };
163
+ jQuery(form).ajaxSubmit(formOptions);
164
  } else {
165
+ form.submit();
166
  }
167
  },
168
 
174
  rules: strongValidation.rules,
175
 
176
  errorPlacement: function (error, element) {
177
+ error.appendTo(element.closest('div.form-field'));
178
  },
179
 
180
  highlight: function (element, errorClass, validClass) {
181
  if (element.type === 'checkbox') {
182
+ jQuery(element).closest('.field-wrap').addClass(errorClass).removeClass(validClass);
183
  } else if ('rating' === jQuery(element).data('fieldType')) {
184
+ jQuery(element).closest('.field-wrap').addClass(errorClass).removeClass(validClass);
185
  } else {
186
+ jQuery(element).addClass(errorClass).removeClass(validClass);
187
  }
188
  },
189
 
190
  unhighlight: function (element, errorClass, validClass) {
191
  if (element.type === 'checkbox') {
192
+ jQuery(element).closest('.field-wrap').removeClass(errorClass).addClass(validClass);
193
  } else if ('rating' === jQuery(element).data('fieldType')) {
194
+ jQuery(element).closest('.field-wrap').removeClass(errorClass).addClass(validClass);
195
  } else {
196
+ jQuery(element).removeClass(errorClass).addClass(validClass);
197
  }
198
  }
199
 
200
+ });
201
 
202
  },
203
 
207
  * @param response
208
  */
209
  showResponse: function (response) {
210
+ var obj = JSON.parse(response);
211
  if (obj.success) {
212
+ jQuery('#wpmtst-form').html(obj.message);
213
+ strongValidation.scrollOnSuccess();
214
  } else {
215
  for (var key in obj.errors) {
216
  if (obj.errors.hasOwnProperty(key)) {
218
  .find('span.error')
219
  .remove()
220
  .end()
221
+ .append('<span class="error">' + obj.errors[key] + '</span>');
222
  }
223
  }
224
  }
229
  */
230
  scrollOnSuccess: function () {
231
  if (strongValidation.settings.scroll.onSuccess) {
232
+ var containerOffset, scrollTop;
233
+ containerOffset = jQuery('.testimonial-success').offset();
234
  if (containerOffset) {
235
+ scrollTop = containerOffset.top - strongValidation.settings.scroll.onSuccessOffset;
236
  // is WordPress admin bar showing?
237
  if (jQuery('#wpadminbar').length) {
238
+ scrollTop -= 32;
239
  }
240
+ jQuery('html, body').animate({scrollTop: scrollTop}, 800);
241
  }
242
  }
243
  }
244
+ };
public/js/lib/form-validation/form-validation.min.js CHANGED
@@ -1 +1 @@
1
- var strongValidation={defaults:{ajaxUrl:"",display:{successMessage:false},scroll:{onError:true,onErrorOffset:100,onSuccess:true,onSuccessOffset:100},fields:{}},settings:{},setOpts:function(options){this.settings=jQuery.extend({},this.defaults,options)},rules:{},setRules:function(){for(var i=0;i<this.settings.fields.length;i++){if("rating"===this.settings.fields[i].type){if(1===this.settings.fields[i].required){this.rules[this.settings.fields[i].name]={ratingRequired:true}}}}},init:function(){var strongForm={};if(typeof window["strongForm"]!=="undefined"){strongForm=window["strongForm"]}this.setOpts(strongForm);if(this.settings.display.successMessage){this.scrollOnSuccess()}else{this.setRules();this.changeEvents();this.customValidators();this.validateForm()}},changeEvents:function(){jQuery('input[type="text"], input[type="url"], input[type="email"], textarea',"#wpmtst-submission-form").on("change blur",function(e){e.target.value=e.target.value.trim()});jQuery("input[type=url]").change(function(){if(this.value.length&&!/^https*:\/\//.test(this.value)){this.value="http://"+this.value}});var ratings=document.getElementsByClassName("strong-rating");for(var i=0;i<ratings.length;i++){ratings[i].addEventListener("click",this.handleRadioEvent,true);ratings[i].addEventListener("keyup",this.handleRadioEvent,true);ratings[i].addEventListener("change",function(){jQuery(this).valid()},true)}},handleRadioEvent:function(e){if(e.keyCode>=48&&e.keyCode<=53){var key=e.keyCode-48;jQuery(this).find("input[type='radio'][value="+key+"]").click()}},customValidators:function(){jQuery.validator.addMethod("ratingRequired",function(value,element){return jQuery(element).find("input:checked").val()>0},jQuery.validator.messages.required)},validateForm:function(){var theForm=jQuery("#wpmtst-submission-form");theForm.validate({onfocusout:false,focusInvalid:false,invalidHandler:function(form,validator){var errors=validator.numberOfInvalids();if(errors){if(strongValidation.settings.scroll.onError){if(typeof validator.errorList[0]!=="undefined"){var firstError=jQuery(validator.errorList[0].element);var fieldOffset=firstError.closest(".form-field").offset();var scrollTop=fieldOffset.top-strongValidation.settings.scroll.onErrorOffset;jQuery("html, body").animate({scrollTop:scrollTop},800,function(){firstError.focus()})}}else{validator.errorList[0].element.focus()}}},submitHandler:function(form){if(strongValidation.settings.ajaxUrl!==""){var formOptions={url:strongValidation.settings.ajaxUrl,data:{action:"wpmtst_form2"},success:strongValidation.showResponse};jQuery(form).ajaxSubmit(formOptions)}else{form.submit()}},rules:strongValidation.rules,errorPlacement:function(error,element){error.appendTo(element.closest("div.form-field"))},highlight:function(element,errorClass,validClass){if(element.type==="checkbox"){jQuery(element).closest(".field-wrap").addClass(errorClass).removeClass(validClass)}else if("rating"===jQuery(element).data("fieldType")){jQuery(element).closest(".field-wrap").addClass(errorClass).removeClass(validClass)}else{jQuery(element).addClass(errorClass).removeClass(validClass)}},unhighlight:function(element,errorClass,validClass){if(element.type==="checkbox"){jQuery(element).closest(".field-wrap").removeClass(errorClass).addClass(validClass)}else if("rating"===jQuery(element).data("fieldType")){jQuery(element).closest(".field-wrap").removeClass(errorClass).addClass(validClass)}else{jQuery(element).removeClass(errorClass).addClass(validClass)}}})},showResponse:function(response){var obj=JSON.parse(response);if(obj.success){jQuery("#wpmtst-form").html(obj.message);strongValidation.scrollOnSuccess()}else{for(var key in obj.errors){if(obj.errors.hasOwnProperty(key)){jQuery("div.wpmtst-"+key).find("span.error").remove().end().append('<span class="error">'+obj.errors[key]+"</span>")}}}},scrollOnSuccess:function(){if(strongValidation.settings.scroll.onSuccess){var containerOffset,scrollTop;containerOffset=jQuery(".testimonial-success").offset();if(containerOffset){scrollTop=containerOffset.top-strongValidation.settings.scroll.onSuccessOffset;if(jQuery("#wpadminbar").length){scrollTop-=32}jQuery("html, body").animate({scrollTop:scrollTop},800)}}}};
1
+ var strongValidation={defaults:{ajaxUrl:"",display:{successMessage:false},scroll:{onError:true,onErrorOffset:100,onSuccess:true,onSuccessOffset:100},fields:{}},settings:{},setOpts:function(options){this.settings=jQuery.extend({},this.defaults,options)},rules:{},setRules:function(){for(var i=0;i<this.settings.fields.length;i++){if("rating"===this.settings.fields[i].type){if(1===this.settings.fields[i].required){this.rules[this.settings.fields[i].name]={ratingRequired:true}}}}},init:function(){var strongForm={};if(typeof window["strongForm"]!=="undefined"){strongForm=window["strongForm"]}this.setOpts(strongForm);if(this.settings.display.successMessage){this.scrollOnSuccess()}else{this.setRules();this.changeEvents();this.customValidators();this.validateForm()}},changeEvents:function(){jQuery('input[type="text"], input[type="url"], input[type="email"], textarea',"#wpmtst-submission-form").on("change blur",function(e){e.target.value=e.target.value.trim()});jQuery("input[type=url]").change(function(){if(this.value.length&&!/^https*:\/\//.test(this.value)){this.value="http://"+this.value}});var ratings=document.getElementsByClassName("strong-rating");for(var i=0;i<ratings.length;i++){ratings[i].addEventListener("click",this.handleRadioEvent,true);ratings[i].addEventListener("keyup",this.handleRadioEvent,true);ratings[i].addEventListener("change",function(){jQuery(this).valid()},true)}},handleRadioEvent:function(e){if(e.keyCode>=48&&e.keyCode<=53){var key=e.keyCode-48;jQuery(this).find('input[type="radio"][value='+key+"]").click()}},customValidators:function(){jQuery.validator.addMethod("ratingRequired",function(value,element){return jQuery(element).find("input:checked").val()>0},jQuery.validator.messages.required)},validateForm:function(){var theForm=jQuery("#wpmtst-submission-form");theForm.validate({onfocusout:false,focusInvalid:false,invalidHandler:function(form,validator){var errors=validator.numberOfInvalids();if(errors){if(strongValidation.settings.scroll.onError){if(typeof validator.errorList[0]!=="undefined"){var firstError=jQuery(validator.errorList[0].element);var fieldOffset=firstError.closest(".form-field").offset();var scrollTop=fieldOffset.top-strongValidation.settings.scroll.onErrorOffset;jQuery("html, body").animate({scrollTop:scrollTop},800,function(){firstError.focus()})}}else{validator.errorList[0].element.focus()}}},submitHandler:function(form){if(strongValidation.settings.ajaxUrl!==""){var formOptions={url:strongValidation.settings.ajaxUrl,data:{action:"wpmtst_form2"},success:strongValidation.showResponse};jQuery(form).ajaxSubmit(formOptions)}else{form.submit()}},rules:strongValidation.rules,errorPlacement:function(error,element){error.appendTo(element.closest("div.form-field"))},highlight:function(element,errorClass,validClass){if(element.type==="checkbox"){jQuery(element).closest(".field-wrap").addClass(errorClass).removeClass(validClass)}else if("rating"===jQuery(element).data("fieldType")){jQuery(element).closest(".field-wrap").addClass(errorClass).removeClass(validClass)}else{jQuery(element).addClass(errorClass).removeClass(validClass)}},unhighlight:function(element,errorClass,validClass){if(element.type==="checkbox"){jQuery(element).closest(".field-wrap").removeClass(errorClass).addClass(validClass)}else if("rating"===jQuery(element).data("fieldType")){jQuery(element).closest(".field-wrap").removeClass(errorClass).addClass(validClass)}else{jQuery(element).removeClass(errorClass).addClass(validClass)}}})},showResponse:function(response){var obj=JSON.parse(response);if(obj.success){jQuery("#wpmtst-form").html(obj.message);strongValidation.scrollOnSuccess()}else{for(var key in obj.errors){if(obj.errors.hasOwnProperty(key)){jQuery("div.wpmtst-"+key).find("span.error").remove().end().append('<span class="error">'+obj.errors[key]+"</span>")}}}},scrollOnSuccess:function(){if(strongValidation.settings.scroll.onSuccess){var containerOffset,scrollTop;containerOffset=jQuery(".testimonial-success").offset();if(containerOffset){scrollTop=containerOffset.top-strongValidation.settings.scroll.onSuccessOffset;if(jQuery("#wpadminbar").length){scrollTop-=32}jQuery("html, body").animate({scrollTop:scrollTop},800)}}}};
public/js/lib/strongpager/jquery.strongpager.js CHANGED
@@ -1,6 +1,6 @@
1
  /*!
2
  * jQuery Strong Pager Plugin
3
- * Version 2.0.1
4
  *
5
  * Copyright (c) 2017 Chris Dillon
6
  * Released under the MIT license
@@ -15,214 +15,214 @@
15
  offset: 40,
16
  div: '.strong-content',
17
  imagesLoaded: true
18
- }
19
 
20
  $.fn.strongPager = function (options) {
21
 
22
  if (this.length === 0) {
23
- return this
24
  }
25
 
26
  // create a namespace to be used throughout the plugin
27
- var pager = {}
28
  // set a reference to our view container
29
- var el = this
30
 
31
  /**
32
  * Initialize
33
  */
34
  var init = function () {
35
- var pagerVar = el.data('pager-var')
36
- var config = {}
37
 
38
- if (typeof( window[pagerVar] ) !== 'undefined') {
39
- config = window[pagerVar].config
40
  }
41
 
42
  // Merge user options with the defaults
43
- pager.settings = $.extend({}, defaults, config, options)
44
 
45
- pager.div = el.find(pager.settings.div)
46
- pager.pageCounter = 0
47
- pager.scrollto = 0
48
- pager.currentPage = pager.settings.currentPage
49
- pager.visibilityInterval = 0
50
 
51
  // Wait for images loaded
52
  if (pager.settings.imagesLoaded) {
53
- el.imagesLoaded(setup)
54
  } else {
55
- setup()
56
  }
57
 
58
  // Store reference to self in order to access public functions later
59
- $(el).data('strongPager', this)
60
 
61
  // Set initialized flag
62
- el.attr("data-state","init")
63
 
64
- }
65
 
66
  /**
67
  * Scroll upon navigation
68
  */
69
  var scroll = function () {
70
  if (pager.settings.scrollTop) {
71
- $('html, body').animate({scrollTop: pager.scrollto}, 800)
72
  }
73
- }
74
 
75
  /**
76
  * Paginate
77
  */
78
  var paginate = function () {
79
- var pageCounter = 1
80
 
81
- pager.div.wrap('<div class="simplePagerContainer"></div>')
82
 
83
  pager.div.children().each(function (i) {
84
- var rangeEnd = pageCounter * pager.settings.pageSize - 1
85
  if (i > rangeEnd) {
86
- pageCounter++
87
  }
88
- $(this).addClass('simplePagerPage' + pageCounter)
89
- })
90
 
91
- pager.pageCounter = pageCounter
92
- }
93
 
94
  /**
95
  * Calculate offset for scrolling
96
  */
97
  var findOffset = function () {
98
- var containerOffset
99
 
100
  // WooCommerce product tabs
101
  if (el.closest('.woocommerce-tabs').length) {
102
- containerOffset = el.closest('.woocommerce-tabs').offset()
103
  } else {
104
- containerOffset = el.find('.simplePagerContainer').offset()
105
  }
106
 
107
- pager.scrollto = ~~(containerOffset.top - pager.settings.offset)
108
 
109
  // WordPress admin bar
110
  if (document.getElementById('#wpadminbar')) {
111
- pager.scrollto -= 32
112
  }
113
- }
114
 
115
  /**
116
  * Hide all and show current
117
  */
118
  var switchPages = function (fade) {
119
  // Hide the pages
120
- pager.div.children().hide()
121
 
122
  // Show the container which now has paging controls
123
- el.show()
124
 
125
  // Show the current page
126
- var newPage = pager.div.children('.simplePagerPage' + pager.currentPage)
127
  if (fade) {
128
- newPage.fadeIn()
129
  } else {
130
- newPage.show()
131
  }
132
- }
133
 
134
  /**
135
  * Add navigation
136
  */
137
  var addNavigation = function () {
138
- var nav = '<ul class="simplePagerNav">'
139
- var cssClass
140
 
141
  for (var i = 1; i <= pager.pageCounter; i++) {
142
- cssClass = ''
143
  if (i === pager.currentPage) {
144
- cssClass = 'currentPage '
145
  }
146
- nav += '<li class="' + cssClass + 'simplePageNav' + i + '"><a rel="' + i + '" href="#">' + i + '</a></li>'
147
  }
148
- nav += '</ul>'
149
- nav = '<div class="simplePagerList">' + nav + '</div>'
150
 
151
  switch (pager.settings.pagerLocation) {
152
  case 'before':
153
- pager.div.before(nav)
154
- break
155
  case 'both':
156
- pager.div.before(nav)
157
- pager.div.after(nav)
158
- break
159
  default:
160
- pager.div.after(nav)
161
  }
162
- }
163
 
164
  /**
165
  * Navigation behavior
166
  */
167
  var navigationHandler = function () {
168
  el.find('.simplePagerNav a').click(function (e) {
169
- var $this = $(e.target)
170
- var container
171
 
172
- container = $this.closest('.simplePagerContainer')
173
 
174
  // Get the REL attribute
175
- pager.currentPage = $this.attr('rel')
176
 
177
  // Remove current page highlight
178
- container.find('li.currentPage').removeClass('currentPage')
179
 
180
  // Add current page highlight
181
- container.find('a[rel="' + pager.currentPage + '"]').parent('li').addClass('currentPage')
182
 
183
  // Switch pages
184
- switchPages(true)
185
 
186
  // Scroll up for any nav click
187
- scroll()
188
 
189
- return false
190
- })
191
- }
192
 
193
  /**
194
  * Visibility check.
195
  */
196
  var visibilityCheck = function () {
197
  if (el.is(':visible')) {
198
- clearInterval(pager.visibilityInterval)
199
- findOffset()
200
  }
201
- }
202
 
203
  /**
204
  * Setup
205
  */
206
  var setup = function () {
207
- paginate()
208
  // Bail if only one page
209
  if (pager.pageCounter > 1) {
210
- addNavigation()
211
- navigationHandler()
212
  }
213
 
214
- switchPages()
215
 
216
  // Set up timer to calculate offset which is dependent on visibility
217
- pager.visibilityInterval = setInterval( visibilityCheck, 500 );
218
- }
219
 
220
  /**
221
  * Start it up
222
  */
223
- init()
224
 
225
- return this
226
- }
227
 
228
- })(jQuery)
1
  /*!
2
  * jQuery Strong Pager Plugin
3
+ * Version 2.1
4
  *
5
  * Copyright (c) 2017 Chris Dillon
6
  * Released under the MIT license
15
  offset: 40,
16
  div: '.strong-content',
17
  imagesLoaded: true
18
+ };
19
 
20
  $.fn.strongPager = function (options) {
21
 
22
  if (this.length === 0) {
23
+ return this;
24
  }
25
 
26
  // create a namespace to be used throughout the plugin
27
+ var pager = {};
28
  // set a reference to our view container
29
+ var el = this;
30
 
31
  /**
32
  * Initialize
33
  */
34
  var init = function () {
35
+ var pagerVar = el.data('pager-var');
36
+ var config = {};
37
 
38
+ if (typeof(window[pagerVar]) !== 'undefined') {
39
+ config = window[pagerVar].config;
40
  }
41
 
42
  // Merge user options with the defaults
43
+ pager.settings = $.extend({}, defaults, config, options);
44
 
45
+ pager.div = el.find(pager.settings.div);
46
+ pager.pageCounter = 0;
47
+ pager.scrollto = 0;
48
+ pager.currentPage = pager.settings.currentPage;
49
+ pager.visibilityInterval = 0;
50
 
51
  // Wait for images loaded
52
  if (pager.settings.imagesLoaded) {
53
+ el.imagesLoaded(setup);
54
  } else {
55
+ setup();
56
  }
57
 
58
  // Store reference to self in order to access public functions later
59
+ $(el).data('strongPager', this);
60
 
61
  // Set initialized flag
62
+ el.attr("data-state", "init");
63
 
64
+ };
65
 
66
  /**
67
  * Scroll upon navigation
68
  */
69
  var scroll = function () {
70
  if (pager.settings.scrollTop) {
71
+ $('html, body').animate({scrollTop: pager.scrollto}, 800);
72
  }
73
+ };
74
 
75
  /**
76
  * Paginate
77
  */
78
  var paginate = function () {
79
+ var pageCounter = 1;
80
 
81
+ pager.div.wrap('<div class="simplePagerContainer"></div>');
82
 
83
  pager.div.children().each(function (i) {
84
+ var rangeEnd = pageCounter * pager.settings.pageSize - 1;
85
  if (i > rangeEnd) {
86
+ pageCounter++;
87
  }
88
+ $(this).addClass('simplePagerPage' + pageCounter);
89
+ });
90
 
91
+ pager.pageCounter = pageCounter;
92
+ };
93
 
94
  /**
95
  * Calculate offset for scrolling
96
  */
97
  var findOffset = function () {
98
+ var containerOffset;
99
 
100
  // WooCommerce product tabs
101
  if (el.closest('.woocommerce-tabs').length) {
102
+ containerOffset = el.closest('.woocommerce-tabs').offset();
103
  } else {
104
+ containerOffset = el.find('.simplePagerContainer').offset();
105
  }
106
 
107
+ pager.scrollto = ~~(containerOffset.top - pager.settings.offset);
108
 
109
  // WordPress admin bar
110
  if (document.getElementById('#wpadminbar')) {
111
+ pager.scrollto -= 32;
112
  }
113
+ };
114
 
115
  /**
116
  * Hide all and show current
117
  */
118
  var switchPages = function (fade) {
119
  // Hide the pages
120
+ pager.div.children().hide();
121
 
122
  // Show the container which now has paging controls
123
+ el.show();
124
 
125
  // Show the current page
126
+ var newPage = pager.div.children('.simplePagerPage' + pager.currentPage);
127
  if (fade) {
128
+ newPage.fadeIn();
129
  } else {
130
+ newPage.show();
131
  }
132
+ };
133
 
134
  /**
135
  * Add navigation
136
  */
137
  var addNavigation = function () {
138
+ var nav = '<ul class="simplePagerNav">';
139
+ var cssClass;
140
 
141
  for (var i = 1; i <= pager.pageCounter; i++) {
142
+ cssClass = '';
143
  if (i === pager.currentPage) {
144
+ cssClass = 'currentPage ';
145
  }
146
+ nav += '<li class="' + cssClass + 'simplePageNav' + i + '"><a rel="' + i + '" href="#">' + i + '</a></li>';
147
  }
148
+ nav += '</ul>';
149
+ nav = '<div class="simplePagerList">' + nav + '</div>';
150
 
151
  switch (pager.settings.pagerLocation) {
152
  case 'before':
153
+ pager.div.before(nav);
154
+ break;
155
  case 'both':
156
+ pager.div.before(nav);
157
+ pager.div.after(nav);
158
+ break;
159
  default:
160
+ pager.div.after(nav);
161
  }
162
+ };
163
 
164
  /**
165
  * Navigation behavior
166
  */
167
  var navigationHandler = function () {
168
  el.find('.simplePagerNav a').click(function (e) {
169
+ var $this = $(e.target);
170
+ var container;
171
 
172
+ container = $this.closest('.simplePagerContainer');
173
 
174
  // Get the REL attribute
175
+ pager.currentPage = $this.attr('rel');
176
 
177
  // Remove current page highlight
178
+ container.find('li.currentPage').removeClass('currentPage');
179
 
180
  // Add current page highlight
181
+ container.find('a[rel="' + pager.currentPage + '"]').parent('li').addClass('currentPage');
182
 
183
  // Switch pages
184
+ switchPages(true);
185
 
186
  // Scroll up for any nav click
187
+ scroll();
188
 
189
+ return false;
190
+ });
191
+ };
192
 
193
  /**
194
  * Visibility check.
195
  */
196
  var visibilityCheck = function () {
197
  if (el.is(':visible')) {
198
+ clearInterval(pager.visibilityInterval);
199
+ findOffset();
200
  }
201
+ };
202
 
203
  /**
204
  * Setup
205
  */
206
  var setup = function () {
207
+ paginate();
208
  // Bail if only one page
209
  if (pager.pageCounter > 1) {
210
+ addNavigation();
211
+ navigationHandler();
212
  }
213
 
214
+ switchPages();
215
 
216
  // Set up timer to calculate offset which is dependent on visibility
217
+ pager.visibilityInterval = setInterval(visibilityCheck, 500);
218
+ };
219
 
220
  /**
221
  * Start it up
222
  */
223
+ init();
224
 
225
+ return this;
226
+ };
227
 
228
+ })(jQuery);
public/js/lib/strongslider/jquery.strongslider.js CHANGED
@@ -1,6 +1,6 @@
1
  /*!
2
  * jQuery Strong Slider Plugin
3
- * Version 2.0.1
4
  *
5
  * Copyright (c) 2017 Chris Dillon
6
  * Released under the MIT license
@@ -23,7 +23,10 @@
23
  debug: false,
24
  logAs: 'strongSlider',
25
  compat: {
26
- flatsome: false
 
 
 
27
  },
28
 
29
  // GENERAL
@@ -100,40 +103,40 @@
100
 
101
  // CALLBACKS
102
  onSliderLoad: function () {
103
- return true
104
  },
105
  onSlideBefore: function () {
106
- return true
107
  },
108
  onSlideAfter: function () {
109
- return true
110
  },
111
  onSlideNext: function () {
112
- return true
113
  },
114
  onSlidePrev: function () {
115
- return true
116
  },
117
  onSliderResize: function () {
118
- return true
119
  }
120
- }
121
 
122
  $.fn.strongSlider = function (options) {
123
 
124
  if (this.length === 0) {
125
- return this
126
  }
127
 
128
  // create a namespace to be used throughout the plugin
129
  var slider = {},
130
  // set a reference to our slider element
131
  viewEl = this,
132
- el = this.find('.wpmslider-content')
133
 
134
  // Return if slider is already initialized
135
  if ($(el).data('strongSlider')) {
136
- return
137
  }
138
 
139
  /**
@@ -148,119 +151,119 @@
148
  var init = function () {
149
  // Return if slider is already initialized
150
  if ($(el).data('strongSlider')) {
151
- return
152
  }
153
 
154
  // timer to check visibility; used to control sliders in hidden tabs
155
- slider.visibilityInterval = 0
156
  // slider state
157
- slider.hidden = false
158
 
159
  // merge user-supplied options with the defaults
160
- var sliderVar = viewEl.data('slider-var')
161
- var config = {}
162
 
163
- if (typeof( window[sliderVar] ) !== 'undefined') {
164
- config = window[sliderVar].config
165
  }
166
 
167
- slider.settings = $.extend({}, defaults, config, options)
168
- slider.debug = slider.settings.debug
169
- slider.logAs = slider.settings.logAs
170
- if (slider.debug) console.log(slider.logAs, 'slider.settings', slider.settings)
171
 
172
  // parse slideWidth setting
173
- slider.settings.slideWidth = parseInt(slider.settings.slideWidth)
174
 
175
  // store the original children
176
- slider.children = el.children(slider.settings.slideSelector)
177
 
178
  // check if actual number of slides is less than minSlides / maxSlides
179
  if (slider.children.length < slider.settings.minSlides) {
180
- slider.settings.minSlides = slider.children.length
181
  }
182
  if (slider.children.length < slider.settings.maxSlides) {
183
- slider.settings.maxSlides = slider.children.length
184
  }
185
 
186
  // if random start, set the startSlide setting to random number
187
  if (slider.settings.randomStart) {
188
- slider.settings.startSlide = Math.floor(Math.random() * slider.children.length)
189
  }
190
 
191
  // store active slide information
192
- slider.active = {index: slider.settings.startSlide}
193
 
194
  // store if the slider is in carousel mode (displaying / moving multiple slides)
195
- slider.carousel = slider.settings.minSlides > 1 || slider.settings.maxSlides > 1
196
 
197
  // if carousel, force preloadImages = 'all'
198
  if (slider.carousel) {
199
- slider.settings.preloadImages = 'all'
200
  }
201
 
202
  // calculate the min / max width thresholds based on min / max number of slides
203
  // used to setup and update carousel slides dimensions
204
- slider.minThreshold = (slider.settings.minSlides * slider.settings.slideWidth) + ((slider.settings.minSlides - 1) * slider.settings.slideMargin)
205
- slider.maxThreshold = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin)
206
 
207
  // store the current state of the slider (if currently animating, working is true)
208
- slider.working = false
209
 
210
  // initialize the controls object
211
- slider.controls = {}
212
 
213
  // initialize an auto interval
214
  // no interval = is paused or waiting for user to start
215
- slider.interval = null
216
 
217
  // determine which property to use for transitions
218
- slider.animProp = slider.settings.mode === 'vertical' ? 'top' : 'left'
219
 
220
  // determine if hardware acceleration can be used
221
  slider.usingCSS = slider.settings.useCSS && slider.settings.mode !== 'fade' && (function () {
222
  // create our test div element
223
- var div = document.createElement('div')
224
  // css transition properties
225
- var props = ['WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective']
226
 
227
  // test for each property
228
  for (var i = 0; i < props.length; i++) {
229
  if (div.style[props[i]] !== undefined) {
230
- slider.cssPrefix = props[i].replace('Perspective', '').toLowerCase()
231
- slider.animProp = '-' + slider.cssPrefix + '-transform'
232
- return true
233
  }
234
  }
235
- return false
236
- }())
237
 
238
  // if vertical mode always make maxSlides and minSlides equal
239
  if (slider.settings.mode === 'vertical') {
240
- slider.settings.maxSlides = slider.settings.minSlides
241
  }
242
  // save original style data
243
- el.data('origStyle', el.attr('style'))
244
  el.children(slider.settings.slideSelector).each(function () {
245
- $(this).data('origStyle', $(this).attr('style'))
246
- })
247
 
248
  // Bail if no slides
249
  if (!el.getSlideCount()) {
250
- return
251
  }
252
 
253
  // Wait for images loaded
254
  if (slider.settings.imagesLoaded) {
255
  viewEl.imagesLoaded(function () {
256
- initVisibilityCheck()
257
- })
258
  }
259
  else {
260
- initVisibilityCheck()
261
  }
262
 
263
- }
264
 
265
  /**
266
  * Primary
@@ -268,8 +271,8 @@
268
  * @returns {boolean}
269
  */
270
  var reallyVisible = function () {
271
- return (viewEl.is(':visible') && viewEl.css('visibility') !== 'hidden')
272
- }
273
 
274
  /**
275
  * Secondary
@@ -277,67 +280,92 @@
277
  * @returns {boolean}
278
  */
279
  var compatCheck = function () {
280
- if (slider.settings.compat.flatsome) {
281
- if (viewEl.find('img.lazy-load').length) {
282
- if (slider.debug) console.log(slider.logAs, 'lazy loading...')
283
- return false
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
  }
 
285
  }
286
- if (slider.debug) console.log(slider.logAs, 'compat check complete')
287
- return true
288
- }
 
289
 
290
  /**
291
  * Check visibility and lazy load status.
292
  */
293
  var initVisibilityCheck = function () {
294
  if (reallyVisible() && compatCheck()) {
295
- clearInterval(slider.visibilityInterval)
296
- setup()
297
  }
298
  else {
299
  if (slider.visibilityInterval === 0) {
300
- slider.visibilityInterval = setInterval(initVisibilityCheck, 1000 * 4)
301
  }
302
  }
303
- }
304
 
305
  /**
306
  * Performs all DOM and CSS modifications
307
  */
308
  var setup = function () {
309
  // set the default preload selector (visible)
310
- var preloadSelector = slider.children.eq(slider.settings.startSlide)
311
 
312
  // wrap el in a wrapper
313
- el.wrap('<div class="' + slider.settings.wrapperClass + '"><div class="wpmslider-viewport"></div></div>')
314
 
315
  // store a namespace reference to .wpmslider-viewport
316
- slider.viewport = el.parent()
317
 
318
  // add aria-live if the setting is enabled
319
  if (slider.settings.ariaLive) {
320
- slider.viewport.attr('aria-live', 'polite')
321
  }
322
 
323
  // add a loading div to display while images are loading
324
- slider.loader = $('<div class="wpmslider-loading" />')
325
- slider.viewport.prepend(slider.loader)
326
 
327
  // set el to a massive width, to hold any needed slides
328
  // also strip any margin and padding from el
329
  el.css({
330
  width: slider.settings.mode === 'horizontal' ? (slider.children.length * 1000 + 215) + '%' : 'auto',
331
  position: 'relative'
332
- })
333
 
334
  // if using CSS, add the easing property
335
  if (slider.usingCSS && slider.settings.easing) {
336
- el.css('-' + slider.cssPrefix + '-transition-timing-function', slider.settings.easing)
337
  // if not using CSS and no easing value was supplied, use the default JS animation easing (swing)
338
  }
339
  else if (!slider.settings.easing) {
340
- slider.settings.easing = 'swing'
341
  }
342
 
343
  // make modifications to the viewport (.wpmslider-viewport)
@@ -345,17 +373,17 @@
345
  width: '100%',
346
  overflow: 'hidden',
347
  position: 'relative'
348
- })
349
 
350
  slider.viewport.parent().css({
351
  maxWidth: getViewportMaxWidth()
352
- })
353
 
354
  // make modification to the wrapper (.wpmslider-wrapper)
355
  if (!slider.settings.pager && !slider.settings.controls) {
356
  slider.viewport.parent().css({
357
  margin: '0 auto 0px'
358
- })
359
  }
360
 
361
  // apply css to all slider children
@@ -363,17 +391,17 @@
363
  float: slider.settings.mode === 'horizontal' ? 'left' : 'none',
364
  // display: 'unset', // not working in Chrome
365
  position: 'relative'
366
- })
367
 
368
  // apply the calculated width after the float is applied to prevent scrollbar interference
369
- slider.children.css('width', getSlideWidth())
370
 
371
  // if slideMargin is supplied, add the css
372
  if (slider.settings.mode === 'horizontal' && slider.settings.slideMargin > 0) {
373
- slider.children.css('marginRight', slider.settings.slideMargin)
374
  }
375
  if (slider.settings.mode === 'vertical' && slider.settings.slideMargin > 0) {
376
- slider.children.css('marginBottom', slider.settings.slideMargin)
377
  }
378
 
379
  // if "fade" mode, add positioning and z-index CSS
@@ -382,60 +410,60 @@
382
  position: 'absolute',
383
  zIndex: 0,
384
  display: 'none'
385
- })
386
  // prepare the z-index on the showing element
387
- slider.children.eq(slider.settings.startSlide).css({zIndex: slider.settings.slideZIndex, display: 'block'})
388
  }
389
  else {
390
  slider.children.css({
391
  display: 'block'
392
- })
393
  }
394
 
395
  // create an element to contain all slider controls (pager, start / stop, etc)
396
- slider.controls.el = $('<div class="wpmslider-controls" />')
397
 
398
  // if captions are requested, add them
399
  if (slider.settings.captions) {
400
- appendCaptions()
401
  }
402
 
403
  // check if startSlide is last slide
404
- slider.active.last = slider.settings.startSlide === getPagerQty() - 1
405
 
406
  if (slider.settings.preloadImages === 'all') {
407
- preloadSelector = slider.children
408
  }
409
 
410
  // [ LEFT ]
411
  // if controls are requested, add them
412
  if (slider.settings.controls) {
413
- appendControlPrev()
414
  }
415
 
416
  // [ MIDDLE ]
417
  // if auto is true, and auto controls are requested, add them
418
  if (slider.settings.auto && slider.settings.autoControls) {
419
- appendControlsAuto()
420
  }
421
 
422
  // if pager is requested, add it
423
  if (slider.settings.pager) {
424
- appendPager()
425
  }
426
 
427
  // [ RIGHT ]
428
  if (slider.settings.controls) {
429
- appendControlNext()
430
  }
431
 
432
  // if any control option is requested, add the controls wrapper
433
  if (slider.settings.controls || slider.settings.autoControls || slider.settings.pager) {
434
- slider.viewport.after(slider.controls.el)
435
  }
436
 
437
- start()
438
- }
439
 
440
  /**
441
  * Start the slider
@@ -446,78 +474,78 @@
446
  if (slider.settings.infiniteLoop && slider.settings.mode !== 'fade') {
447
 
448
  // slide is always 1 if not carousel mode
449
- var slice = slider.settings.mode === 'vertical' ? slider.settings.minSlides : slider.settings.maxSlides
450
 
451
- var sliceAppend = slider.children.slice(0, slice).clone(true).addClass('wpmslider-clone')
452
 
453
- var slicePrepend = slider.children.slice(-slice).clone(true).addClass('wpmslider-clone')
454
 
455
  if (slider.settings.ariaHidden) {
456
- sliceAppend.attr('aria-hidden', true)
457
- slicePrepend.attr('aria-hidden', true)
458
  }
459
 
460
- el.append(sliceAppend).prepend(slicePrepend)
461
  }
462
 
463
  // remove the loading DOM element
464
- slider.loader.remove()
465
 
466
  // set the left / top position of "el"
467
- setSlidePosition()
468
 
469
  // if "vertical" mode, always use adaptiveHeight to prevent odd behavior
470
  if (slider.settings.mode === 'vertical') {
471
- slider.settings.adaptiveHeight = true
472
  }
473
 
474
  // set the viewport height
475
- slider.viewport.height(getViewportHeight())
476
 
477
  // if stretch, set t-slide height to 100%
478
  if (slider.settings.stretch) {
479
- setSlideHeight()
480
  }
481
 
482
  // make sure everything is positioned just right (same as a window resize)
483
- el.redrawSlider()
484
 
485
  // onSliderLoad callback
486
- slider.settings.onSliderLoad.call(el, slider.active.index)
487
 
488
  // slider has been fully initialized
489
- slider.initialized = true
490
- slider.visibilityInterval = setInterval(visibilityCheck, 500)
491
 
492
  if (slider.settings.responsive) {
493
- attachListeners()
494
  }
495
 
496
  // if auto is true and has more than 1 page, start the show
497
  if (slider.settings.auto
498
  && slider.settings.autoStart
499
  && (getPagerQty() > 1 || slider.settings.autoSlideForOnePage)) {
500
- initAuto()
501
  }
502
  // throw new Error("STOP");
503
 
504
  // if pager is requested, make the appropriate pager link active
505
  if (slider.settings.pager) {
506
- updatePagerActive(slider.settings.startSlide)
507
  }
508
  // check for any updates to the controls (like hideControlOnEnd updates)
509
  if (slider.settings.controls) {
510
- updateDirectionControls()
511
  }
512
  // if touchEnabled is true, setup the touch events
513
  if (slider.settings.touchEnabled) {
514
- initTouch()
515
  }
516
  // if keyboardEnabled is true, setup the keyboard events
517
  if (slider.settings.keyboardEnabled) {
518
- $(document).keydown(keyPress)
519
  }
520
- }
521
 
522
  /**
523
  * ==============================================================
@@ -546,80 +574,80 @@
546
  */
547
  var attachListeners = function () {
548
 
549
- window.addEventListener('resize', updateLayout, false)
550
- window.addEventListener('orientationchange', updateLayout, false)
551
 
552
  // Test this with dev console closed
553
  // (or click in the document once to establish focus).
554
  window.addEventListener('blur', function () {
555
- pauseEvent('blur')
556
- })
557
 
558
  window.addEventListener('focus', function () {
559
- playEvent('blur')
560
- })
561
 
562
- }
563
 
564
  // Debounced resize event.
565
- var updateLayout = _.debounce(function () { resizeWindow() }, 250)
566
 
567
  // General visibility check.
568
  var visibilityCheck = function () {
569
  if (!slider.settings.auto) {
570
- return
571
  }
572
 
573
  if (!reallyVisible()) {
574
- pauseEvent('hide')
575
  }
576
  else {
577
- playEvent('hide')
578
  }
579
 
580
  if (!verge.inViewport(el)) {
581
- pauseEvent('scroll')
582
  }
583
  else {
584
- playEvent('scroll')
585
  }
586
- }
587
 
588
  var pauseEvent = function (action) {
589
  // if the auto show is currently playing (has an active interval)
590
  if (slider.interval) {
591
  // stop the auto show and pass true argument which will prevent control update
592
- el.stopAuto(true)
593
  // create a new autoPaused value which will be used by the corresponding event
594
- slider.autoPaused = action
595
- if (slider.debug) console.log(slider.logAs, 'pause', action)
596
  }
597
- }
598
 
599
  var playEvent = function (action) {
600
  // if the autoPaused value was created by the prior event
601
  if (slider.autoPaused === action) {
602
  // start the auto show and pass true argument which will prevent control update
603
- el.startAuto(true)
604
  // reset the autoPaused value
605
- slider.autoPaused = null
606
- if (slider.debug) console.log(slider.logAs, 'play', action)
607
  }
608
- }
609
 
610
  var setSlideHeight = function () {
611
  var heights = slider.children.map(function () {
612
- return jQuery(this).actual('outerHeight')
613
- }).get()
614
 
615
- var maxHeight = arrayMax(heights)
616
- slider.children.height(maxHeight)
617
- }
618
 
619
  // Function to get the max value in array
620
  var arrayMax = function (array) {
621
- return Math.max.apply(Math, array)
622
- }
623
 
624
  /**
625
  * Returns the calculated height of the SLIDER viewport (not browser viewport),
@@ -627,15 +655,15 @@
627
  */
628
  var getViewportHeight = function () {
629
 
630
- var height = 0
631
 
632
  // first determine which children (slides) should be used in our height calculation
633
- var children = $()
634
 
635
  // if mode is not "vertical" and adaptiveHeight is false, include all children
636
  if (slider.settings.mode !== 'vertical' && !slider.settings.adaptiveHeight) {
637
 
638
- children = slider.children
639
 
640
  }
641
  else {
@@ -643,27 +671,27 @@
643
  // if not carousel, return the single active child
644
  if (!slider.carousel) {
645
 
646
- children = slider.children.eq(slider.active.index)
647
  // if carousel, return a slice of children
648
 
649
  }
650
  else {
651
 
652
  // get the individual slide index
653
- var currentIndex = slider.settings.moveSlides === 1 ? slider.active.index : slider.active.index * getMoveBy()
654
 
655
  // add the current slide to the children
656
- children = slider.children.eq(currentIndex)
657
 
658
  // cycle through the remaining "showing" slides
659
  for (var i = 1; i <= slider.settings.maxSlides - 1; i++) {
660
 
661
  // if looped back to the start
662
  if (currentIndex + i >= slider.children.length) {
663
- children = children.add(slider.children.eq(i - 1))
664
  }
665
  else {
666
- children = children.add(slider.children.eq(currentIndex + i))
667
  }
668
 
669
  }
@@ -676,12 +704,12 @@
676
  if (slider.settings.mode === 'vertical') {
677
 
678
  children.each(function (index) {
679
- height += $(this).outerHeight()
680
- })
681
 
682
  // add user-supplied margins
683
  if (slider.settings.slideMargin > 0) {
684
- height += slider.settings.slideMargin * (slider.settings.minSlides - 1)
685
  }
686
 
687
  }
@@ -689,37 +717,37 @@
689
 
690
  // if not "vertical" mode, calculate the max height of the children
691
  height = Math.max.apply(Math, children.map(function () {
692
- return $(this).outerHeight(false)
693
- }).get())
694
 
695
  }
696
 
697
  if (slider.viewport.css('box-sizing') === 'border-box') {
698
  height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')) +
699
- parseFloat(slider.viewport.css('border-top-width')) + parseFloat(slider.viewport.css('border-bottom-width'))
700
  }
701
  else if (slider.viewport.css('box-sizing') === 'padding-box') {
702
- height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom'))
703
  }
704
 
705
- return height
706
- }
707
 
708
  /**
709
  * Returns the calculated width to be used for the outer wrapper / SLIDER viewport
710
  */
711
  var getViewportMaxWidth = function () {
712
- var width = '100%'
713
  if (slider.settings.slideWidth > 0) {
714
  if (slider.settings.mode === 'horizontal') {
715
- width = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin)
716
  }
717
  else {
718
- width = slider.settings.slideWidth
719
  }
720
  }
721
- return width
722
- }
723
 
724
  /**
725
  * Returns the calculated width to be applied to each slide
@@ -727,61 +755,61 @@
727
  var getSlideWidth = function () {
728
 
729
  var newElWidth = slider.settings.slideWidth, // start with any user-supplied slide width
730
- wrapWidth = slider.viewport.width() // get the current viewport width
731
 
732
  // if slide width was not supplied, or is larger than the viewport use the viewport width
733
  if (slider.settings.slideWidth === 0 ||
734
 
735
  (slider.settings.slideWidth > wrapWidth && !slider.carousel) ||
736
  slider.settings.mode === 'vertical') {
737
- newElWidth = wrapWidth
738
 
739
  }
740
  else if (slider.settings.maxSlides > 1 && slider.settings.mode === 'horizontal') {
741
 
742
  // if carousel, use the thresholds to determine the width
743
  if (wrapWidth > slider.maxThreshold) {
744
- return newElWidth
745
  }
746
  else if (wrapWidth < slider.minThreshold) {
747
- newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.minSlides - 1))) / slider.settings.minSlides
748
  }
749
  else if (slider.settings.shrinkItems) {
750
- newElWidth = Math.floor((wrapWidth + slider.settings.slideMargin) / (Math.ceil((wrapWidth + slider.settings.slideMargin) / (newElWidth + slider.settings.slideMargin))) - slider.settings.slideMargin)
751
  }
752
 
753
  }
754
- return newElWidth
755
- }
756
 
757
  /**
758
  * Returns the number of slides currently visible in the viewport (includes partially visible slides)
759
  */
760
  var getNumberSlidesShowing = function () {
761
  var slidesShowing = 1,
762
- childWidth = null
763
  if (slider.settings.mode === 'horizontal' && slider.settings.slideWidth > 0) {
764
  // if viewport is smaller than minThreshold, return minSlides
765
  if (slider.viewport.width() < slider.minThreshold) {
766
- slidesShowing = slider.settings.minSlides
767
  }
768
  // if viewport is larger than maxThreshold, return maxSlides
769
  else if (slider.viewport.width() > slider.maxThreshold) {
770
- slidesShowing = slider.settings.maxSlides
771
  }
772
  // if viewport is between min / max thresholds, divide viewport width by first child width
773
  else {
774
- childWidth = slider.children.first().width() + slider.settings.slideMargin
775
  slidesShowing = Math.floor((slider.viewport.width() +
776
- slider.settings.slideMargin) / childWidth)
777
  }
778
  }
779
  // if "vertical" mode, slides showing will always be minSlides
780
  else if (slider.settings.mode === 'vertical') {
781
- slidesShowing = slider.settings.minSlides
782
  }
783
- return slidesShowing
784
- }
785
 
786
  /**
787
  * Returns the number of pages (one full viewport of slides is one "page")
@@ -789,27 +817,27 @@
789
  var getPagerQty = function () {
790
  var pagerQty = 0,
791
  breakPoint = 0,
792
- counter = 0
793
  // if moveSlides is specified by the user
794
  if (slider.settings.moveSlides > 0) {
795
  if (slider.settings.infiniteLoop) {
796
- pagerQty = Math.ceil(slider.children.length / getMoveBy())
797
  }
798
  else {
799
  // when breakpoint goes above children length, counter is the number of pages
800
  while (breakPoint < slider.children.length) {
801
- ++pagerQty
802
- breakPoint = counter + getNumberSlidesShowing()
803
- counter += slider.settings.moveSlides <= getNumberSlidesShowing() ? slider.settings.moveSlides : getNumberSlidesShowing()
804
  }
805
  }
806
  }
807
  // if moveSlides is 0 (auto) divide children length by sides showing, then round up
808
  else {
809
- pagerQty = Math.ceil(slider.children.length / getNumberSlidesShowing())
810
  }
811
- return pagerQty
812
- }
813
 
814
  /**
815
  * Returns the number of individual slides by which to shift the slider
@@ -817,34 +845,34 @@
817
  var getMoveBy = function () {
818
  // if moveSlides was set by the user and moveSlides is less than number of slides showing
819
  if (slider.settings.moveSlides > 0 && slider.settings.moveSlides <= getNumberSlidesShowing()) {
820
- return slider.settings.moveSlides
821
  }
822
  // if moveSlides is 0 (auto)
823
- return getNumberSlidesShowing()
824
- }
825
 
826
  /**
827
  * Sets the slider's (el) left or top position
828
  */
829
  var setSlidePosition = function () {
830
- var position, lastChild, lastShowingIndex
831
 
832
  // if last slide, not infinite loop, and number of children is larger than specified maxSlides
833
  if (slider.children.length > slider.settings.maxSlides && slider.active.last && !slider.settings.infiniteLoop) {
834
 
835
  if (slider.settings.mode === 'horizontal') {
836
  // get the last child's position
837
- lastChild = slider.children.last()
838
- position = lastChild.position()
839
  // set the left position
840
- setPositionProperty(-(position.left - (slider.viewport.width() - lastChild.outerWidth())), 'reset', 0)
841
  }
842
  else if (slider.settings.mode === 'vertical') {
843
  // get the last showing index's position
844
- lastShowingIndex = slider.children.length - slider.settings.minSlides
845
- position = slider.children.eq(lastShowingIndex).position()
846
  // set the top position
847
- setPositionProperty(-position.top, 'reset', 0)
848
  }
849
 
850
  }
@@ -852,28 +880,28 @@
852
  else {
853
 
854
  // get the position of the first showing slide
855
- position = slider.children.eq(slider.active.index * getMoveBy()).position()
856
 
857
  // check for last slide
858
  if (slider.active.index === getPagerQty() - 1) {
859
- slider.active.last = true
860
  }
861
 
862
  // set the respective position
863
  if (position !== undefined) {
864
  if (slider.settings.mode === 'horizontal') {
865
- setPositionProperty(-position.left, 'reset', 0)
866
  }
867
  else if (slider.settings.mode === 'vertical') {
868
- setPositionProperty(-position.top, 'reset', 0)
869
  }
870
  else if (slider.settings.mode === 'none') {
871
- setPositionProperty(-position.top, 'reset', 0)
872
  }
873
  }
874
 
875
  }
876
- }
877
 
878
  /**
879
  * Sets the el's animating property position (which in turn will sometimes animate el).
@@ -892,7 +920,7 @@
892
  * - an optional parameter containing any variables that need to be passed in
893
  */
894
  var setPositionProperty = function (value, type, duration, params) {
895
- var animateObj, propValue
896
  // use CSS transform
897
  if (slider.usingCSS) {
898
 
@@ -900,45 +928,45 @@
900
  // propValue = slider.settings.mode === 'vertical' ? 'translate3d(0, ' + value + 'px, 0)' : 'translate3d(' + value + 'px, 0, 0)'
901
  if (slider.settings.mode === 'vertical') {
902
  //propValue = 'translate3d(0, ' + value + 'px, 0)'
903
- propValue = 'translateY(' + value + 'px)'
904
  }
905
  else if (slider.settings.mode === 'horizontal') {
906
  // propValue = 'translate3d(' + value + 'px, 0, 0)'
907
- propValue = 'translateX(' + value + 'px'
908
  }
909
  else if (slider.settings.mode === 'none') {
910
  // propValue = 'translate3d(0, ' + value + 'px, 0)'
911
- propValue = 'translateY(' + value + 'px)'
912
- duration = 0
913
  }
914
 
915
  // add the CSS transition-duration
916
- el.css('-' + slider.cssPrefix + '-transition-duration', duration / 1000 + 's')
917
 
918
  if (type === 'slide') {
919
 
920
  // set the property value
921
- el.css(slider.animProp, propValue)
922
  if (duration !== 0) {
923
  // bind a callback method - executes when CSS transition completes
924
  el.on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function (e) {
925
  //make sure it's the correct one
926
  if (!$(e.target).is(el)) {
927
- return
928
  }
929
  // unbind the callback
930
- el.off('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd')
931
- updateAfterSlideTransition()
932
- })
933
  }
934
  else {
935
- updateAfterSlideTransition()
936
  }
937
 
938
  }
939
  else if (type === 'reset') {
940
 
941
- el.css(slider.animProp, propValue)
942
 
943
  }
944
 
@@ -946,19 +974,19 @@
946
  // use JS animate
947
  else {
948
 
949
- animateObj = {}
950
- animateObj[slider.animProp] = value
951
  if (type === 'slide') {
952
  el.animate(animateObj, duration, slider.settings.easing, function () {
953
- updateAfterSlideTransition()
954
- })
955
  }
956
  else if (type === 'reset') {
957
- el.css(slider.animProp, value)
958
  }
959
 
960
  }
961
- }
962
 
963
  /**
964
  * Populates the pager with proper amount of pages
@@ -966,35 +994,35 @@
966
  var populatePager = function () {
967
  var pagerHtml = '',
968
  linkContent = '',
969
- pagerQty = getPagerQty()
970
 
971
  // loop through each pager item
972
  for (var i = 0; i < pagerQty; i++) {
973
- linkContent = ''
974
 
975
  if (slider.settings.buildPager) {
976
  // if using icons, use no link text
977
  if (slider.settings.buildPager === 'icons') {
978
- linkContent = ''
979
  }
980
  // if a buildPager function is supplied, use it to get pager link value, else use index + 1
981
  if ($.isFunction(slider.settings.buildPager) || slider.settings.pagerCustom) {
982
- linkContent = slider.settings.buildPager(i)
983
  }
984
- slider.pagerEl.addClass('wpmslider-custom-pager')
985
  }
986
  else {
987
- linkContent = i + 1
988
- slider.pagerEl.addClass('wpmslider-default-pager')
989
  }
990
 
991
  // add the markup to the string
992
- pagerHtml += '<div class="wpmslider-pager-item"><a href="" data-slide-index="' + i + '" class="wpmslider-pager-link">' + linkContent + '</a></div>'
993
  }
994
 
995
  // populate the pager element with pager links
996
- slider.pagerEl.html(pagerHtml)
997
- }
998
 
999
  /**
1000
  * Appends the pager to the controls element
@@ -1002,108 +1030,108 @@
1002
  var appendPager = function () {
1003
  if (!slider.settings.pagerCustom) {
1004
  // create the pager DOM element
1005
- slider.pagerEl = $('<div class="wpmslider-pager" />')
1006
  // if a pager selector was supplied, populate it with the pager
1007
  if (slider.settings.pagerSelector) {
1008
- $(slider.settings.pagerSelector).html(slider.pagerEl)
1009
  }
1010
  else {
1011
  // if no pager selector was supplied, add it after the wrapper
1012
- slider.controls.el.addClass('wpmslider-has-pager').append(slider.pagerEl)
1013
  }
1014
  // populate the pager
1015
- populatePager()
1016
  }
1017
  else {
1018
- slider.pagerEl = $(slider.settings.pagerCustom)
1019
  }
1020
  // assign the pager click binding
1021
- slider.pagerEl.on('click touchend', 'a', clickPagerBind)
1022
- }
1023
 
1024
  /**
1025
  * Appends prev control to the controls element
1026
  */
1027
  var appendControlPrev = function () {
1028
- slider.controls.prev = $('<a class="wpmslider-prev" href="">' + slider.settings.prevText + '</a>')
1029
 
1030
  // bind click actions to the controls
1031
- slider.controls.prev.on('click touchend', clickPrevBind)
1032
 
1033
  // if prevSelector was supplied, populate it
1034
  if (slider.settings.prevSelector) {
1035
- $(slider.settings.prevSelector).append(slider.controls.prev)
1036
  }
1037
 
1038
  // if no custom selectors were supplied
1039
  if (!slider.settings.prevSelector) {
1040
  // add the controls to the DOM
1041
- slider.controls.directionEl = $('<div class="wpmslider-controls-direction" />')
1042
  // add the control elements to the directionEl
1043
- slider.controls.directionEl.append(slider.controls.prev)
1044
- slider.controls.el.addClass('wpmslider-has-controls-direction').append(slider.controls.directionEl)
1045
  }
1046
- }
1047
 
1048
  /**
1049
  * Appends prev / next controls to the controls element
1050
  */
1051
  var appendControlNext = function () {
1052
- slider.controls.next = $('<a class="wpmslider-next" href="">' + slider.settings.nextText + '</a>')
1053
 
1054
  // bind click actions to the controls
1055
- slider.controls.next.on('click touchend', clickNextBind)
1056
 
1057
  // if nextSelector was supplied, populate it
1058
  if (slider.settings.nextSelector) {
1059
- $(slider.settings.nextSelector).append(slider.controls.next)
1060
  }
1061
 
1062
  // if no custom selectors were supplied
1063
  if (!slider.settings.nextSelector) {
1064
  // add the controls to the DOM
1065
- slider.controls.directionEl = $('<div class="wpmslider-controls-direction" />')
1066
  // add the control elements to the directionEl
1067
- slider.controls.directionEl.append(slider.controls.next)
1068
- slider.controls.el.addClass('wpmslider-has-controls-direction').append(slider.controls.directionEl)
1069
  }
1070
- }
1071
 
1072
  /**
1073
  * Appends start / stop auto controls to the controls element
1074
  */
1075
  var appendControlsAuto = function () {
1076
- slider.controls.start = $('<div class="wpmslider-controls-auto-item"><a class="wpmslider-start" href="">' + slider.settings.startText + '</a></div>')
1077
- slider.controls.stop = $('<div class="wpmslider-controls-auto-item"><a class="wpmslider-stop" href="">' + slider.settings.stopText + '</a></div>')
1078
 
1079
  // add the controls to the DOM
1080
- slider.controls.autoEl = $('<div class="wpmslider-controls-auto" />')
1081
 
1082
  // bind click actions to the controls
1083
- slider.controls.autoEl.on('click', '.wpmslider-start', clickStartBind)
1084
- slider.controls.autoEl.on('click', '.wpmslider-stop', clickStopBind)
1085
 
1086
  // if autoControlsCombine, insert only the "start" control
1087
  if (slider.settings.autoControlsCombine) {
1088
- slider.controls.autoEl.append(slider.controls.start)
1089
  // if autoControlsCombine is false, insert both controls
1090
  }
1091
  else {
1092
- slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop)
1093
  }
1094
 
1095
  // if auto controls selector was supplied, populate it with the controls
1096
  if (slider.settings.autoControlsSelector) {
1097
- $(slider.settings.autoControlsSelector).html(slider.controls.autoEl)
1098
  // if auto controls selector was not supplied, add it after the wrapper
1099
  }
1100
  else {
1101
- slider.controls.el.addClass('wpmslider-has-controls-auto').append(slider.controls.autoEl)
1102
  }
1103
 
1104
  // update the auto controls
1105
- updateAutoControls(slider.settings.autoStart ? 'stop' : 'start')
1106
- }
1107
 
1108
  /**
1109
  * Appends image captions to the DOM
@@ -1112,13 +1140,13 @@
1112
  // cycle through each child
1113
  slider.children.each(function (index) {
1114
  // get the image title attribute
1115
- var title = $(this).find('img:first').attr('title')
1116
  // append the caption
1117
  if (title !== undefined && ('' + title).length) {
1118
- $(this).append('<div class="wpmslider-caption"><span>' + title + '</span></div>')
1119
  }
1120
- })
1121
- }
1122
 
1123
  /**
1124
  * Click next binding
@@ -1127,18 +1155,18 @@
1127
  * - DOM event object
1128
  */
1129
  var clickNextBind = function (e) {
1130
- e.preventDefault()
1131
- e.stopPropagation()
1132
  if (slider.controls.el.hasClass('disabled')) {
1133
- return
1134
  }
1135
  // if auto show is running, stop it
1136
  if (slider.settings.auto && slider.settings.stopAutoOnClick) {
1137
- if (slider.debug) console.log(slider.logAs, 'stop on navigation')
1138
- el.stopAuto()
1139
  }
1140
- el.goToNextSlide()
1141
- }
1142
 
1143
  /**
1144
  * Click prev binding
@@ -1147,18 +1175,18 @@
1147
  * - DOM event object
1148
  */
1149
  var clickPrevBind = function (e) {
1150
- e.preventDefault()
1151
- e.stopPropagation()
1152
  if (slider.controls.el.hasClass('disabled')) {
1153
- return
1154
  }
1155
  // if auto show is running, stop it
1156
  if (slider.settings.auto && slider.settings.stopAutoOnClick) {
1157
- if (slider.debug) console.log(slider.logAs, 'stop on navigation')
1158
- el.stopAuto()
1159
  }
1160
- el.goToPrevSlide()
1161
- }
1162
 
1163
  /**
1164
  * Click start binding
@@ -1167,10 +1195,10 @@
1167
  * - DOM event object
1168
  */
1169
  var clickStartBind = function (e) {
1170
- el.startAuto()
1171
- e.preventDefault()
1172
- e.stopPropagation()
1173
- }
1174
 
1175
  /**
1176
  * Click stop binding
@@ -1179,10 +1207,10 @@
1179
  * - DOM event object
1180
  */
1181
  var clickStopBind = function (e) {
1182
- el.stopAuto()
1183
- e.preventDefault()
1184
- e.stopPropagation()
1185
- }
1186
 
1187
  /**
1188
  * Click pager binding
@@ -1191,26 +1219,26 @@
1191
  * - DOM event object
1192
  */
1193
  var clickPagerBind = function (e) {
1194
- var pagerLink, pagerIndex
1195
- e.preventDefault()
1196
- e.stopPropagation()
1197
  if (slider.controls.el.hasClass('disabled')) {
1198
- return
1199
  }
1200
  // if auto show is running, stop it
1201
  if (slider.settings.auto && slider.settings.stopAutoOnClick) {
1202
- if (slider.debug) console.log(slider.logAs, 'stop on navigation')
1203
- el.stopAuto()
1204
  }
1205
- pagerLink = $(e.currentTarget)
1206
  if (pagerLink.attr('data-slide-index') !== undefined) {
1207
- pagerIndex = parseInt(pagerLink.attr('data-slide-index'))
1208
  // if clicked pager link is not active, continue with the goToSlide call
1209
  if (pagerIndex !== slider.active.index) {
1210
- el.goToSlide(pagerIndex)
1211
  }
1212
  }
1213
- }
1214
 
1215
  /**
1216
  * Updates the pager links with an active class
@@ -1220,21 +1248,21 @@
1220
  */
1221
  var updatePagerActive = function (slideIndex) {
1222
  // if "short" pager type
1223
- var len = slider.children.length // nb of children
1224
  if (slider.settings.pagerType === 'short') {
1225
  if (slider.settings.maxSlides > 1) {
1226
- len = Math.ceil(slider.children.length / slider.settings.maxSlides)
1227
  }
1228
- slider.pagerEl.html((slideIndex + 1) + slider.settings.pagerShortSeparator + len)
1229
- return
1230
  }
1231
  // remove all pager active classes
1232
- slider.pagerEl.find('a').removeClass('active')
1233
  // apply the active class for all pagers
1234
  slider.pagerEl.each(function (i, el) {
1235
- $(el).find('a').eq(slideIndex).addClass('active')
1236
- })
1237
- }
1238
 
1239
  /**
1240
  * Performs needed actions after a slide transition
@@ -1242,34 +1270,34 @@
1242
  var updateAfterSlideTransition = function () {
1243
  // if infinite loop is true
1244
  if (slider.settings.infiniteLoop) {
1245
- var position = ''
1246
  // first slide
1247
  if (slider.active.index === 0) {
1248
  // set the new position
1249
- position = slider.children.eq(0).position()
1250
  }
1251
  // carousel, last slide
1252
  else if (slider.active.index === getPagerQty() - 1 && slider.carousel) {
1253
- position = slider.children.eq((getPagerQty() - 1) * getMoveBy()).position()
1254
  }
1255
  // last slide
1256
  else if (slider.active.index === slider.children.length - 1) {
1257
- position = slider.children.eq(slider.children.length - 1).position()
1258
  }
1259
  if (position) {
1260
  if (slider.settings.mode === 'horizontal') {
1261
- setPositionProperty(-position.left, 'reset', 0)
1262
  }
1263
  else if (slider.settings.mode === 'vertical') {
1264
- setPositionProperty(-position.top, 'reset', 0)
1265
  }
1266
  }
1267
  }
1268
  // declare that the transition is complete
1269
- slider.working = false
1270
  // onSlideAfter callback
1271
- slider.settings.onSlideAfter.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)
1272
- }
1273
 
1274
  /**
1275
  * Updates the auto controls state (either active, or combined switch)
@@ -1280,41 +1308,41 @@
1280
  var updateAutoControls = function (state) {
1281
  // if autoControlsCombine is true, replace the current control with the new state
1282
  if (slider.settings.autoControlsCombine) {
1283
- slider.controls.autoEl.html(slider.controls[state])
1284
  }
1285
  // if autoControlsCombine is false, apply the "active" class to the appropriate control
1286
  else {
1287
- slider.controls.autoEl.find('a').removeClass('active')
1288
- slider.controls.autoEl.find('a:not(.wpmslider-' + state + ')').addClass('active')
1289
  }
1290
- }
1291
 
1292
  /**
1293
  * Updates the direction controls (checks if either should be hidden)
1294
  */
1295
  var updateDirectionControls = function () {
1296
  if (getPagerQty() === 1) {
1297
- slider.controls.prev.addClass('disabled')
1298
- slider.controls.next.addClass('disabled')
1299
  }
1300
  else if (!slider.settings.infiniteLoop && slider.settings.hideControlOnEnd) {
1301
  // if first slide
1302
  if (slider.active.index === 0) {
1303
- slider.controls.prev.addClass('disabled')
1304
- slider.controls.next.removeClass('disabled')
1305
  }
1306
  // if last slide
1307
  else if (slider.active.index === getPagerQty() - 1) {
1308
- slider.controls.next.addClass('disabled')
1309
- slider.controls.prev.removeClass('disabled')
1310
  }
1311
  // if any slide in the middle
1312
  else {
1313
- slider.controls.prev.removeClass('disabled')
1314
- slider.controls.next.removeClass('disabled')
1315
  }
1316
  }
1317
- }
1318
 
1319
  /**
1320
  * Initializes the auto process
@@ -1322,23 +1350,23 @@
1322
  var initAuto = function () {
1323
  // if autoDelay was supplied, launch the auto show using a setTimeout() call
1324
  if (slider.settings.autoDelay > 0) {
1325
- var timeout = setTimeout(el.startAuto, slider.settings.autoDelay)
1326
  }
1327
  // if autoDelay was not supplied, start the auto show normally
1328
  else {
1329
- el.startAuto()
1330
  }
1331
 
1332
  // if autoHover is requested
1333
  if (slider.settings.autoHover) {
1334
  // on el hover
1335
  el.hover(function () {
1336
- pauseEvent('hover')
1337
  }, function () {
1338
- playEvent('hover')
1339
- })
1340
  }
1341
- }
1342
 
1343
  /**
1344
  * Check if el is on screen
@@ -1370,19 +1398,19 @@
1370
  var activeElementTag = document.activeElement.tagName.toLowerCase(),
1371
  tagFilters = 'input|textarea',
1372
  p = new RegExp(activeElementTag, ['i']),
1373
- result = p.exec(tagFilters)
1374
 
1375
  if (result === null && verge.inViewport(el)) {
1376
  if (e.keyCode === 39) {
1377
- clickNextBind(e)
1378
- return false
1379
  }
1380
  else if (e.keyCode === 37) {
1381
- clickPrevBind(e)
1382
- return false
1383
  }
1384
  }
1385
- }
1386
 
1387
  /**
1388
  * Initializes touch events
@@ -1392,19 +1420,19 @@
1392
  slider.touch = {
1393
  start: {x: 0, y: 0},
1394
  end: {x: 0, y: 0}
1395
- }
1396
- slider.viewport.on('touchstart MSPointerDown pointerdown', onTouchStart)
1397
 
1398
  //for browsers that have implemented pointer events and fire a click after
1399
  //every pointerup regardless of whether pointerup is on same screen location as pointerdown or not
1400
  slider.viewport.on('click', '.wpmslider a', function (e) {
1401
  if (slider.viewport.hasClass('click-disabled')) {
1402
- e.preventDefault()
1403
- e.stopPropagation()
1404
- slider.viewport.removeClass('click-disabled')
1405
  }
1406
- })
1407
- }
1408
 
1409
  /**
1410
  * Event handler for "touchstart"
@@ -1414,38 +1442,38 @@
1414
  */
1415
  var onTouchStart = function (e) {
1416
  //disable slider controls while user is interacting with slides to avoid slider freeze that happens on touch devices when a slide swipe happens immediately after interacting with slider controls
1417
- slider.controls.el.addClass('disabled')
1418
 
1419
  if (slider.working) {
1420
- e.preventDefault()
1421
- e.stopPropagation()
1422
- slider.controls.el.removeClass('disabled')
1423
  }
1424
  else {
1425
  // record the original position when touch starts
1426
- slider.touch.originalPos = el.position()
1427
  var orig = e.originalEvent,
1428
- touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig]
1429
  // https://stackoverflow.com/questions/41541121/domexception-failed-to-execute-setpointercapture-on-element-and-releasepoin
1430
- var chromePointerEvents = typeof PointerEvent === 'function'
1431
  if (chromePointerEvents) { if (orig.pointerId === undefined) { return; } }
1432
  // record the starting touch x, y coordinates
1433
- slider.touch.start.x = touchPoints[0].pageX
1434
- slider.touch.start.y = touchPoints[0].pageY
1435
 
1436
  if (slider.viewport.get(0).setPointerCapture) {
1437
- slider.pointerId = orig.pointerId
1438
- if(slider.pointerId === 1){
1439
  slider.viewport.get(0).setPointerCapture(slider.pointerId);
1440
  }
1441
  }
1442
  // bind a "touchmove" event to the viewport
1443
- slider.viewport.on('touchmove MSPointerMove pointermove', onTouchMove)
1444
  // bind a "touchend" event to the viewport
1445
- slider.viewport.on('touchend MSPointerUp pointerup', onTouchEnd)
1446
- slider.viewport.on('MSPointerCancel pointercancel', onPointerCancel)
1447
  }
1448
- }
1449
 
1450
  /**
1451
  * Cancel Pointer for Windows Phone
@@ -1456,17 +1484,17 @@
1456
  var onPointerCancel = function (e) {
1457
  /* onPointerCancel handler is needed to deal with situations when a touchend
1458
  doesn't fire after a touchstart (this happens on windows phones only) */
1459
- setPositionProperty(slider.touch.originalPos.left, 'reset', 0)
1460
 
1461
  //remove handlers
1462
- slider.controls.el.removeClass('disabled')
1463
- slider.viewport.off('MSPointerCancel pointercancel', onPointerCancel)
1464
- slider.viewport.off('touchmove MSPointerMove pointermove', onTouchMove)
1465
- slider.viewport.off('touchend MSPointerUp pointerup', onTouchEnd)
1466
  if (slider.viewport.get(0).releasePointerCapture) {
1467
- slider.viewport.get(0).releasePointerCapture(slider.pointerId)
1468
  }
1469
- }
1470
 
1471
  /**
1472
  * Event handler for "touchmove"
@@ -1481,32 +1509,32 @@
1481
  xMovement = Math.abs(touchPoints[0].pageX - slider.touch.start.x),
1482
  yMovement = Math.abs(touchPoints[0].pageY - slider.touch.start.y),
1483
  value = 0,
1484
- change = 0
1485
 
1486
  // x axis swipe
1487
  if ((xMovement * 3) > yMovement && slider.settings.preventDefaultSwipeX) {
1488
- e.preventDefault()
1489
- e.stopPropagation()
1490
  }
1491
  // y axis swipe
1492
  else if ((yMovement * 3) > xMovement && slider.settings.preventDefaultSwipeY) {
1493
- e.preventDefault()
1494
- e.stopPropagation()
1495
  }
1496
  if (slider.settings.mode !== 'fade' && slider.settings.oneToOneTouch) {
1497
  // if horizontal, drag along x axis
1498
  if (slider.settings.mode === 'horizontal') {
1499
- change = touchPoints[0].pageX - slider.touch.start.x
1500
- value = slider.touch.originalPos.left + change
1501
  // if vertical, drag along y axis
1502
  }
1503
  else {
1504
- change = touchPoints[0].pageY - slider.touch.start.y
1505
- value = slider.touch.originalPos.top + change
1506
  }
1507
- setPositionProperty(value, 'reset', 0)
1508
  }
1509
- }
1510
 
1511
  /**
1512
  * Event handler for "touchend"
@@ -1515,66 +1543,66 @@
1515
  * - DOM event object
1516
  */
1517
  var onTouchEnd = function (e) {
1518
- slider.viewport.off('touchmove MSPointerMove pointermove', onTouchMove)
1519
  //enable slider controls as soon as user stops interacing with slides
1520
- slider.controls.el.removeClass('disabled')
1521
  var orig = e.originalEvent,
1522
  touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig],
1523
  value = 0,
1524
- distance = 0
1525
  // record end x, y positions
1526
- slider.touch.end.x = touchPoints[0].pageX
1527
- slider.touch.end.y = touchPoints[0].pageY
1528
  // if fade mode, check if absolute x distance clears the threshold
1529
  if (slider.settings.mode === 'fade') {
1530
- distance = Math.abs(slider.touch.start.x - slider.touch.end.x)
1531
  if (distance >= slider.settings.swipeThreshold) {
1532
  if (slider.touch.start.x > slider.touch.end.x) {
1533
- el.goToNextSlide()
1534
  }
1535
  else {
1536
- el.goToPrevSlide()
1537
  }
1538
- el.stopAuto()
1539
  }
1540
  }
1541
  // not fade mode
1542
  else {
1543
  // calculate distance and el's animate property
1544
  if (slider.settings.mode === 'horizontal') {
1545
- distance = slider.touch.end.x - slider.touch.start.x
1546
- value = slider.touch.originalPos.left
1547
  }
1548
  else {
1549
- distance = slider.touch.end.y - slider.touch.start.y
1550
- value = slider.touch.originalPos.top
1551
  }
1552
  // if not infinite loop and first / last slide, do not attempt a slide transition
1553
  if (!slider.settings.infiniteLoop && ((slider.active.index === 0 && distance > 0) || (slider.active.last && distance < 0))) {
1554
- setPositionProperty(value, 'reset', 200)
1555
  }
1556
  else {
1557
  // check if distance clears threshold
1558
  if (Math.abs(distance) >= slider.settings.swipeThreshold) {
1559
  if (distance < 0) {
1560
- el.goToNextSlide()
1561
  }
1562
  else {
1563
- el.goToPrevSlide()
1564
  }
1565
- el.stopAuto()
1566
  }
1567
  else {
1568
  // el.animate(property, 200);
1569
- setPositionProperty(value, 'reset', 200)
1570
  }
1571
  }
1572
  }
1573
- slider.viewport.off('touchend MSPointerUp pointerup', onTouchEnd)
1574
  if (slider.viewport.get(0).releasePointerCapture) {
1575
- slider.viewport.get(0).releasePointerCapture(slider.pointerId)
1576
  }
1577
- }
1578
 
1579
  /**
1580
  * Window resize event callback
@@ -1582,19 +1610,19 @@
1582
  var resizeWindow = function (e) {
1583
  // don't do anything if slider isn't initialized.
1584
  if (!slider.initialized) {
1585
- return
1586
  }
1587
  // Delay if slider working.
1588
  if (slider.working) {
1589
- window.setTimeout(resizeWindow, 10)
1590
  }
1591
  else {
1592
  // update all dynamic elements
1593
- el.redrawSlider()
1594
  // Call user resize handler
1595
- slider.settings.onSliderResize.call(el, slider.active.index)
1596
  }
1597
- }
1598
 
1599
  /**
1600
  * Adds an aria-hidden=true attribute to each element
@@ -1603,15 +1631,15 @@
1603
  * - the first visible element's index
1604
  */
1605
  var applyAriaHiddenAttributes = function (startVisibleIndex) {
1606
- var numberOfSlidesShowing = getNumberSlidesShowing()
1607
  // only apply attributes if the setting is enabled
1608
  if (slider.settings.ariaHidden) {
1609
  // add aria-hidden=true to all elements
1610
- slider.children.attr('aria-hidden', 'true')
1611
  // get the visible elements and change to aria-hidden=false
1612
- slider.children.slice(startVisibleIndex, startVisibleIndex + numberOfSlidesShowing).attr('aria-hidden', 'false')
1613
  }
1614
- }
1615
 
1616
  /**
1617
  * Returns index according to present page range
@@ -1622,28 +1650,28 @@
1622
  var setSlideIndex = function (slideIndex) {
1623
  if (slideIndex < 0) {
1624
  if (slider.settings.infiniteLoop) {
1625
- return getPagerQty() - 1
1626
  }
1627
  else {
1628
  //we don't go to undefined slides
1629
- return slider.active.index
1630
  }
1631
  }
1632
  // if slideIndex is greater than children length, set active index to 0 (this happens during infinite loop)
1633
  else if (slideIndex >= getPagerQty()) {
1634
  if (slider.settings.infiniteLoop) {
1635
- return 0
1636
  }
1637
  else {
1638
  //we don't move to undefined pages
1639
- return slider.active.index
1640
  }
1641
  }
1642
  // set active index to requested slide
1643
  else {
1644
- return slideIndex
1645
  }
1646
- }
1647
 
1648
  /**
1649
  * ===================================================================================
@@ -1667,69 +1695,69 @@
1667
  moveBy = 0,
1668
  position = {left: 0, top: 0},
1669
  lastChild = null,
1670
- lastShowingIndex, eq, value, requestEl
1671
  // store the old index
1672
- slider.oldIndex = slider.active.index
1673
  //set new index
1674
- slider.active.index = setSlideIndex(slideIndex)
1675
 
1676
  // if plugin is currently in motion, ignore request
1677
  if (slider.working || slider.active.index === slider.oldIndex) {
1678
- return
1679
  }
1680
  // declare that plugin is in motion
1681
- slider.working = true
1682
 
1683
- performTransition = slider.settings.onSlideBefore.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)
1684
 
1685
  // If transitions canceled, reset and return
1686
  if (typeof (performTransition) !== 'undefined' && !performTransition) {
1687
- slider.active.index = slider.oldIndex // restore old index
1688
- slider.working = false // is not in motion
1689
- return
1690
  }
1691
 
1692
  if (direction === 'next') {
1693
  // Prevent canceling in future functions or lack thereof from negating previous commands to cancel
1694
  if (!slider.settings.onSlideNext.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)) {
1695
- performTransition = false
1696
  }
1697
  }
1698
  else if (direction === 'prev') {
1699
  // Prevent canceling in future functions or lack thereof from negating previous commands to cancel
1700
  if (!slider.settings.onSlidePrev.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)) {
1701
- performTransition = false
1702
  }
1703
  }
1704
 
1705
  // check if last slide
1706
- slider.active.last = slider.active.index >= getPagerQty() - 1
1707
 
1708
  // update the pager with active class
1709
  if (slider.settings.pager || slider.settings.pagerCustom) {
1710
- updatePagerActive(slider.active.index)
1711
  }
1712
 
1713
  // check for direction control update
1714
  if (slider.settings.controls) {
1715
- updateDirectionControls()
1716
  }
1717
 
1718
  if (slider.settings.mode === 'fade') {
1719
 
1720
  // if adaptiveHeight is true and next height is different from current height, animate to the new height
1721
  if (slider.settings.adaptiveHeight && slider.viewport.height() !== getViewportHeight()) {
1722
- slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed)
1723
  }
1724
 
1725
  // fade out the visible child and reset its z-index value
1726
- slider.children.filter(':visible').fadeOut(slider.settings.speed).css({zIndex: 0})
1727
 
1728
  // fade in the newly requested slide
1729
  slider.children.eq(slider.active.index).css('zIndex', slider.settings.slideZIndex + 1).fadeIn(slider.settings.speed, function () {
1730
- $(this).css('zIndex', slider.settings.slideZIndex)
1731
- updateAfterSlideTransition()
1732
- })
1733
 
1734
  }
1735
  // slider mode is not "fade"
@@ -1737,7 +1765,7 @@
1737
 
1738
  // if adaptiveHeight is true and next height is different from current height, animate to the new height
1739
  if (slider.settings.adaptiveHeight && slider.viewport.height() !== getViewportHeight()) {
1740
- slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed)
1741
  }
1742
 
1743
  // if carousel and not infinite loop
@@ -1745,15 +1773,15 @@
1745
 
1746
  if (slider.settings.mode === 'horizontal') {
1747
  // get the last child position
1748
- lastChild = slider.children.eq(slider.children.length - 1)
1749
- position = lastChild.position()
1750
  // calculate the position of the last slide
1751
- moveBy = slider.viewport.width() - lastChild.outerWidth()
1752
  }
1753
  else {
1754
  // get last showing index position
1755
- lastShowingIndex = slider.children.length - slider.settings.minSlides
1756
- position = slider.children.eq(lastShowingIndex).position()
1757
  }
1758
 
1759
  }
@@ -1761,25 +1789,25 @@
1761
  else if (slider.carousel && slider.active.last && direction === 'prev') {
1762
 
1763
  // get the last child position
1764
- eq = slider.settings.moveSlides === 1 ? slider.settings.maxSlides - getMoveBy() : ((getPagerQty() - 1) * getMoveBy()) - (slider.children.length - slider.settings.maxSlides)
1765
- lastChild = el.children('.wpmslider-clone').eq(eq)
1766
- position = lastChild.position()
1767
 
1768
  }
1769
  // if infinite loop and "Next" is clicked on the last slide
1770
  else if (direction === 'next' && slider.active.index === 0) {
1771
 
1772
  // get the last clone position
1773
- position = el.find('> .wpmslider-clone').eq(slider.settings.maxSlides).position()
1774
- slider.active.last = false
1775
 
1776
  }
1777
  // normal non-zero requests
1778
  else if (slideIndex >= 0) {
1779
 
1780
  //parseInt is applied to allow floats for slides/page
1781
- requestEl = slideIndex * parseInt(getMoveBy())
1782
- position = slider.children.eq(requestEl).position()
1783
 
1784
  }
1785
 
@@ -1791,26 +1819,26 @@
1791
 
1792
  // value = slider.settings.mode === 'horizontal' ? -(position.left - moveBy) : -position.top
1793
  if (slider.settings.mode === 'horizontal') {
1794
- value = -(position.left - moveBy)
1795
  }
1796
  else {
1797
- value = -position.top
1798
  }
1799
 
1800
  // plugin values to be animated
1801
- setPositionProperty(value, 'slide', slider.settings.speed)
1802
 
1803
  }
1804
  else {
1805
- slider.working = false
1806
  }
1807
 
1808
  }
1809
 
1810
  if (slider.settings.ariaHidden) {
1811
- applyAriaHiddenAttributes(slider.active.index * getMoveBy())
1812
  }
1813
- }
1814
 
1815
  /**
1816
  * Transitions to the next slide in the show
@@ -1818,11 +1846,11 @@
1818
  el.goToNextSlide = function () {
1819
  // if infiniteLoop is false and last page is showing, disregard call
1820
  if (!slider.settings.infiniteLoop && slider.active.last) {
1821
- return
1822
  }
1823
- var pagerIndex = parseInt(slider.active.index) + 1
1824
- el.goToSlide(pagerIndex, 'next')
1825
- }
1826
 
1827
  /**
1828
  * Transitions to the prev slide in the show
@@ -1830,11 +1858,11 @@
1830
  el.goToPrevSlide = function () {
1831
  // if infiniteLoop is false and last page is showing, disregard call
1832
  if (!slider.settings.infiniteLoop && slider.active.index === 0) {
1833
- return
1834
  }
1835
- var pagerIndex = parseInt(slider.active.index) - 1
1836
- el.goToSlide(pagerIndex, 'prev')
1837
- }
1838
 
1839
  /**
1840
  * Starts the auto show
@@ -1845,24 +1873,24 @@
1845
  el.startAuto = function (preventControlUpdate) {
1846
  // if an interval already exists, disregard call
1847
  if (slider.interval) {
1848
- return
1849
  }
1850
 
1851
  // create an interval
1852
  slider.interval = setInterval(function () {
1853
  if (slider.settings.autoDirection === 'next') {
1854
- el.goToNextSlide()
1855
  }
1856
  else {
1857
- el.goToPrevSlide()
1858
  }
1859
- }, slider.settings.pause)
1860
 
1861
  // if auto controls are displayed and preventControlUpdate is not true
1862
  if (slider.settings.autoControls && preventControlUpdate !== true) {
1863
- updateAutoControls('stop')
1864
  }
1865
- }
1866
 
1867
  /**
1868
  * Stops the auto show
@@ -1873,31 +1901,31 @@
1873
  el.stopAuto = function (preventControlUpdate) {
1874
  // if no interval exists, disregard call
1875
  if (!slider.interval) {
1876
- return
1877
  }
1878
  // clear the interval
1879
- clearInterval(slider.interval)
1880
- slider.interval = null
1881
  // if auto controls are displayed and preventControlUpdate is not true
1882
  if (slider.settings.autoControls && preventControlUpdate !== true) {
1883
- updateAutoControls('start')
1884
  }
1885
  //clearInterval(el.visibilityInterval);
1886
- }
1887
 
1888
  /**
1889
  * Returns current slide index (zero-based)
1890
  */
1891
  el.getCurrentSlide = function () {
1892
- return slider.active.index
1893
- }
1894
 
1895
  /**
1896
  * Returns current slide element
1897
  */
1898
  el.getCurrentSlideElement = function () {
1899
- return slider.children.eq(slider.active.index)
1900
- }
1901
 
1902
  /**
1903
  * Returns a slide element
@@ -1905,51 +1933,51 @@
1905
  * - The index (zero-based) of the element you want returned.
1906
  */
1907
  el.getSlideElement = function (index) {
1908
- return slider.children.eq(index)
1909
- }
1910
 
1911
  /**
1912
  * Returns number of slides in show
1913
  */
1914
  el.getSlideCount = function () {
1915
- return slider.children.length
1916
- }
1917
 
1918
  /**
1919
  * Return slider.working variable
1920
  */
1921
  el.isWorking = function () {
1922
- return slider.working
1923
- }
1924
 
1925
  /**
1926
  * Update all dynamic slider elements
1927
  */
1928
  el.redrawSlider = function () {
1929
  // resize all children in ratio to new screen size
1930
- slider.children.add(el.find('.wpmslider-clone')).outerWidth(getSlideWidth())
1931
  // adjust the height
1932
- slider.viewport.css('height', getViewportHeight())
1933
  // update the slide position
1934
- setSlidePosition()
1935
  // if active.last was true before the screen resize, we want
1936
  // to keep it last no matter what screen size we end on
1937
  if (slider.active.last) {
1938
- slider.active.index = getPagerQty() - 1
1939
  }
1940
  // if the active index (page) no longer exists due to the resize, simply set the index as last
1941
  if (slider.active.index >= getPagerQty()) {
1942
- slider.active.last = true
1943
  }
1944
  // if a pager is being displayed and a custom pager is not being used, update it
1945
  if (slider.settings.pager && !slider.settings.pagerCustom) {
1946
- populatePager()
1947
- updatePagerActive(slider.active.index)
1948
  }
1949
  if (slider.settings.ariaHidden) {
1950
- applyAriaHiddenAttributes(slider.active.index * getMoveBy())
1951
  }
1952
- }
1953
 
1954
  /**
1955
  * Destroy the current instance of the slider (revert everything back to original state)
@@ -1957,89 +1985,89 @@
1957
  el.destroySlider = function () {
1958
  // don't do anything if slider has already been destroyed
1959
  if (!slider.initialized) {
1960
- return
1961
  }
1962
- slider.initialized = false
1963
- $('.wpmslider-clone', this).remove()
1964
 
1965
  slider.children.each(function () {
1966
  if ($(this).data('origStyle') !== undefined) {
1967
- $(this).attr('style', $(this).data('origStyle'))
1968
  }
1969
  else {
1970
- $(this).removeAttr('style')
1971
  }
1972
- })
1973
 
1974
  if ($(this).data('origStyle') !== undefined) {
1975
- this.attr('style', $(this).data('origStyle'))
1976
  }
1977
  else {
1978
- $(this).removeAttr('style')
1979
  }
1980
 
1981
- $(this).unwrap().unwrap()
1982
 
1983
  if (slider.controls.el) {
1984
- slider.controls.el.remove()
1985
  }
1986
  if (slider.controls.next) {
1987
- slider.controls.next.remove()
1988
  }
1989
  if (slider.controls.prev) {
1990
- slider.controls.prev.remove()
1991
  }
1992
  if (slider.pagerEl && slider.settings.controls && !slider.settings.pagerCustom) {
1993
- slider.pagerEl.remove()
1994
  }
1995
 
1996
- $('.wpmslider-caption', this).remove()
1997
 
1998
  if (slider.controls.autoEl) {
1999
- slider.controls.autoEl.remove()
2000
  }
2001
 
2002
- clearInterval(slider.interval)
2003
- clearInterval(slider.visibilityInterval)
2004
-
2005
  if (slider.settings.responsive) {
2006
- $(window).off('resize', resizeWindow)
2007
  }
2008
 
2009
  if (slider.settings.keyboardEnabled) {
2010
- $(document).off('keydown', keyPress)
2011
  }
2012
 
2013
  //remove self reference in data
2014
- $(this).removeData('strongSlider')
2015
- }
2016
 
2017
  /**
2018
  * Reload the slider (revert all DOM changes, and re-initialize)
2019
  */
2020
  el.reloadSlider = function (settings) {
2021
  if (settings !== undefined) {
2022
- options = settings
2023
  }
2024
- el.destroySlider()
2025
- init()
2026
  // Store reference to self in order to access public functions later
2027
- $(el).data('strongSlider', this)
2028
- }
2029
 
2030
  // Fire it up!
2031
- init()
2032
 
2033
  // Store reference to self in order to access public functions later
2034
- $(el).data('strongSlider', this)
2035
 
2036
  // Set initialized flag on container
2037
- viewEl.attr('data-state', 'init')
2038
 
2039
- if (slider.debug) console.log(slider.logAs, 'viewport', verge.viewportW(), 'x', verge.viewportH())
2040
 
2041
  // returns the current jQuery object
2042
- return this
2043
- }
2044
 
2045
- })(jQuery)
1
  /*!
2
  * jQuery Strong Slider Plugin
3
+ * Version 2.1
4
  *
5
  * Copyright (c) 2017 Chris Dillon
6
  * Released under the MIT license
23
  debug: false,
24
  logAs: 'strongSlider',
25
  compat: {
26
+ lazyload: {
27
+ active: false,
28
+ classes: {}
29
+ }
30
  },
31
 
32
  // GENERAL
103
 
104
  // CALLBACKS
105
  onSliderLoad: function () {
106
+ return true;
107
  },
108
  onSlideBefore: function () {
109
+ return true;
110
  },
111
  onSlideAfter: function () {
112
+ return true;
113
  },
114
  onSlideNext: function () {
115
+ return true;
116
  },
117
  onSlidePrev: function () {
118
+ return true;
119
  },
120
  onSliderResize: function () {
121
+ return true;
122
  }
123
+ };
124
 
125
  $.fn.strongSlider = function (options) {
126
 
127
  if (this.length === 0) {
128
+ return this;
129
  }
130
 
131
  // create a namespace to be used throughout the plugin
132
  var slider = {},
133
  // set a reference to our slider element
134
  viewEl = this,
135
+ el = this.find('.wpmslider-content');
136
 
137
  // Return if slider is already initialized
138
  if ($(el).data('strongSlider')) {
139
+ return;
140
  }
141
 
142
  /**
151
  var init = function () {
152
  // Return if slider is already initialized
153
  if ($(el).data('strongSlider')) {
154
+ return;
155
  }
156
 
157
  // timer to check visibility; used to control sliders in hidden tabs
158
+ slider.visibilityInterval = 0;
159
  // slider state
160
+ slider.hidden = false;
161
 
162
  // merge user-supplied options with the defaults
163
+ var sliderVar = viewEl.data('slider-var');
164
+ var config = {};
165
 
166
+ if (typeof(window[sliderVar]) !== 'undefined') {
167
+ config = window[sliderVar].config;
168
  }
169
 
170
+ slider.settings = $.extend({}, defaults, config, options);
171
+ slider.debug = slider.settings.debug;
172
+ slider.logAs = slider.settings.logAs;
173
+ if (slider.debug) console.log(slider.logAs, 'slider.settings', slider.settings);
174
 
175
  // parse slideWidth setting
176
+ slider.settings.slideWidth = parseInt(slider.settings.slideWidth);
177
 
178
  // store the original children
179
+ slider.children = el.children(slider.settings.slideSelector);
180
 
181
  // check if actual number of slides is less than minSlides / maxSlides
182
  if (slider.children.length < slider.settings.minSlides) {
183
+ slider.settings.minSlides = slider.children.length;
184
  }
185
  if (slider.children.length < slider.settings.maxSlides) {
186
+ slider.settings.maxSlides = slider.children.length;
187
  }
188
 
189
  // if random start, set the startSlide setting to random number
190
  if (slider.settings.randomStart) {
191
+ slider.settings.startSlide = Math.floor(Math.random() * slider.children.length);
192
  }
193
 
194
  // store active slide information
195
+ slider.active = {index: slider.settings.startSlide};
196
 
197
  // store if the slider is in carousel mode (displaying / moving multiple slides)
198
+ slider.carousel = slider.settings.minSlides > 1 || slider.settings.maxSlides > 1;
199
 
200
  // if carousel, force preloadImages = 'all'
201
  if (slider.carousel) {
202
+ slider.settings.preloadImages = 'all';
203
  }
204
 
205
  // calculate the min / max width thresholds based on min / max number of slides
206
  // used to setup and update carousel slides dimensions
207
+ slider.minThreshold = (slider.settings.minSlides * slider.settings.slideWidth) + ((slider.settings.minSlides - 1) * slider.settings.slideMargin);
208
+ slider.maxThreshold = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin);
209
 
210
  // store the current state of the slider (if currently animating, working is true)
211
+ slider.working = false;
212
 
213
  // initialize the controls object
214
+ slider.controls = {};
215
 
216
  // initialize an auto interval
217
  // no interval = is paused or waiting for user to start
218
+ slider.interval = null;
219
 
220
  // determine which property to use for transitions
221
+ slider.animProp = slider.settings.mode === 'vertical' ? 'top' : 'left';
222
 
223
  // determine if hardware acceleration can be used
224
  slider.usingCSS = slider.settings.useCSS && slider.settings.mode !== 'fade' && (function () {
225
  // create our test div element
226
+ var div = document.createElement('div');
227
  // css transition properties
228
+ var props = ['WebkitPerspective', 'MozPerspective', 'OPerspective', 'msPerspective'];
229
 
230
  // test for each property
231
  for (var i = 0; i < props.length; i++) {
232
  if (div.style[props[i]] !== undefined) {
233
+ slider.cssPrefix = props[i].replace('Perspective', '').toLowerCase();
234
+ slider.animProp = '-' + slider.cssPrefix + '-transform';
235
+ return true;
236
  }
237
  }
238
+ return false;
239
+ }());
240
 
241
  // if vertical mode always make maxSlides and minSlides equal
242
  if (slider.settings.mode === 'vertical') {
243
+ slider.settings.maxSlides = slider.settings.minSlides;
244
  }
245
  // save original style data
246
+ el.data('origStyle', el.attr('style'));
247
  el.children(slider.settings.slideSelector).each(function () {
248
+ $(this).data('origStyle', $(this).attr('style'));
249
+ });
250
 
251
  // Bail if no slides
252
  if (!el.getSlideCount()) {
253
+ return;
254
  }
255
 
256
  // Wait for images loaded
257
  if (slider.settings.imagesLoaded) {
258
  viewEl.imagesLoaded(function () {
259
+ initVisibilityCheck();
260
+ });
261
  }
262
  else {
263
+ initVisibilityCheck();
264
  }
265
 
266
+ };
267
 
268
  /**
269
  * Primary
271
  * @returns {boolean}
272
  */
273
  var reallyVisible = function () {
274
+ return (viewEl.is(':visible') && viewEl.css('visibility') !== 'hidden');
275
+ };
276
 
277
  /**
278
  * Secondary
280
  * @returns {boolean}
281
  */
282
  var compatCheck = function () {
283
+ if (slider.settings.compat.lazyload) {
284
+
285
+ var inProgress = false;
286
+ for (var i = 0, len = slider.settings.compat.lazyload.classes.length; i < len; i++) {
287
+
288
+ var startClass = slider.settings.compat.lazyload.classes[i].start;
289
+ var finishClass = slider.settings.compat.lazyload.classes[i].finish;
290
+
291
+ if (startClass && finishClass) {
292
+ if (viewEl.find('img.' + startClass).length && !viewEl.find('img.' + finishClass).length) {
293
+ inProgress = true;
294
+ }
295
+ } else if (startClass) {
296
+ if (viewEl.find('img.' + startClass).length) {
297
+ inProgress = true;
298
+ }
299
+ } else if (finishClass) {
300
+ if (!viewEl.find('img.' + finishClass).length) {
301
+ inProgress = true;
302
+ }
303
+ }
304
+
305
+ }
306
+
307
+ if (inProgress) {
308
+ if (slider.debug) console.log(slider.logAs, 'lazy loading...');
309
+ return false;
310
  }
311
+
312
  }
313
+
314
+ if (slider.debug) console.log(slider.logAs, 'compat check complete');
315
+ return true;
316
+ };
317
 
318
  /**
319
  * Check visibility and lazy load status.
320
  */
321
  var initVisibilityCheck = function () {
322
  if (reallyVisible() && compatCheck()) {
323
+ clearInterval(slider.visibilityInterval);
324
+ setup();
325
  }
326
  else {
327
  if (slider.visibilityInterval === 0) {
328
+ slider.visibilityInterval = setInterval(initVisibilityCheck, 1000 * 4);
329
  }
330
  }
331
+ };
332
 
333
  /**
334
  * Performs all DOM and CSS modifications
335
  */
336
  var setup = function () {
337
  // set the default preload selector (visible)
338
+ var preloadSelector = slider.children.eq(slider.settings.startSlide);
339
 
340
  // wrap el in a wrapper
341
+ el.wrap('<div class="' + slider.settings.wrapperClass + '"><div class="wpmslider-viewport"></div></div>');
342
 
343
  // store a namespace reference to .wpmslider-viewport
344
+ slider.viewport = el.parent();
345
 
346
  // add aria-live if the setting is enabled
347
  if (slider.settings.ariaLive) {
348
+ slider.viewport.attr('aria-live', 'polite');
349
  }
350
 
351
  // add a loading div to display while images are loading
352
+ slider.loader = $('<div class="wpmslider-loading" />');
353
+ slider.viewport.prepend(slider.loader);
354
 
355
  // set el to a massive width, to hold any needed slides
356
  // also strip any margin and padding from el
357
  el.css({
358
  width: slider.settings.mode === 'horizontal' ? (slider.children.length * 1000 + 215) + '%' : 'auto',
359
  position: 'relative'
360
+ });
361
 
362
  // if using CSS, add the easing property
363
  if (slider.usingCSS && slider.settings.easing) {
364
+ el.css('-' + slider.cssPrefix + '-transition-timing-function', slider.settings.easing);
365
  // if not using CSS and no easing value was supplied, use the default JS animation easing (swing)
366
  }
367
  else if (!slider.settings.easing) {
368
+ slider.settings.easing = 'swing';
369
  }
370
 
371
  // make modifications to the viewport (.wpmslider-viewport)
373
  width: '100%',
374
  overflow: 'hidden',
375
  position: 'relative'
376
+ });
377
 
378
  slider.viewport.parent().css({
379
  maxWidth: getViewportMaxWidth()
380
+ });
381
 
382
  // make modification to the wrapper (.wpmslider-wrapper)
383
  if (!slider.settings.pager && !slider.settings.controls) {
384
  slider.viewport.parent().css({
385
  margin: '0 auto 0px'
386
+ });
387
  }
388
 
389
  // apply css to all slider children
391
  float: slider.settings.mode === 'horizontal' ? 'left' : 'none',
392
  // display: 'unset', // not working in Chrome
393
  position: 'relative'
394
+ });
395
 
396
  // apply the calculated width after the float is applied to prevent scrollbar interference
397
+ slider.children.css('width', getSlideWidth());
398
 
399
  // if slideMargin is supplied, add the css
400
  if (slider.settings.mode === 'horizontal' && slider.settings.slideMargin > 0) {
401
+ slider.children.css('marginRight', slider.settings.slideMargin);
402
  }
403
  if (slider.settings.mode === 'vertical' && slider.settings.slideMargin > 0) {
404
+ slider.children.css('marginBottom', slider.settings.slideMargin);
405
  }
406
 
407
  // if "fade" mode, add positioning and z-index CSS
410
  position: 'absolute',
411
  zIndex: 0,
412
  display: 'none'
413
+ });
414
  // prepare the z-index on the showing element
415
+ slider.children.eq(slider.settings.startSlide).css({zIndex: slider.settings.slideZIndex, display: 'block'});
416
  }
417
  else {
418
  slider.children.css({
419
  display: 'block'
420
+ });
421
  }
422
 
423
  // create an element to contain all slider controls (pager, start / stop, etc)
424
+ slider.controls.el = $('<div class="wpmslider-controls" />');
425
 
426
  // if captions are requested, add them
427
  if (slider.settings.captions) {
428
+ appendCaptions();
429
  }
430
 
431
  // check if startSlide is last slide
432
+ slider.active.last = slider.settings.startSlide === getPagerQty() - 1;
433
 
434
  if (slider.settings.preloadImages === 'all') {
435
+ preloadSelector = slider.children;
436
  }
437
 
438
  // [ LEFT ]
439
  // if controls are requested, add them
440
  if (slider.settings.controls) {
441
+ appendControlPrev();
442
  }
443
 
444
  // [ MIDDLE ]
445
  // if auto is true, and auto controls are requested, add them
446
  if (slider.settings.auto && slider.settings.autoControls) {
447
+ appendControlsAuto();
448
  }
449
 
450
  // if pager is requested, add it
451
  if (slider.settings.pager) {
452
+ appendPager();
453
  }
454
 
455
  // [ RIGHT ]
456
  if (slider.settings.controls) {
457
+ appendControlNext();
458
  }
459
 
460
  // if any control option is requested, add the controls wrapper
461
  if (slider.settings.controls || slider.settings.autoControls || slider.settings.pager) {
462
+ slider.viewport.after(slider.controls.el);
463
  }
464
 
465
+ start();
466
+ };
467
 
468
  /**
469
  * Start the slider
474
  if (slider.settings.infiniteLoop && slider.settings.mode !== 'fade') {
475
 
476
  // slide is always 1 if not carousel mode
477
+ var slice = slider.settings.mode === 'vertical' ? slider.settings.minSlides : slider.settings.maxSlides;
478
 
479
+ var sliceAppend = slider.children.slice(0, slice).clone(true).addClass('wpmslider-clone');
480
 
481
+ var slicePrepend = slider.children.slice(-slice).clone(true).addClass('wpmslider-clone');
482
 
483
  if (slider.settings.ariaHidden) {
484
+ sliceAppend.attr('aria-hidden', true);
485
+ slicePrepend.attr('aria-hidden', true);
486
  }
487
 
488
+ el.append(sliceAppend).prepend(slicePrepend);
489
  }
490
 
491
  // remove the loading DOM element
492
+ slider.loader.remove();
493
 
494
  // set the left / top position of "el"
495
+ setSlidePosition();
496
 
497
  // if "vertical" mode, always use adaptiveHeight to prevent odd behavior
498
  if (slider.settings.mode === 'vertical') {
499
+ slider.settings.adaptiveHeight = true;
500
  }
501
 
502
  // set the viewport height
503
+ slider.viewport.height(getViewportHeight());
504
 
505
  // if stretch, set t-slide height to 100%
506
  if (slider.settings.stretch) {
507
+ setSlideHeight();
508
  }
509
 
510
  // make sure everything is positioned just right (same as a window resize)
511
+ el.redrawSlider();
512
 
513
  // onSliderLoad callback
514
+ slider.settings.onSliderLoad.call(el, slider.active.index);
515
 
516
  // slider has been fully initialized
517
+ slider.initialized = true;
518
+ slider.visibilityInterval = setInterval(visibilityCheck, 500);
519
 
520
  if (slider.settings.responsive) {
521
+ attachListeners();
522
  }
523
 
524
  // if auto is true and has more than 1 page, start the show
525
  if (slider.settings.auto
526
  && slider.settings.autoStart
527
  && (getPagerQty() > 1 || slider.settings.autoSlideForOnePage)) {
528
+ initAuto();
529
  }
530
  // throw new Error("STOP");
531
 
532
  // if pager is requested, make the appropriate pager link active
533
  if (slider.settings.pager) {
534
+ updatePagerActive(slider.settings.startSlide);
535
  }
536
  // check for any updates to the controls (like hideControlOnEnd updates)
537
  if (slider.settings.controls) {
538
+ updateDirectionControls();
539
  }
540
  // if touchEnabled is true, setup the touch events
541
  if (slider.settings.touchEnabled) {
542
+ initTouch();
543
  }
544
  // if keyboardEnabled is true, setup the keyboard events
545
  if (slider.settings.keyboardEnabled) {
546
+ $(document).keydown(keyPress);
547
  }
548
+ };
549
 
550
  /**
551
  * ==============================================================
574
  */
575
  var attachListeners = function () {
576
 
577
+ window.addEventListener('resize', updateLayout, false);
578
+ window.addEventListener('orientationchange', updateLayout, false);
579
 
580
  // Test this with dev console closed
581
  // (or click in the document once to establish focus).
582
  window.addEventListener('blur', function () {
583
+ pauseEvent('blur');
584
+ });
585
 
586
  window.addEventListener('focus', function () {
587
+ playEvent('blur');
588
+ });
589
 
590
+ };
591
 
592
  // Debounced resize event.
593
+ var updateLayout = _.debounce(function () { resizeWindow(); }, 250);
594
 
595
  // General visibility check.
596
  var visibilityCheck = function () {
597
  if (!slider.settings.auto) {
598
+ return;
599
  }
600
 
601
  if (!reallyVisible()) {
602
+ pauseEvent('hide');
603
  }
604
  else {
605
+ playEvent('hide');
606
  }
607
 
608
  if (!verge.inViewport(el)) {
609
+ pauseEvent('scroll');
610
  }
611
  else {
612
+ playEvent('scroll');
613
  }
614
+ };
615
 
616
  var pauseEvent = function (action) {
617
  // if the auto show is currently playing (has an active interval)
618
  if (slider.interval) {
619
  // stop the auto show and pass true argument which will prevent control update
620
+ el.stopAuto(true);
621
  // create a new autoPaused value which will be used by the corresponding event
622
+ slider.autoPaused = action;
623
+ if (slider.debug) console.log(slider.logAs, 'pause', action);
624
  }
625
+ };
626
 
627
  var playEvent = function (action) {
628
  // if the autoPaused value was created by the prior event
629
  if (slider.autoPaused === action) {
630
  // start the auto show and pass true argument which will prevent control update
631
+ el.startAuto(true);
632
  // reset the autoPaused value
633
+ slider.autoPaused = null;
634
+ if (slider.debug) console.log(slider.logAs, 'play', action);
635
  }
636
+ };
637
 
638
  var setSlideHeight = function () {
639
  var heights = slider.children.map(function () {
640
+ return jQuery(this).actual('outerHeight');
641
+ }).get();
642
 
643
+ var maxHeight = arrayMax(heights);
644
+ slider.children.height(maxHeight);
645
+ };
646
 
647
  // Function to get the max value in array
648
  var arrayMax = function (array) {
649
+ return Math.max.apply(Math, array);
650
+ };
651
 
652
  /**
653
  * Returns the calculated height of the SLIDER viewport (not browser viewport),
655
  */
656
  var getViewportHeight = function () {
657
 
658
+ var height = 0;
659
 
660
  // first determine which children (slides) should be used in our height calculation
661
+ var children = $();
662
 
663
  // if mode is not "vertical" and adaptiveHeight is false, include all children
664
  if (slider.settings.mode !== 'vertical' && !slider.settings.adaptiveHeight) {
665
 
666
+ children = slider.children;
667
 
668
  }
669
  else {
671
  // if not carousel, return the single active child
672
  if (!slider.carousel) {
673
 
674
+ children = slider.children.eq(slider.active.index);
675
  // if carousel, return a slice of children
676
 
677
  }
678
  else {
679
 
680
  // get the individual slide index
681
+ var currentIndex = slider.settings.moveSlides === 1 ? slider.active.index : slider.active.index * getMoveBy();
682
 
683
  // add the current slide to the children
684
+ children = slider.children.eq(currentIndex);
685
 
686
  // cycle through the remaining "showing" slides
687
  for (var i = 1; i <= slider.settings.maxSlides - 1; i++) {
688
 
689
  // if looped back to the start
690
  if (currentIndex + i >= slider.children.length) {
691
+ children = children.add(slider.children.eq(i - 1));
692
  }
693
  else {
694
+ children = children.add(slider.children.eq(currentIndex + i));
695
  }
696
 
697
  }
704
  if (slider.settings.mode === 'vertical') {
705
 
706
  children.each(function (index) {
707
+ height += $(this).outerHeight();
708
+ });
709
 
710
  // add user-supplied margins
711
  if (slider.settings.slideMargin > 0) {
712
+ height += slider.settings.slideMargin * (slider.settings.minSlides - 1);
713
  }
714
 
715
  }
717
 
718
  // if not "vertical" mode, calculate the max height of the children
719
  height = Math.max.apply(Math, children.map(function () {
720
+ return $(this).outerHeight(false);
721
+ }).get());
722
 
723
  }
724
 
725
  if (slider.viewport.css('box-sizing') === 'border-box') {
726
  height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom')) +
727
+ parseFloat(slider.viewport.css('border-top-width')) + parseFloat(slider.viewport.css('border-bottom-width'));
728
  }
729
  else if (slider.viewport.css('box-sizing') === 'padding-box') {
730
+ height += parseFloat(slider.viewport.css('padding-top')) + parseFloat(slider.viewport.css('padding-bottom'));
731
  }
732
 
733
+ return height;
734
+ };
735
 
736
  /**
737
  * Returns the calculated width to be used for the outer wrapper / SLIDER viewport
738
  */
739
  var getViewportMaxWidth = function () {
740
+ var width = '100%';
741
  if (slider.settings.slideWidth > 0) {
742
  if (slider.settings.mode === 'horizontal') {
743
+ width = (slider.settings.maxSlides * slider.settings.slideWidth) + ((slider.settings.maxSlides - 1) * slider.settings.slideMargin);
744
  }
745
  else {
746
+ width = slider.settings.slideWidth;
747
  }
748
  }
749
+ return width;
750
+ };
751
 
752
  /**
753
  * Returns the calculated width to be applied to each slide
755
  var getSlideWidth = function () {
756
 
757
  var newElWidth = slider.settings.slideWidth, // start with any user-supplied slide width
758
+ wrapWidth = slider.viewport.width(); // get the current viewport width
759
 
760
  // if slide width was not supplied, or is larger than the viewport use the viewport width
761
  if (slider.settings.slideWidth === 0 ||
762
 
763
  (slider.settings.slideWidth > wrapWidth && !slider.carousel) ||
764
  slider.settings.mode === 'vertical') {
765
+ newElWidth = wrapWidth;
766
 
767
  }
768
  else if (slider.settings.maxSlides > 1 && slider.settings.mode === 'horizontal') {
769
 
770
  // if carousel, use the thresholds to determine the width
771
  if (wrapWidth > slider.maxThreshold) {
772
+ return newElWidth;
773
  }
774
  else if (wrapWidth < slider.minThreshold) {
775
+ newElWidth = (wrapWidth - (slider.settings.slideMargin * (slider.settings.minSlides - 1))) / slider.settings.minSlides;
776
  }
777
  else if (slider.settings.shrinkItems) {
778
+ newElWidth = Math.floor((wrapWidth + slider.settings.slideMargin) / (Math.ceil((wrapWidth + slider.settings.slideMargin) / (newElWidth + slider.settings.slideMargin))) - slider.settings.slideMargin);
779
  }
780
 
781
  }
782
+ return newElWidth;
783
+ };
784
 
785
  /**
786
  * Returns the number of slides currently visible in the viewport (includes partially visible slides)
787
  */
788
  var getNumberSlidesShowing = function () {
789
  var slidesShowing = 1,
790
+ childWidth = null;
791
  if (slider.settings.mode === 'horizontal' && slider.settings.slideWidth > 0) {
792
  // if viewport is smaller than minThreshold, return minSlides
793
  if (slider.viewport.width() < slider.minThreshold) {
794
+ slidesShowing = slider.settings.minSlides;
795
  }
796
  // if viewport is larger than maxThreshold, return maxSlides
797
  else if (slider.viewport.width() > slider.maxThreshold) {
798
+ slidesShowing = slider.settings.maxSlides;
799
  }
800
  // if viewport is between min / max thresholds, divide viewport width by first child width
801
  else {
802
+ childWidth = slider.children.first().width() + slider.settings.slideMargin;
803
  slidesShowing = Math.floor((slider.viewport.width() +
804
+ slider.settings.slideMargin) / childWidth);
805
  }
806
  }
807
  // if "vertical" mode, slides showing will always be minSlides
808
  else if (slider.settings.mode === 'vertical') {
809
+ slidesShowing = slider.settings.minSlides;
810
  }
811
+ return slidesShowing;
812
+ };
813
 
814
  /**
815
  * Returns the number of pages (one full viewport of slides is one "page")
817
  var getPagerQty = function () {
818
  var pagerQty = 0,
819
  breakPoint = 0,
820
+ counter = 0;
821
  // if moveSlides is specified by the user
822
  if (slider.settings.moveSlides > 0) {
823
  if (slider.settings.infiniteLoop) {
824
+ pagerQty = Math.ceil(slider.children.length / getMoveBy());
825
  }
826
  else {
827
  // when breakpoint goes above children length, counter is the number of pages
828
  while (breakPoint < slider.children.length) {
829
+ ++pagerQty;
830
+ breakPoint = counter + getNumberSlidesShowing();
831
+ counter += slider.settings.moveSlides <= getNumberSlidesShowing() ? slider.settings.moveSlides : getNumberSlidesShowing();
832
  }
833
  }
834
  }
835
  // if moveSlides is 0 (auto) divide children length by sides showing, then round up
836
  else {
837
+ pagerQty = Math.ceil(slider.children.length / getNumberSlidesShowing());
838
  }
839
+ return pagerQty;
840
+ };
841
 
842
  /**
843
  * Returns the number of individual slides by which to shift the slider
845
  var getMoveBy = function () {
846
  // if moveSlides was set by the user and moveSlides is less than number of slides showing
847
  if (slider.settings.moveSlides > 0 && slider.settings.moveSlides <= getNumberSlidesShowing()) {
848
+ return slider.settings.moveSlides;
849
  }
850
  // if moveSlides is 0 (auto)
851
+ return getNumberSlidesShowing();
852
+ };
853
 
854
  /**
855
  * Sets the slider's (el) left or top position
856
  */
857
  var setSlidePosition = function () {
858
+ var position, lastChild, lastShowingIndex;
859
 
860
  // if last slide, not infinite loop, and number of children is larger than specified maxSlides
861
  if (slider.children.length > slider.settings.maxSlides && slider.active.last && !slider.settings.infiniteLoop) {
862
 
863
  if (slider.settings.mode === 'horizontal') {
864
  // get the last child's position
865
+ lastChild = slider.children.last();
866
+ position = lastChild.position();
867
  // set the left position
868
+ setPositionProperty(-(position.left - (slider.viewport.width() - lastChild.outerWidth())), 'reset', 0);
869
  }
870
  else if (slider.settings.mode === 'vertical') {
871
  // get the last showing index's position
872
+ lastShowingIndex = slider.children.length - slider.settings.minSlides;
873
+ position = slider.children.eq(lastShowingIndex).position();
874
  // set the top position
875
+ setPositionProperty(-position.top, 'reset', 0);
876
  }
877
 
878
  }
880
  else {
881
 
882
  // get the position of the first showing slide
883
+ position = slider.children.eq(slider.active.index * getMoveBy()).position();
884
 
885
  // check for last slide
886
  if (slider.active.index === getPagerQty() - 1) {
887
+ slider.active.last = true;
888
  }
889
 
890
  // set the respective position
891
  if (position !== undefined) {
892
  if (slider.settings.mode === 'horizontal') {
893
+ setPositionProperty(-position.left, 'reset', 0);
894
  }
895
  else if (slider.settings.mode === 'vertical') {
896
+ setPositionProperty(-position.top, 'reset', 0);
897
  }
898
  else if (slider.settings.mode === 'none') {
899
+ setPositionProperty(-position.top, 'reset', 0);
900
  }
901
  }
902
 
903
  }
904
+ };
905
 
906
  /**
907
  * Sets the el's animating property position (which in turn will sometimes animate el).
920
  * - an optional parameter containing any variables that need to be passed in
921
  */
922
  var setPositionProperty = function (value, type, duration, params) {
923
+ var animateObj, propValue;
924
  // use CSS transform
925
  if (slider.usingCSS) {
926
 
928
  // propValue = slider.settings.mode === 'vertical' ? 'translate3d(0, ' + value + 'px, 0)' : 'translate3d(' + value + 'px, 0, 0)'
929
  if (slider.settings.mode === 'vertical') {
930
  //propValue = 'translate3d(0, ' + value + 'px, 0)'
931
+ propValue = 'translateY(' + value + 'px)';
932
  }
933
  else if (slider.settings.mode === 'horizontal') {
934
  // propValue = 'translate3d(' + value + 'px, 0, 0)'
935
+ propValue = 'translateX(' + value + 'px';
936
  }
937
  else if (slider.settings.mode === 'none') {
938
  // propValue = 'translate3d(0, ' + value + 'px, 0)'
939
+ propValue = 'translateY(' + value + 'px)';
940
+ duration = 0;
941
  }
942
 
943
  // add the CSS transition-duration
944
+ el.css('-' + slider.cssPrefix + '-transition-duration', duration / 1000 + 's');
945
 
946
  if (type === 'slide') {
947
 
948
  // set the property value
949
+ el.css(slider.animProp, propValue);
950
  if (duration !== 0) {
951
  // bind a callback method - executes when CSS transition completes
952
  el.on('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd', function (e) {
953
  //make sure it's the correct one
954
  if (!$(e.target).is(el)) {
955
+ return;
956
  }
957
  // unbind the callback
958
+ el.off('transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd');
959
+ updateAfterSlideTransition();
960
+ });
961
  }
962
  else {
963
+ updateAfterSlideTransition();
964
  }
965
 
966
  }
967
  else if (type === 'reset') {
968
 
969
+ el.css(slider.animProp, propValue);
970
 
971
  }
972
 
974
  // use JS animate
975
  else {
976
 
977
+ animateObj = {};
978
+ animateObj[slider.animProp] = value;
979
  if (type === 'slide') {
980
  el.animate(animateObj, duration, slider.settings.easing, function () {
981
+ updateAfterSlideTransition();
982
+ });
983
  }
984
  else if (type === 'reset') {
985
+ el.css(slider.animProp, value);
986
  }
987
 
988
  }
989
+ };
990
 
991
  /**
992
  * Populates the pager with proper amount of pages
994
  var populatePager = function () {
995
  var pagerHtml = '',
996
  linkContent = '',
997
+ pagerQty = getPagerQty();
998
 
999
  // loop through each pager item
1000
  for (var i = 0; i < pagerQty; i++) {
1001
+ linkContent = '';
1002
 
1003
  if (slider.settings.buildPager) {
1004
  // if using icons, use no link text
1005
  if (slider.settings.buildPager === 'icons') {
1006
+ linkContent = '';
1007
  }
1008
  // if a buildPager function is supplied, use it to get pager link value, else use index + 1
1009
  if ($.isFunction(slider.settings.buildPager) || slider.settings.pagerCustom) {
1010
+ linkContent = slider.settings.buildPager(i);
1011
  }
1012
+ slider.pagerEl.addClass('wpmslider-custom-pager');
1013
  }
1014
  else {
1015
+ linkContent = i + 1;
1016
+ slider.pagerEl.addClass('wpmslider-default-pager');
1017
  }
1018
 
1019
  // add the markup to the string
1020
+ pagerHtml += '<div class="wpmslider-pager-item"><a href="" data-slide-index="' + i + '" class="wpmslider-pager-link">' + linkContent + '</a></div>';
1021
  }
1022
 
1023
  // populate the pager element with pager links
1024
+ slider.pagerEl.html(pagerHtml);
1025
+ };
1026
 
1027
  /**
1028
  * Appends the pager to the controls element
1030
  var appendPager = function () {
1031
  if (!slider.settings.pagerCustom) {
1032
  // create the pager DOM element
1033
+ slider.pagerEl = $('<div class="wpmslider-pager" />');
1034
  // if a pager selector was supplied, populate it with the pager
1035
  if (slider.settings.pagerSelector) {
1036
+ $(slider.settings.pagerSelector).html(slider.pagerEl);
1037
  }
1038
  else {
1039
  // if no pager selector was supplied, add it after the wrapper
1040
+ slider.controls.el.addClass('wpmslider-has-pager').append(slider.pagerEl);
1041
  }
1042
  // populate the pager
1043
+ populatePager();
1044
  }
1045
  else {
1046
+ slider.pagerEl = $(slider.settings.pagerCustom);
1047
  }
1048
  // assign the pager click binding
1049
+ slider.pagerEl.on('click touchend', 'a', clickPagerBind);
1050
+ };
1051
 
1052
  /**
1053
  * Appends prev control to the controls element
1054
  */
1055
  var appendControlPrev = function () {
1056
+ slider.controls.prev = $('<a class="wpmslider-prev" href="">' + slider.settings.prevText + '</a>');
1057
 
1058
  // bind click actions to the controls
1059
+ slider.controls.prev.on('click touchend', clickPrevBind);
1060
 
1061
  // if prevSelector was supplied, populate it
1062
  if (slider.settings.prevSelector) {
1063
+ $(slider.settings.prevSelector).append(slider.controls.prev);
1064
  }
1065
 
1066
  // if no custom selectors were supplied
1067
  if (!slider.settings.prevSelector) {
1068
  // add the controls to the DOM
1069
+ slider.controls.directionEl = $('<div class="wpmslider-controls-direction" />');
1070
  // add the control elements to the directionEl
1071
+ slider.controls.directionEl.append(slider.controls.prev);
1072
+ slider.controls.el.addClass('wpmslider-has-controls-direction').append(slider.controls.directionEl);
1073
  }
1074
+ };
1075
 
1076
  /**
1077
  * Appends prev / next controls to the controls element
1078
  */
1079
  var appendControlNext = function () {
1080
+ slider.controls.next = $('<a class="wpmslider-next" href="">' + slider.settings.nextText + '</a>');
1081
 
1082
  // bind click actions to the controls
1083
+ slider.controls.next.on('click touchend', clickNextBind);
1084
 
1085
  // if nextSelector was supplied, populate it
1086
  if (slider.settings.nextSelector) {
1087
+ $(slider.settings.nextSelector).append(slider.controls.next);
1088
  }
1089
 
1090
  // if no custom selectors were supplied
1091
  if (!slider.settings.nextSelector) {
1092
  // add the controls to the DOM
1093
+ slider.controls.directionEl = $('<div class="wpmslider-controls-direction" />');
1094
  // add the control elements to the directionEl
1095
+ slider.controls.directionEl.append(slider.controls.next);
1096
+ slider.controls.el.addClass('wpmslider-has-controls-direction').append(slider.controls.directionEl);
1097
  }
1098
+ };
1099
 
1100
  /**
1101
  * Appends start / stop auto controls to the controls element
1102
  */
1103
  var appendControlsAuto = function () {
1104
+ slider.controls.start = $('<div class="wpmslider-controls-auto-item"><a class="wpmslider-start" href="">' + slider.settings.startText + '</a></div>');
1105
+ slider.controls.stop = $('<div class="wpmslider-controls-auto-item"><a class="wpmslider-stop" href="">' + slider.settings.stopText + '</a></div>');
1106
 
1107
  // add the controls to the DOM
1108
+ slider.controls.autoEl = $('<div class="wpmslider-controls-auto" />');
1109
 
1110
  // bind click actions to the controls
1111
+ slider.controls.autoEl.on('click', '.wpmslider-start', clickStartBind);
1112
+ slider.controls.autoEl.on('click', '.wpmslider-stop', clickStopBind);
1113
 
1114
  // if autoControlsCombine, insert only the "start" control
1115
  if (slider.settings.autoControlsCombine) {
1116
+ slider.controls.autoEl.append(slider.controls.start);
1117
  // if autoControlsCombine is false, insert both controls
1118
  }
1119
  else {
1120
+ slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop);
1121
  }
1122
 
1123
  // if auto controls selector was supplied, populate it with the controls
1124
  if (slider.settings.autoControlsSelector) {
1125
+ $(slider.settings.autoControlsSelector).html(slider.controls.autoEl);
1126
  // if auto controls selector was not supplied, add it after the wrapper
1127
  }
1128
  else {
1129
+ slider.controls.el.addClass('wpmslider-has-controls-auto').append(slider.controls.autoEl);
1130
  }
1131
 
1132
  // update the auto controls
1133
+ updateAutoControls(slider.settings.autoStart ? 'stop' : 'start');
1134
+ };
1135
 
1136
  /**
1137
  * Appends image captions to the DOM
1140
  // cycle through each child
1141
  slider.children.each(function (index) {
1142
  // get the image title attribute
1143
+ var title = $(this).find('img:first').attr('title');
1144
  // append the caption
1145
  if (title !== undefined && ('' + title).length) {
1146
+ $(this).append('<div class="wpmslider-caption"><span>' + title + '</span></div>');
1147
  }
1148
+ });
1149
+ };
1150
 
1151
  /**
1152
  * Click next binding
1155
  * - DOM event object
1156
  */
1157
  var clickNextBind = function (e) {
1158
+ e.preventDefault();
1159
+ e.stopPropagation();
1160
  if (slider.controls.el.hasClass('disabled')) {
1161
+ return;
1162
  }
1163
  // if auto show is running, stop it
1164
  if (slider.settings.auto && slider.settings.stopAutoOnClick) {
1165
+ if (slider.debug) console.log(slider.logAs, 'stop on navigation');
1166
+ el.stopAuto();
1167
  }
1168
+ el.goToNextSlide();
1169
+ };
1170
 
1171
  /**
1172
  * Click prev binding
1175
  * - DOM event object
1176
  */
1177
  var clickPrevBind = function (e) {
1178
+ e.preventDefault();
1179
+ e.stopPropagation();
1180
  if (slider.controls.el.hasClass('disabled')) {
1181
+ return;
1182
  }
1183
  // if auto show is running, stop it
1184
  if (slider.settings.auto && slider.settings.stopAutoOnClick) {
1185
+ if (slider.debug) console.log(slider.logAs, 'stop on navigation');
1186
+ el.stopAuto();
1187
  }
1188
+ el.goToPrevSlide();
1189
+ };
1190
 
1191
  /**
1192
  * Click start binding
1195
  * - DOM event object
1196
  */
1197
  var clickStartBind = function (e) {
1198
+ el.startAuto();
1199
+ e.preventDefault();
1200
+ e.stopPropagation();
1201
+ };
1202
 
1203
  /**
1204
  * Click stop binding
1207
  * - DOM event object
1208
  */
1209
  var clickStopBind = function (e) {
1210
+ el.stopAuto();
1211
+ e.preventDefault();
1212
+ e.stopPropagation();
1213
+ };
1214
 
1215
  /**
1216
  * Click pager binding
1219
  * - DOM event object
1220
  */
1221
  var clickPagerBind = function (e) {
1222
+ var pagerLink, pagerIndex;
1223
+ e.preventDefault();
1224
+ e.stopPropagation();
1225
  if (slider.controls.el.hasClass('disabled')) {
1226
+ return;
1227
  }
1228
  // if auto show is running, stop it
1229
  if (slider.settings.auto && slider.settings.stopAutoOnClick) {
1230
+ if (slider.debug) console.log(slider.logAs, 'stop on navigation');
1231
+ el.stopAuto();
1232
  }
1233
+ pagerLink = $(e.currentTarget);
1234
  if (pagerLink.attr('data-slide-index') !== undefined) {
1235
+ pagerIndex = parseInt(pagerLink.attr('data-slide-index'));
1236
  // if clicked pager link is not active, continue with the goToSlide call
1237
  if (pagerIndex !== slider.active.index) {
1238
+ el.goToSlide(pagerIndex);
1239
  }
1240
  }
1241
+ };
1242
 
1243
  /**
1244
  * Updates the pager links with an active class
1248
  */
1249
  var updatePagerActive = function (slideIndex) {
1250
  // if "short" pager type
1251
+ var len = slider.children.length; // nb of children
1252
  if (slider.settings.pagerType === 'short') {
1253
  if (slider.settings.maxSlides > 1) {
1254
+ len = Math.ceil(slider.children.length / slider.settings.maxSlides);
1255
  }
1256
+ slider.pagerEl.html((slideIndex + 1) + slider.settings.pagerShortSeparator + len);
1257
+ return;
1258
  }
1259
  // remove all pager active classes
1260
+ slider.pagerEl.find('a').removeClass('active');
1261
  // apply the active class for all pagers
1262
  slider.pagerEl.each(function (i, el) {
1263
+ $(el).find('a').eq(slideIndex).addClass('active');
1264
+ });
1265
+ };
1266
 
1267
  /**
1268
  * Performs needed actions after a slide transition
1270
  var updateAfterSlideTransition = function () {
1271
  // if infinite loop is true
1272
  if (slider.settings.infiniteLoop) {
1273
+ var position = '';
1274
  // first slide
1275
  if (slider.active.index === 0) {
1276
  // set the new position
1277
+ position = slider.children.eq(0).position();
1278
  }
1279
  // carousel, last slide
1280
  else if (slider.active.index === getPagerQty() - 1 && slider.carousel) {
1281
+ position = slider.children.eq((getPagerQty() - 1) * getMoveBy()).position();
1282
  }
1283
  // last slide
1284
  else if (slider.active.index === slider.children.length - 1) {
1285
+ position = slider.children.eq(slider.children.length - 1).position();
1286
  }
1287
  if (position) {
1288
  if (slider.settings.mode === 'horizontal') {
1289
+ setPositionProperty(-position.left, 'reset', 0);
1290
  }
1291
  else if (slider.settings.mode === 'vertical') {
1292
+ setPositionProperty(-position.top, 'reset', 0);
1293
  }
1294
  }
1295
  }
1296
  // declare that the transition is complete
1297
+ slider.working = false;
1298
  // onSlideAfter callback
1299
+ slider.settings.onSlideAfter.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index);
1300
+ };
1301
 
1302
  /**
1303
  * Updates the auto controls state (either active, or combined switch)
1308
  var updateAutoControls = function (state) {
1309
  // if autoControlsCombine is true, replace the current control with the new state
1310
  if (slider.settings.autoControlsCombine) {
1311
+ slider.controls.autoEl.html(slider.controls[state]);
1312
  }
1313
  // if autoControlsCombine is false, apply the "active" class to the appropriate control
1314
  else {
1315
+ slider.controls.autoEl.find('a').removeClass('active');
1316
+ slider.controls.autoEl.find('a:not(.wpmslider-' + state + ')').addClass('active');
1317
  }
1318
+ };
1319
 
1320
  /**
1321
  * Updates the direction controls (checks if either should be hidden)
1322
  */
1323
  var updateDirectionControls = function () {
1324
  if (getPagerQty() === 1) {
1325
+ slider.controls.prev.addClass('disabled');
1326
+ slider.controls.next.addClass('disabled');
1327
  }
1328
  else if (!slider.settings.infiniteLoop && slider.settings.hideControlOnEnd) {
1329
  // if first slide
1330
  if (slider.active.index === 0) {
1331
+ slider.controls.prev.addClass('disabled');
1332
+ slider.controls.next.removeClass('disabled');
1333
  }
1334
  // if last slide
1335
  else if (slider.active.index === getPagerQty() - 1) {
1336
+ slider.controls.next.addClass('disabled');
1337
+ slider.controls.prev.removeClass('disabled');
1338
  }
1339
  // if any slide in the middle
1340
  else {
1341
+ slider.controls.prev.removeClass('disabled');
1342
+ slider.controls.next.removeClass('disabled');
1343
  }
1344
  }
1345
+ };
1346
 
1347
  /**
1348
  * Initializes the auto process
1350
  var initAuto = function () {
1351
  // if autoDelay was supplied, launch the auto show using a setTimeout() call
1352
  if (slider.settings.autoDelay > 0) {
1353
+ var timeout = setTimeout(el.startAuto, slider.settings.autoDelay);
1354
  }
1355
  // if autoDelay was not supplied, start the auto show normally
1356
  else {
1357
+ el.startAuto();
1358
  }
1359
 
1360
  // if autoHover is requested
1361
  if (slider.settings.autoHover) {
1362
  // on el hover
1363
  el.hover(function () {
1364
+ pauseEvent('hover');
1365
  }, function () {
1366
+ playEvent('hover');
1367
+ });
1368
  }
1369
+ };
1370
 
1371
  /**
1372
  * Check if el is on screen
1398
  var activeElementTag = document.activeElement.tagName.toLowerCase(),
1399
  tagFilters = 'input|textarea',
1400
  p = new RegExp(activeElementTag, ['i']),
1401
+ result = p.exec(tagFilters);
1402
 
1403
  if (result === null && verge.inViewport(el)) {
1404
  if (e.keyCode === 39) {
1405
+ clickNextBind(e);
1406
+ return false;
1407
  }
1408
  else if (e.keyCode === 37) {
1409
+ clickPrevBind(e);
1410
+ return false;
1411
  }
1412
  }
1413
+ };
1414
 
1415
  /**
1416
  * Initializes touch events
1420
  slider.touch = {
1421
  start: {x: 0, y: 0},
1422
  end: {x: 0, y: 0}
1423
+ };
1424
+ slider.viewport.on('touchstart MSPointerDown pointerdown', onTouchStart);
1425
 
1426
  //for browsers that have implemented pointer events and fire a click after
1427
  //every pointerup regardless of whether pointerup is on same screen location as pointerdown or not
1428
  slider.viewport.on('click', '.wpmslider a', function (e) {
1429
  if (slider.viewport.hasClass('click-disabled')) {
1430
+ e.preventDefault();
1431
+ e.stopPropagation();
1432
+ slider.viewport.removeClass('click-disabled');
1433
  }
1434
+ });
1435
+ };
1436
 
1437
  /**
1438
  * Event handler for "touchstart"
1442
  */
1443
  var onTouchStart = function (e) {
1444
  //disable slider controls while user is interacting with slides to avoid slider freeze that happens on touch devices when a slide swipe happens immediately after interacting with slider controls
1445
+ slider.controls.el.addClass('disabled');
1446
 
1447
  if (slider.working) {
1448
+ e.preventDefault();
1449
+ e.stopPropagation();
1450
+ slider.controls.el.removeClass('disabled');
1451
  }
1452
  else {
1453
  // record the original position when touch starts
1454
+ slider.touch.originalPos = el.position();
1455
  var orig = e.originalEvent,
1456
+ touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig];
1457
  // https://stackoverflow.com/questions/41541121/domexception-failed-to-execute-setpointercapture-on-element-and-releasepoin
1458
+ var chromePointerEvents = typeof PointerEvent === 'function';
1459
  if (chromePointerEvents) { if (orig.pointerId === undefined) { return; } }
1460
  // record the starting touch x, y coordinates
1461
+ slider.touch.start.x = touchPoints[0].pageX;
1462
+ slider.touch.start.y = touchPoints[0].pageY;
1463
 
1464
  if (slider.viewport.get(0).setPointerCapture) {
1465
+ slider.pointerId = orig.pointerId;
1466
+ if (slider.pointerId === 1) {
1467
  slider.viewport.get(0).setPointerCapture(slider.pointerId);
1468
  }
1469
  }
1470
  // bind a "touchmove" event to the viewport
1471
+ slider.viewport.on('touchmove MSPointerMove pointermove', onTouchMove);
1472
  // bind a "touchend" event to the viewport
1473
+ slider.viewport.on('touchend MSPointerUp pointerup', onTouchEnd);
1474
+ slider.viewport.on('MSPointerCancel pointercancel', onPointerCancel);
1475
  }
1476
+ };
1477
 
1478
  /**
1479
  * Cancel Pointer for Windows Phone
1484
  var onPointerCancel = function (e) {
1485
  /* onPointerCancel handler is needed to deal with situations when a touchend
1486
  doesn't fire after a touchstart (this happens on windows phones only) */
1487
+ setPositionProperty(slider.touch.originalPos.left, 'reset', 0);
1488
 
1489
  //remove handlers
1490
+ slider.controls.el.removeClass('disabled');
1491
+ slider.viewport.off('MSPointerCancel pointercancel', onPointerCancel);
1492
+ slider.viewport.off('touchmove MSPointerMove pointermove', onTouchMove);
1493
+ slider.viewport.off('touchend MSPointerUp pointerup', onTouchEnd);
1494
  if (slider.viewport.get(0).releasePointerCapture) {
1495
+ slider.viewport.get(0).releasePointerCapture(slider.pointerId);
1496
  }
1497
+ };
1498
 
1499
  /**
1500
  * Event handler for "touchmove"
1509
  xMovement = Math.abs(touchPoints[0].pageX - slider.touch.start.x),
1510
  yMovement = Math.abs(touchPoints[0].pageY - slider.touch.start.y),
1511
  value = 0,
1512
+ change = 0;
1513
 
1514
  // x axis swipe
1515
  if ((xMovement * 3) > yMovement && slider.settings.preventDefaultSwipeX) {
1516
+ e.preventDefault();
1517
+ e.stopPropagation();
1518
  }
1519
  // y axis swipe
1520
  else if ((yMovement * 3) > xMovement && slider.settings.preventDefaultSwipeY) {
1521
+ e.preventDefault();
1522
+ e.stopPropagation();
1523
  }
1524
  if (slider.settings.mode !== 'fade' && slider.settings.oneToOneTouch) {
1525
  // if horizontal, drag along x axis
1526
  if (slider.settings.mode === 'horizontal') {
1527
+ change = touchPoints[0].pageX - slider.touch.start.x;
1528
+ value = slider.touch.originalPos.left + change;
1529
  // if vertical, drag along y axis
1530
  }
1531
  else {
1532
+ change = touchPoints[0].pageY - slider.touch.start.y;
1533
+ value = slider.touch.originalPos.top + change;
1534
  }
1535
+ setPositionProperty(value, 'reset', 0);
1536
  }
1537
+ };
1538
 
1539
  /**
1540
  * Event handler for "touchend"
1543
  * - DOM event object
1544
  */
1545
  var onTouchEnd = function (e) {
1546
+ slider.viewport.off('touchmove MSPointerMove pointermove', onTouchMove);
1547
  //enable slider controls as soon as user stops interacing with slides
1548
+ slider.controls.el.removeClass('disabled');
1549
  var orig = e.originalEvent,
1550
  touchPoints = (typeof orig.changedTouches !== 'undefined') ? orig.changedTouches : [orig],
1551
  value = 0,
1552
+ distance = 0;
1553
  // record end x, y positions
1554
+ slider.touch.end.x = touchPoints[0].pageX;
1555
+ slider.touch.end.y = touchPoints[0].pageY;
1556
  // if fade mode, check if absolute x distance clears the threshold
1557
  if (slider.settings.mode === 'fade') {
1558
+ distance = Math.abs(slider.touch.start.x - slider.touch.end.x);
1559
  if (distance >= slider.settings.swipeThreshold) {
1560
  if (slider.touch.start.x > slider.touch.end.x) {
1561
+ el.goToNextSlide();
1562
  }
1563
  else {
1564
+ el.goToPrevSlide();
1565
  }
1566
+ el.stopAuto();
1567
  }
1568
  }
1569
  // not fade mode
1570
  else {
1571
  // calculate distance and el's animate property
1572
  if (slider.settings.mode === 'horizontal') {
1573
+ distance = slider.touch.end.x - slider.touch.start.x;
1574
+ value = slider.touch.originalPos.left;
1575
  }
1576
  else {
1577
+ distance = slider.touch.end.y - slider.touch.start.y;
1578
+ value = slider.touch.originalPos.top;
1579
  }
1580
  // if not infinite loop and first / last slide, do not attempt a slide transition
1581
  if (!slider.settings.infiniteLoop && ((slider.active.index === 0 && distance > 0) || (slider.active.last && distance < 0))) {
1582
+ setPositionProperty(value, 'reset', 200);
1583
  }
1584
  else {
1585
  // check if distance clears threshold
1586
  if (Math.abs(distance) >= slider.settings.swipeThreshold) {
1587
  if (distance < 0) {
1588
+ el.goToNextSlide();
1589
  }
1590
  else {
1591
+ el.goToPrevSlide();
1592
  }
1593
+ el.stopAuto();
1594
  }
1595
  else {
1596
  // el.animate(property, 200);
1597
+ setPositionProperty(value, 'reset', 200);
1598
  }
1599
  }
1600
  }
1601
+ slider.viewport.off('touchend MSPointerUp pointerup', onTouchEnd);
1602
  if (slider.viewport.get(0).releasePointerCapture) {
1603
+ slider.viewport.get(0).releasePointerCapture(slider.pointerId);
1604
  }
1605
+ };
1606
 
1607
  /**
1608
  * Window resize event callback
1610
  var resizeWindow = function (e) {
1611
  // don't do anything if slider isn't initialized.
1612
  if (!slider.initialized) {
1613
+ return;
1614
  }
1615
  // Delay if slider working.
1616
  if (slider.working) {
1617
+ window.setTimeout(resizeWindow, 10);
1618
  }
1619
  else {
1620
  // update all dynamic elements
1621
+ el.redrawSlider();
1622
  // Call user resize handler
1623
+ slider.settings.onSliderResize.call(el, slider.active.index);
1624
  }
1625
+ };
1626
 
1627
  /**
1628
  * Adds an aria-hidden=true attribute to each element
1631
  * - the first visible element's index
1632
  */
1633
  var applyAriaHiddenAttributes = function (startVisibleIndex) {
1634
+ var numberOfSlidesShowing = getNumberSlidesShowing();
1635
  // only apply attributes if the setting is enabled
1636
  if (slider.settings.ariaHidden) {
1637
  // add aria-hidden=true to all elements
1638
+ slider.children.attr('aria-hidden', 'true');
1639
  // get the visible elements and change to aria-hidden=false
1640
+ slider.children.slice(startVisibleIndex, startVisibleIndex + numberOfSlidesShowing).attr('aria-hidden', 'false');
1641
  }
1642
+ };
1643
 
1644
  /**
1645
  * Returns index according to present page range
1650
  var setSlideIndex = function (slideIndex) {
1651
  if (slideIndex < 0) {
1652
  if (slider.settings.infiniteLoop) {
1653
+ return getPagerQty() - 1;
1654
  }
1655
  else {
1656
  //we don't go to undefined slides
1657
+ return slider.active.index;
1658
  }
1659
  }
1660
  // if slideIndex is greater than children length, set active index to 0 (this happens during infinite loop)
1661
  else if (slideIndex >= getPagerQty()) {
1662
  if (slider.settings.infiniteLoop) {
1663
+ return 0;
1664
  }
1665
  else {
1666
  //we don't move to undefined pages
1667
+ return slider.active.index;
1668
  }
1669
  }
1670
  // set active index to requested slide
1671
  else {
1672
+ return slideIndex;
1673
  }
1674
+ };
1675
 
1676
  /**
1677
  * ===================================================================================
1695
  moveBy = 0,
1696
  position = {left: 0, top: 0},
1697
  lastChild = null,
1698
+ lastShowingIndex, eq, value, requestEl;
1699
  // store the old index
1700
+ slider.oldIndex = slider.active.index;
1701
  //set new index
1702
+ slider.active.index = setSlideIndex(slideIndex);
1703
 
1704
  // if plugin is currently in motion, ignore request
1705
  if (slider.working || slider.active.index === slider.oldIndex) {
1706
+ return;
1707
  }
1708
  // declare that plugin is in motion
1709
+ slider.working = true;
1710
 
1711
+ performTransition = slider.settings.onSlideBefore.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index);
1712
 
1713
  // If transitions canceled, reset and return
1714
  if (typeof (performTransition) !== 'undefined' && !performTransition) {
1715
+ slider.active.index = slider.oldIndex; // restore old index
1716
+ slider.working = false; // is not in motion
1717
+ return;
1718
  }
1719
 
1720
  if (direction === 'next') {
1721
  // Prevent canceling in future functions or lack thereof from negating previous commands to cancel
1722
  if (!slider.settings.onSlideNext.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)) {
1723
+ performTransition = false;
1724
  }
1725
  }
1726
  else if (direction === 'prev') {
1727
  // Prevent canceling in future functions or lack thereof from negating previous commands to cancel
1728
  if (!slider.settings.onSlidePrev.call(el, slider.children.eq(slider.active.index), slider.oldIndex, slider.active.index)) {
1729
+ performTransition = false;
1730
  }
1731
  }
1732
 
1733
  // check if last slide
1734
+ slider.active.last = slider.active.index >= getPagerQty() - 1;
1735
 
1736
  // update the pager with active class
1737
  if (slider.settings.pager || slider.settings.pagerCustom) {
1738
+ updatePagerActive(slider.active.index);
1739
  }
1740
 
1741
  // check for direction control update
1742
  if (slider.settings.controls) {
1743
+ updateDirectionControls();
1744
  }
1745
 
1746
  if (slider.settings.mode === 'fade') {
1747
 
1748
  // if adaptiveHeight is true and next height is different from current height, animate to the new height
1749
  if (slider.settings.adaptiveHeight && slider.viewport.height() !== getViewportHeight()) {
1750
+ slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed);
1751
  }
1752
 
1753
  // fade out the visible child and reset its z-index value
1754
+ slider.children.filter(':visible').fadeOut(slider.settings.speed).css({zIndex: 0});
1755
 
1756
  // fade in the newly requested slide
1757
  slider.children.eq(slider.active.index).css('zIndex', slider.settings.slideZIndex + 1).fadeIn(slider.settings.speed, function () {
1758
+ $(this).css('zIndex', slider.settings.slideZIndex);
1759
+ updateAfterSlideTransition();
1760
+ });
1761
 
1762
  }
1763
  // slider mode is not "fade"
1765
 
1766
  // if adaptiveHeight is true and next height is different from current height, animate to the new height
1767
  if (slider.settings.adaptiveHeight && slider.viewport.height() !== getViewportHeight()) {
1768
+ slider.viewport.animate({height: getViewportHeight()}, slider.settings.adaptiveHeightSpeed);
1769
  }
1770
 
1771
  // if carousel and not infinite loop
1773
 
1774
  if (slider.settings.mode === 'horizontal') {
1775
  // get the last child position
1776
+ lastChild = slider.children.eq(slider.children.length - 1);
1777
+ position = lastChild.position();
1778
  // calculate the position of the last slide
1779
+ moveBy = slider.viewport.width() - lastChild.outerWidth();
1780
  }
1781
  else {
1782
  // get last showing index position
1783
+ lastShowingIndex = slider.children.length - slider.settings.minSlides;
1784
+ position = slider.children.eq(lastShowingIndex).position();
1785
  }
1786
 
1787
  }
1789
  else if (slider.carousel && slider.active.last && direction === 'prev') {
1790
 
1791
  // get the last child position
1792
+ eq = slider.settings.moveSlides === 1 ? slider.settings.maxSlides - getMoveBy() : ((getPagerQty() - 1) * getMoveBy()) - (slider.children.length - slider.settings.maxSlides);
1793
+ lastChild = el.children('.wpmslider-clone').eq(eq);
1794
+ position = lastChild.position();
1795
 
1796
  }
1797
  // if infinite loop and "Next" is clicked on the last slide
1798
  else if (direction === 'next' && slider.active.index === 0) {
1799
 
1800
  // get the last clone position
1801
+ position = el.find('> .wpmslider-clone').eq(slider.settings.maxSlides).position();
1802
+ slider.active.last = false;
1803
 
1804
  }
1805
  // normal non-zero requests
1806
  else if (slideIndex >= 0) {
1807
 
1808
  //parseInt is applied to allow floats for slides/page
1809
+ requestEl = slideIndex * parseInt(getMoveBy());
1810
+ position = slider.children.eq(requestEl).position();
1811
 
1812
  }
1813
 
1819
 
1820
  // value = slider.settings.mode === 'horizontal' ? -(position.left - moveBy) : -position.top
1821
  if (slider.settings.mode === 'horizontal') {
1822
+ value = -(position.left - moveBy);
1823
  }
1824
  else {
1825
+ value = -position.top;
1826
  }
1827
 
1828
  // plugin values to be animated
1829
+ setPositionProperty(value, 'slide', slider.settings.speed);
1830
 
1831
  }
1832
  else {
1833
+ slider.working = false;
1834
  }
1835
 
1836
  }
1837
 
1838
  if (slider.settings.ariaHidden) {
1839
+ applyAriaHiddenAttributes(slider.active.index * getMoveBy());
1840
  }
1841
+ };
1842
 
1843
  /**
1844
  * Transitions to the next slide in the show
1846
  el.goToNextSlide = function () {
1847
  // if infiniteLoop is false and last page is showing, disregard call
1848
  if (!slider.settings.infiniteLoop && slider.active.last) {
1849
+ return;
1850
  }
1851
+ var pagerIndex = parseInt(slider.active.index) + 1;
1852
+ el.goToSlide(pagerIndex, 'next');
1853
+ };
1854
 
1855
  /**
1856
  * Transitions to the prev slide in the show
1858
  el.goToPrevSlide = function () {
1859
  // if infiniteLoop is false and last page is showing, disregard call
1860
  if (!slider.settings.infiniteLoop && slider.active.index === 0) {
1861
+ return;
1862
  }
1863
+ var pagerIndex = parseInt(slider.active.index) - 1;
1864
+ el.goToSlide(pagerIndex, 'prev');
1865
+ };
1866
 
1867
  /**
1868
  * Starts the auto show
1873
  el.startAuto = function (preventControlUpdate) {
1874
  // if an interval already exists, disregard call
1875
  if (slider.interval) {
1876
+ return;
1877
  }
1878
 
1879
  // create an interval
1880
  slider.interval = setInterval(function () {
1881
  if (slider.settings.autoDirection === 'next') {
1882
+ el.goToNextSlide();
1883
  }
1884
  else {
1885
+ el.goToPrevSlide();
1886
  }
1887
+ }, slider.settings.pause);
1888
 
1889
  // if auto controls are displayed and preventControlUpdate is not true
1890
  if (slider.settings.autoControls && preventControlUpdate !== true) {
1891
+ updateAutoControls('stop');
1892
  }
1893
+ };
1894
 
1895
  /**
1896
  * Stops the auto show
1901
  el.stopAuto = function (preventControlUpdate) {
1902
  // if no interval exists, disregard call
1903
  if (!slider.interval) {
1904
+ return;
1905
  }
1906
  // clear the interval
1907
+ clearInterval(slider.interval);
1908
+ slider.interval = null;
1909
  // if auto controls are displayed and preventControlUpdate is not true
1910
  if (slider.settings.autoControls && preventControlUpdate !== true) {
1911
+ updateAutoControls('start');
1912
  }
1913
  //clearInterval(el.visibilityInterval);
1914
+ };
1915
 
1916
  /**
1917
  * Returns current slide index (zero-based)
1918
  */
1919
  el.getCurrentSlide = function () {
1920
+ return slider.active.index;
1921
+ };
1922
 
1923
  /**
1924
  * Returns current slide element
1925
  */
1926
  el.getCurrentSlideElement = function () {
1927
+ return slider.children.eq(slider.active.index);
1928
+ };
1929
 
1930
  /**
1931
  * Returns a slide element
1933
  * - The index (zero-based) of the element you want returned.
1934
  */
1935
  el.getSlideElement = function (index) {
1936
+ return slider.children.eq(index);
1937
+ };
1938
 
1939
  /**
1940
  * Returns number of slides in show
1941
  */
1942
  el.getSlideCount = function () {
1943
+ return slider.children.length;
1944
+ };
1945
 
1946
  /**
1947
  * Return slider.working variable
1948
  */
1949
  el.isWorking = function () {
1950
+ return slider.working;
1951
+ };
1952
 
1953
  /**
1954
  * Update all dynamic slider elements
1955
  */
1956
  el.redrawSlider = function () {
1957
  // resize all children in ratio to new screen size
1958
+ slider.children.add(el.find('.wpmslider-clone')).outerWidth(getSlideWidth());
1959
  // adjust the height
1960
+ slider.viewport.css('height', getViewportHeight());
1961
  // update the slide position
1962
+ setSlidePosition();
1963
  // if active.last was true before the screen resize, we want
1964
  // to keep it last no matter what screen size we end on
1965
  if (slider.active.last) {
1966
+ slider.active.index = getPagerQty() - 1;
1967
  }
1968
  // if the active index (page) no longer exists due to the resize, simply set the index as last
1969
  if (slider.active.index >= getPagerQty()) {
1970
+ slider.active.last = true;
1971
  }
1972
  // if a pager is being displayed and a custom pager is not being used, update it
1973
  if (slider.settings.pager && !slider.settings.pagerCustom) {
1974
+ populatePager();
1975
+ updatePagerActive(slider.active.index);
1976
  }
1977
  if (slider.settings.ariaHidden) {
1978
+ applyAriaHiddenAttributes(slider.active.index * getMoveBy());
1979
  }
1980
+ };
1981
 
1982
  /**
1983
  * Destroy the current instance of the slider (revert everything back to original state)
1985
  el.destroySlider = function () {
1986
  // don't do anything if slider has already been destroyed
1987
  if (!slider.initialized) {
1988
+ return;
1989
  }
1990
+ slider.initialized = false;
1991
+ $('.wpmslider-clone', this).remove();
1992
 
1993
  slider.children.each(function () {
1994
  if ($(this).data('origStyle') !== undefined) {
1995
+ $(this).attr('style', $(this).data('origStyle'));
1996
  }
1997
  else {
1998
+ $(this).removeAttr('style');
1999
  }
2000
+ });
2001
 
2002
  if ($(this).data('origStyle') !== undefined) {
2003
+ this.attr('style', $(this).data('origStyle'));
2004
  }
2005
  else {
2006
+ $(this).removeAttr('style');
2007
  }
2008
 
2009
+ $(this).unwrap().unwrap();
2010
 
2011
  if (slider.controls.el) {
2012
+ slider.controls.el.remove();
2013
  }
2014
  if (slider.controls.next) {
2015
+ slider.controls.next.remove();
2016
  }
2017
  if (slider.controls.prev) {
2018
+ slider.controls.prev.remove();
2019
  }
2020
  if (slider.pagerEl && slider.settings.controls && !slider.settings.pagerCustom) {
2021
+ slider.pagerEl.remove();
2022
  }
2023
 
2024
+ $('.wpmslider-caption', this).remove();
2025
 
2026
  if (slider.controls.autoEl) {
2027
+ slider.controls.autoEl.remove();
2028
  }
2029
 
2030
+ clearInterval(slider.interval);
2031
+ clearInterval(slider.visibilityInterval);
2032
+
2033
  if (slider.settings.responsive) {
2034
+ $(window).off('resize', resizeWindow);
2035
  }
2036
 
2037
  if (slider.settings.keyboardEnabled) {
2038
+ $(document).off('keydown', keyPress);
2039
  }
2040
 
2041
  //remove self reference in data
2042
+ $(this).removeData('strongSlider');
2043
+ };
2044
 
2045
  /**
2046
  * Reload the slider (revert all DOM changes, and re-initialize)
2047
  */
2048
  el.reloadSlider = function (settings) {
2049
  if (settings !== undefined) {
2050
+ options = settings;
2051
  }
2052
+ el.destroySlider();
2053
+ init();
2054
  // Store reference to self in order to access public functions later
2055
+ $(el).data('strongSlider', this);
2056
+ };
2057
 
2058
  // Fire it up!
2059
+ init();
2060
 
2061
  // Store reference to self in order to access public functions later
2062
+ $(el).data('strongSlider', this);
2063
 
2064
  // Set initialized flag on container
2065
+ viewEl.attr('data-state', 'init');
2066
 
2067
+ if (slider.debug) console.log(slider.logAs, 'viewport', verge.viewportW(), 'x', verge.viewportH());
2068
 
2069
  // returns the current jQuery object
2070
+ return this;
2071
+ };
2072
 
2073
+ })(jQuery);
public/js/lib/strongslider/jquery.strongslider.min.js CHANGED
@@ -1,2 +1,2 @@
1
- (function($){var defaults={debug:false,logAs:"strongSlider",compat:{flatsome:false},mode:"horizontal",slideSelector:"div.t-slide",infiniteLoop:true,hideControlOnEnd:false,speed:500,easing:null,slideMargin:0,startSlide:0,randomStart:false,captions:false,adaptiveHeight:false,adaptiveHeightSpeed:500,useCSS:true,preloadImages:"visible",responsive:true,slideZIndex:50,stretch:false,imagesLoaded:true,wrapperClass:"wpmslider-wrapper",touchEnabled:true,swipeThreshold:50,oneToOneTouch:true,preventDefaultSwipeX:true,preventDefaultSwipeY:false,ariaLive:true,ariaHidden:true,keyboardEnabled:false,pager:true,pagerType:"full",pagerShortSeparator:" / ",pagerSelector:null,buildPager:null,pagerCustom:null,controls:true,nextText:"Next",prevText:"Prev",nextSelector:null,prevSelector:null,autoControls:false,startText:"Start",stopText:"Stop",autoControlsCombine:false,autoControlsSelector:null,auto:true,pause:4e3,autoStart:true,autoDirection:"next",stopAutoOnClick:false,autoHover:false,autoDelay:0,autoSlideForOnePage:false,minSlides:1,maxSlides:1,moveSlides:0,slideWidth:0,shrinkItems:false,onSliderLoad:function(){return true},onSlideBefore:function(){return true},onSlideAfter:function(){return true},onSlideNext:function(){return true},onSlidePrev:function(){return true},onSliderResize:function(){return true}};$.fn.strongSlider=function(options){if(this.length===0){return this}var slider={},viewEl=this,el=this.find(".wpmslider-content");if($(el).data("strongSlider")){return}var init=function(){if($(el).data("strongSlider")){return}slider.visibilityInterval=0;slider.hidden=false;var sliderVar=viewEl.data("slider-var");var config={};if(typeof window[sliderVar]!=="undefined"){config=window[sliderVar].config}slider.settings=$.extend({},defaults,config,options);slider.debug=slider.settings.debug;slider.logAs=slider.settings.logAs;if(slider.debug)console.log(slider.logAs,"slider.settings",slider.settings);slider.settings.slideWidth=parseInt(slider.settings.slideWidth);slider.children=el.children(slider.settings.slideSelector);if(slider.children.length<slider.settings.minSlides){slider.settings.minSlides=slider.children.length}if(slider.children.length<slider.settings.maxSlides){slider.settings.maxSlides=slider.children.length}if(slider.settings.randomStart){slider.settings.startSlide=Math.floor(Math.random()*slider.children.length)}slider.active={index:slider.settings.startSlide};slider.carousel=slider.settings.minSlides>1||slider.settings.maxSlides>1;if(slider.carousel){slider.settings.preloadImages="all"}slider.minThreshold=slider.settings.minSlides*slider.settings.slideWidth+(slider.settings.minSlides-1)*slider.settings.slideMargin;slider.maxThreshold=slider.settings.maxSlides*slider.settings.slideWidth+(slider.settings.maxSlides-1)*slider.settings.slideMargin;slider.working=false;slider.controls={};slider.interval=null;slider.animProp=slider.settings.mode==="vertical"?"top":"left";slider.usingCSS=slider.settings.useCSS&&slider.settings.mode!=="fade"&&function(){var div=document.createElement("div");var props=["WebkitPerspective","MozPerspective","OPerspective","msPerspective"];for(var i=0;i<props.length;i++){if(div.style[props[i]]!==undefined){slider.cssPrefix=props[i].replace("Perspective","").toLowerCase();slider.animProp="-"+slider.cssPrefix+"-transform";return true}}return false}();if(slider.settings.mode==="vertical"){slider.settings.maxSlides=slider.settings.minSlides}el.data("origStyle",el.attr("style"));el.children(slider.settings.slideSelector).each(function(){$(this).data("origStyle",$(this).attr("style"))});if(!el.getSlideCount()){return}if(slider.settings.imagesLoaded){viewEl.imagesLoaded(function(){initVisibilityCheck()})}else{initVisibilityCheck()}};var reallyVisible=function(){return viewEl.is(":visible")&&viewEl.css("visibility")!=="hidden"};var compatCheck=function(){if(slider.settings.compat.flatsome){if(viewEl.find("img.lazy-load").length){if(slider.debug)console.log(slider.logAs,"lazy loading...");return false}}if(slider.debug)console.log(slider.logAs,"compat check complete");return true};var initVisibilityCheck=function(){if(reallyVisible()&&compatCheck()){clearInterval(slider.visibilityInterval);setup()}else{if(slider.visibilityInterval===0){slider.visibilityInterval=setInterval(initVisibilityCheck,1e3*4)}}};var setup=function(){var preloadSelector=slider.children.eq(slider.settings.startSlide);el.wrap('<div class="'+slider.settings.wrapperClass+'"><div class="wpmslider-viewport"></div></div>');slider.viewport=el.parent();if(slider.settings.ariaLive){slider.viewport.attr("aria-live","polite")}slider.loader=$('<div class="wpmslider-loading" />');slider.viewport.prepend(slider.loader);el.css({width:slider.settings.mode==="horizontal"?slider.children.length*1e3+215+"%":"auto",position:"relative"});if(slider.usingCSS&&slider.settings.easing){el.css("-"+slider.cssPrefix+"-transition-timing-function",slider.settings.easing)}else if(!slider.settings.easing){slider.settings.easing="swing"}slider.viewport.css({width:"100%",overflow:"hidden",position:"relative"});slider.viewport.parent().css({maxWidth:getViewportMaxWidth()});if(!slider.settings.pager&&!slider.settings.controls){slider.viewport.parent().css({margin:"0 auto 0px"})}slider.children.css({float:slider.settings.mode==="horizontal"?"left":"none",position:"relative"});slider.children.css("width",getSlideWidth());if(slider.settings.mode==="horizontal"&&slider.settings.slideMargin>0){slider.children.css("marginRight",slider.settings.slideMargin)}if(slider.settings.mode==="vertical"&&slider.settings.slideMargin>0){slider.children.css("marginBottom",slider.settings.slideMargin)}if(slider.settings.mode==="fade"){slider.children.css({position:"absolute",zIndex:0,display:"none"});slider.children.eq(slider.settings.startSlide).css({zIndex:slider.settings.slideZIndex,display:"block"})}else{slider.children.css({display:"block"})}slider.controls.el=$('<div class="wpmslider-controls" />');if(slider.settings.captions){appendCaptions()}slider.active.last=slider.settings.startSlide===getPagerQty()-1;if(slider.settings.preloadImages==="all"){preloadSelector=slider.children}if(slider.settings.controls){appendControlPrev()}if(slider.settings.auto&&slider.settings.autoControls){appendControlsAuto()}if(slider.settings.pager){appendPager()}if(slider.settings.controls){appendControlNext()}if(slider.settings.controls||slider.settings.autoControls||slider.settings.pager){slider.viewport.after(slider.controls.el)}start()};var start=function(){if(slider.settings.infiniteLoop&&slider.settings.mode!=="fade"){var slice=slider.settings.mode==="vertical"?slider.settings.minSlides:slider.settings.maxSlides;var sliceAppend=slider.children.slice(0,slice).clone(true).addClass("wpmslider-clone");var slicePrepend=slider.children.slice(-slice).clone(true).addClass("wpmslider-clone");if(slider.settings.ariaHidden){sliceAppend.attr("aria-hidden",true);slicePrepend.attr("aria-hidden",true)}el.append(sliceAppend).prepend(slicePrepend)}slider.loader.remove();setSlidePosition();if(slider.settings.mode==="vertical"){slider.settings.adaptiveHeight=true}slider.viewport.height(getViewportHeight());if(slider.settings.stretch){setSlideHeight()}el.redrawSlider();slider.settings.onSliderLoad.call(el,slider.active.index);slider.initialized=true;slider.visibilityInterval=setInterval(visibilityCheck,500);if(slider.settings.responsive){attachListeners()}if(slider.settings.auto&&slider.settings.autoStart&&(getPagerQty()>1||slider.settings.autoSlideForOnePage)){initAuto()}if(slider.settings.pager){updatePagerActive(slider.settings.startSlide)}if(slider.settings.controls){updateDirectionControls()}if(slider.settings.touchEnabled){initTouch()}if(slider.settings.keyboardEnabled){$(document).keydown(keyPress)}};var attachListeners=function(){window.addEventListener("resize",updateLayout,false);window.addEventListener("orientationchange",updateLayout,false);window.addEventListener("blur",function(){pauseEvent("blur")});window.addEventListener("focus",function(){playEvent("blur")})};var updateLayout=_.debounce(function(){resizeWindow()},250);var visibilityCheck=function(){if(!slider.settings.auto){return}if(!reallyVisible()){pauseEvent("hide")}else{playEvent("hide")}if(!verge.inViewport(el)){pauseEvent("scroll")}else{playEvent("scroll")}};var pauseEvent=function(action){if(slider.interval){el.stopAuto(true);slider.autoPaused=action;if(slider.debug)console.log(slider.logAs,"pause",action)}};var playEvent=function(action){if(slider.autoPaused===action){el.startAuto(true);slider.autoPaused=null;if(slider.debug)console.log(slider.logAs,"play",action)}};var setSlideHeight=function(){var heights=slider.children.map(function(){return jQuery(this).actual("outerHeight")}).get();var maxHeight=arrayMax(heights);slider.children.height(maxHeight)};var arrayMax=function(array){return Math.max.apply(Math,array)};var getViewportHeight=function(){var height=0;var children=$();if(slider.settings.mode!=="vertical"&&!slider.settings.adaptiveHeight){children=slider.children}else{if(!slider.carousel){children=slider.children.eq(slider.active.index)}else{var currentIndex=slider.settings.moveSlides===1?slider.active.index:slider.active.index*getMoveBy();children=slider.children.eq(currentIndex);for(var i=1;i<=slider.settings.maxSlides-1;i++){if(currentIndex+i>=slider.children.length){children=children.add(slider.children.eq(i-1))}else{children=children.add(slider.children.eq(currentIndex+i))}}}}if(slider.settings.mode==="vertical"){children.each(function(index){height+=$(this).outerHeight()});if(slider.settings.slideMargin>0){height+=slider.settings.slideMargin*(slider.settings.minSlides-1)}}else{height=Math.max.apply(Math,children.map(function(){return $(this).outerHeight(false)}).get())}if(slider.viewport.css("box-sizing")==="border-box"){height+=parseFloat(slider.viewport.css("padding-top"))+parseFloat(slider.viewport.css("padding-bottom"))+parseFloat(slider.viewport.css("border-top-width"))+parseFloat(slider.viewport.css("border-bottom-width"))}else if(slider.viewport.css("box-sizing")==="padding-box"){height+=parseFloat(slider.viewport.css("padding-top"))+parseFloat(slider.viewport.css("padding-bottom"))}return height};var getViewportMaxWidth=function(){var width="100%";if(slider.settings.slideWidth>0){if(slider.settings.mode==="horizontal"){width=slider.settings.maxSlides*slider.settings.slideWidth+(slider.settings.maxSlides-1)*slider.settings.slideMargin}else{width=slider.settings.slideWidth}}return width};var getSlideWidth=function(){var newElWidth=slider.settings.slideWidth,wrapWidth=slider.viewport.width();if(slider.settings.slideWidth===0||slider.settings.slideWidth>wrapWidth&&!slider.carousel||slider.settings.mode==="vertical"){newElWidth=wrapWidth}else if(slider.settings.maxSlides>1&&slider.settings.mode==="horizontal"){if(wrapWidth>slider.maxThreshold){return newElWidth}else if(wrapWidth<slider.minThreshold){newElWidth=(wrapWidth-slider.settings.slideMargin*(slider.settings.minSlides-1))/slider.settings.minSlides}else if(slider.settings.shrinkItems){newElWidth=Math.floor((wrapWidth+slider.settings.slideMargin)/Math.ceil((wrapWidth+slider.settings.slideMargin)/(newElWidth+slider.settings.slideMargin))-slider.settings.slideMargin)}}return newElWidth};var getNumberSlidesShowing=function(){var slidesShowing=1,childWidth=null;if(slider.settings.mode==="horizontal"&&slider.settings.slideWidth>0){if(slider.viewport.width()<slider.minThreshold){slidesShowing=slider.settings.minSlides}else if(slider.viewport.width()>slider.maxThreshold){slidesShowing=slider.settings.maxSlides}else{childWidth=slider.children.first().width()+slider.settings.slideMargin;slidesShowing=Math.floor((slider.viewport.width()+slider.settings.slideMargin)/childWidth)}}else if(slider.settings.mode==="vertical"){slidesShowing=slider.settings.minSlides}return slidesShowing};var getPagerQty=function(){var pagerQty=0,breakPoint=0,counter=0;if(slider.settings.moveSlides>0){if(slider.settings.infiniteLoop){pagerQty=Math.ceil(slider.children.length/getMoveBy())}else{while(breakPoint<slider.children.length){++pagerQty;breakPoint=counter+getNumberSlidesShowing();counter+=slider.settings.moveSlides<=getNumberSlidesShowing()?slider.settings.moveSlides:getNumberSlidesShowing()}}}else{pagerQty=Math.ceil(slider.children.length/getNumberSlidesShowing())}return pagerQty};var getMoveBy=function(){if(slider.settings.moveSlides>0&&slider.settings.moveSlides<=getNumberSlidesShowing()){return slider.settings.moveSlides}return getNumberSlidesShowing()};var setSlidePosition=function(){var position,lastChild,lastShowingIndex;if(slider.children.length>slider.settings.maxSlides&&slider.active.last&&!slider.settings.infiniteLoop){if(slider.settings.mode==="horizontal"){lastChild=slider.children.last();position=lastChild.position();setPositionProperty(-(position.left-(slider.viewport.width()-lastChild.outerWidth())),"reset",0)}else if(slider.settings.mode==="vertical"){lastShowingIndex=slider.children.length-slider.settings.minSlides;position=slider.children.eq(lastShowingIndex).position();setPositionProperty(-position.top,"reset",0)}}else{position=slider.children.eq(slider.active.index*getMoveBy()).position();if(slider.active.index===getPagerQty()-1){slider.active.last=true}if(position!==undefined){if(slider.settings.mode==="horizontal"){setPositionProperty(-position.left,"reset",0)}else if(slider.settings.mode==="vertical"){setPositionProperty(-position.top,"reset",0)}else if(slider.settings.mode==="none"){setPositionProperty(-position.top,"reset",0)}}}};var setPositionProperty=function(value,type,duration,params){var animateObj,propValue;if(slider.usingCSS){if(slider.settings.mode==="vertical"){propValue="translateY("+value+"px)"}else if(slider.settings.mode==="horizontal"){propValue="translateX("+value+"px"}else if(slider.settings.mode==="none"){propValue="translateY("+value+"px)";duration=0}el.css("-"+slider.cssPrefix+"-transition-duration",duration/1e3+"s");if(type==="slide"){el.css(slider.animProp,propValue);if(duration!==0){el.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd",function(e){if(!$(e.target).is(el)){return}el.off("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd");updateAfterSlideTransition()})}else{updateAfterSlideTransition()}}else if(type==="reset"){el.css(slider.animProp,propValue)}}else{animateObj={};animateObj[slider.animProp]=value;if(type==="slide"){el.animate(animateObj,duration,slider.settings.easing,function(){updateAfterSlideTransition()})}else if(type==="reset"){el.css(slider.animProp,value)}}};var populatePager=function(){var pagerHtml="",linkContent="",pagerQty=getPagerQty();for(var i=0;i<pagerQty;i++){linkContent="";if(slider.settings.buildPager){if(slider.settings.buildPager==="icons"){linkContent=""}if($.isFunction(slider.settings.buildPager)||slider.settings.pagerCustom){linkContent=slider.settings.buildPager(i)}slider.pagerEl.addClass("wpmslider-custom-pager")}else{linkContent=i+1;slider.pagerEl.addClass("wpmslider-default-pager")}pagerHtml+='<div class="wpmslider-pager-item"><a href="" data-slide-index="'+i+'" class="wpmslider-pager-link">'+linkContent+"</a></div>"}slider.pagerEl.html(pagerHtml)};var appendPager=function(){if(!slider.settings.pagerCustom){slider.pagerEl=$('<div class="wpmslider-pager" />');if(slider.settings.pagerSelector){$(slider.settings.pagerSelector).html(slider.pagerEl)}else{slider.controls.el.addClass("wpmslider-has-pager").append(slider.pagerEl)}populatePager()}else{slider.pagerEl=$(slider.settings.pagerCustom)}slider.pagerEl.on("click touchend","a",clickPagerBind)};var appendControlPrev=function(){slider.controls.prev=$('<a class="wpmslider-prev" href="">'+slider.settings.prevText+"</a>");slider.controls.prev.on("click touchend",clickPrevBind);if(slider.settings.prevSelector){$(slider.settings.prevSelector).append(slider.controls.prev)}if(!slider.settings.prevSelector){slider.controls.directionEl=$('<div class="wpmslider-controls-direction" />');slider.controls.directionEl.append(slider.controls.prev);slider.controls.el.addClass("wpmslider-has-controls-direction").append(slider.controls.directionEl)}};var appendControlNext=function(){slider.controls.next=$('<a class="wpmslider-next" href="">'+slider.settings.nextText+"</a>");slider.controls.next.on("click touchend",clickNextBind);if(slider.settings.nextSelector){$(slider.settings.nextSelector).append(slider.controls.next)}if(!slider.settings.nextSelector){slider.controls.directionEl=$('<div class="wpmslider-controls-direction" />');slider.controls.directionEl.append(slider.controls.next);slider.controls.el.addClass("wpmslider-has-controls-direction").append(slider.controls.directionEl)}};var appendControlsAuto=function(){slider.controls.start=$('<div class="wpmslider-controls-auto-item"><a class="wpmslider-start" href="">'+slider.settings.startText+"</a></div>");slider.controls.stop=$('<div class="wpmslider-controls-auto-item"><a class="wpmslider-stop" href="">'+slider.settings.stopText+"</a></div>");slider.controls.autoEl=$('<div class="wpmslider-controls-auto" />');slider.controls.autoEl.on("click",".wpmslider-start",clickStartBind);slider.controls.autoEl.on("click",".wpmslider-stop",clickStopBind);if(slider.settings.autoControlsCombine){slider.controls.autoEl.append(slider.controls.start)}else{slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop)}if(slider.settings.autoControlsSelector){$(slider.settings.autoControlsSelector).html(slider.controls.autoEl)}else{slider.controls.el.addClass("wpmslider-has-controls-auto").append(slider.controls.autoEl)}updateAutoControls(slider.settings.autoStart?"stop":"start")};var appendCaptions=function(){slider.children.each(function(index){var title=$(this).find("img:first").attr("title");if(title!==undefined&&(""+title).length){$(this).append('<div class="wpmslider-caption"><span>'+title+"</span></div>")}})};var clickNextBind=function(e){e.preventDefault();e.stopPropagation();if(slider.controls.el.hasClass("disabled")){return}if(slider.settings.auto&&slider.settings.stopAutoOnClick){if(slider.debug)console.log(slider.logAs,"stop on navigation");el.stopAuto()}el.goToNextSlide()};var clickPrevBind=function(e){e.preventDefault();e.stopPropagation();if(slider.controls.el.hasClass("disabled")){return}if(slider.settings.auto&&slider.settings.stopAutoOnClick){if(slider.debug)console.log(slider.logAs,"stop on navigation");el.stopAuto()}el.goToPrevSlide()};var clickStartBind=function(e){el.startAuto();e.preventDefault();e.stopPropagation()};var clickStopBind=function(e){el.stopAuto();e.preventDefault();e.stopPropagation()};var clickPagerBind=function(e){var pagerLink,pagerIndex;e.preventDefault();e.stopPropagation();if(slider.controls.el.hasClass("disabled")){return}if(slider.settings.auto&&slider.settings.stopAutoOnClick){if(slider.debug)console.log(slider.logAs,"stop on navigation");el.stopAuto()}pagerLink=$(e.currentTarget);if(pagerLink.attr("data-slide-index")!==undefined){pagerIndex=parseInt(pagerLink.attr("data-slide-index"));if(pagerIndex!==slider.active.index){el.goToSlide(pagerIndex)}}};var updatePagerActive=function(slideIndex){var len=slider.children.length;if(slider.settings.pagerType==="short"){if(slider.settings.maxSlides>1){len=Math.ceil(slider.children.length/slider.settings.maxSlides)}slider.pagerEl.html(slideIndex+1+slider.settings.pagerShortSeparator+len);return}slider.pagerEl.find("a").removeClass("active");slider.pagerEl.each(function(i,el){$(el).find("a").eq(slideIndex).addClass("active")})};var updateAfterSlideTransition=function(){if(slider.settings.infiniteLoop){var position="";if(slider.active.index===0){position=slider.children.eq(0).position()}else if(slider.active.index===getPagerQty()-1&&slider.carousel){position=slider.children.eq((getPagerQty()-1)*getMoveBy()).position()}else if(slider.active.index===slider.children.length-1){position=slider.children.eq(slider.children.length-1).position()}if(position){if(slider.settings.mode==="horizontal"){setPositionProperty(-position.left,"reset",0)}else if(slider.settings.mode==="vertical"){setPositionProperty(-position.top,"reset",0)}}}slider.working=false;slider.settings.onSlideAfter.call(el,slider.children.eq(slider.active.index),slider.oldIndex,slider.active.index)};var updateAutoControls=function(state){if(slider.settings.autoControlsCombine){slider.controls.autoEl.html(slider.controls[state])}else{slider.controls.autoEl.find("a").removeClass("active");slider.controls.autoEl.find("a:not(.wpmslider-"+state+")").addClass("active")}};var updateDirectionControls=function(){if(getPagerQty()===1){slider.controls.prev.addClass("disabled");slider.controls.next.addClass("disabled")}else if(!slider.settings.infiniteLoop&&slider.settings.hideControlOnEnd){if(slider.active.index===0){slider.controls.prev.addClass("disabled");slider.controls.next.removeClass("disabled")}else if(slider.active.index===getPagerQty()-1){slider.controls.next.addClass("disabled");slider.controls.prev.removeClass("disabled")}else{slider.controls.prev.removeClass("disabled");slider.controls.next.removeClass("disabled")}}};var initAuto=function(){if(slider.settings.autoDelay>0){var timeout=setTimeout(el.startAuto,slider.settings.autoDelay)}else{el.startAuto()}if(slider.settings.autoHover){el.hover(function(){pauseEvent("hover")},function(){playEvent("hover")})}};var keyPress=function(e){var activeElementTag=document.activeElement.tagName.toLowerCase(),tagFilters="input|textarea",p=new RegExp(activeElementTag,["i"]),result=p.exec(tagFilters);if(result===null&&verge.inViewport(el)){if(e.keyCode===39){clickNextBind(e);return false}else if(e.keyCode===37){clickPrevBind(e);return false}}};var initTouch=function(){slider.touch={start:{x:0,y:0},end:{x:0,y:0}};slider.viewport.on("touchstart MSPointerDown pointerdown",onTouchStart);slider.viewport.on("click",".wpmslider a",function(e){if(slider.viewport.hasClass("click-disabled")){e.preventDefault();e.stopPropagation();slider.viewport.removeClass("click-disabled")}})};var onTouchStart=function(e){slider.controls.el.addClass("disabled");if(slider.working){e.preventDefault();e.stopPropagation();slider.controls.el.removeClass("disabled")}else{slider.touch.originalPos=el.position();var orig=e.originalEvent,touchPoints=typeof orig.changedTouches!=="undefined"?orig.changedTouches:[orig];var chromePointerEvents=typeof PointerEvent==="function";if(chromePointerEvents){if(orig.pointerId===undefined){return}}slider.touch.start.x=touchPoints[0].pageX;slider.touch.start.y=touchPoints[0].pageY;if(slider.viewport.get(0).setPointerCapture){slider.pointerId=orig.pointerId;if(slider.pointerId===1){slider.viewport.get(0).setPointerCapture(slider.pointerId)}}slider.viewport.on("touchmove MSPointerMove pointermove",onTouchMove);slider.viewport.on("touchend MSPointerUp pointerup",onTouchEnd);slider.viewport.on("MSPointerCancel pointercancel",onPointerCancel)}};var onPointerCancel=function(e){setPositionProperty(slider.touch.originalPos.left,"reset",0);slider.controls.el.removeClass("disabled");slider.viewport.off("MSPointerCancel pointercancel",onPointerCancel);slider.viewport.off("touchmove MSPointerMove pointermove",onTouchMove);slider.viewport.off("touchend MSPointerUp pointerup",onTouchEnd);if(slider.viewport.get(0).releasePointerCapture){slider.viewport.get(0).releasePointerCapture(slider.pointerId)}};var onTouchMove=function(e){var orig=e.originalEvent,touchPoints=typeof orig.changedTouches!=="undefined"?orig.changedTouches:[orig],xMovement=Math.abs(touchPoints[0].pageX-slider.touch.start.x),yMovement=Math.abs(touchPoints[0].pageY-slider.touch.start.y),value=0,change=0;if(xMovement*3>yMovement&&slider.settings.preventDefaultSwipeX){e.preventDefault();e.stopPropagation()}else if(yMovement*3>xMovement&&slider.settings.preventDefaultSwipeY){e.preventDefault();e.stopPropagation()}if(slider.settings.mode!=="fade"&&slider.settings.oneToOneTouch){if(slider.settings.mode==="horizontal"){change=touchPoints[0].pageX-slider.touch.start.x;value=slider.touch.originalPos.left+change}else{change=touchPoints[0].pageY-slider.touch.start.y;value=slider.touch.originalPos.top+change}setPositionProperty(value,"reset",0)}};var onTouchEnd=function(e){slider.viewport.off("touchmove MSPointerMove pointermove",onTouchMove);slider.controls.el.removeClass("disabled");var orig=e.originalEvent,touchPoints=typeof orig.changedTouches!=="undefined"?orig.changedTouches:[orig],value=0,distance=0;slider.touch.end.x=touchPoints[0].pageX;slider.touch.end.y=touchPoints[0].pageY;if(slider.settings.mode==="fade"){distance=Math.abs(slider.touch.start.x-slider.touch.end.x);if(distance>=slider.settings.swipeThreshold){if(slider.touch.start.x>slider.touch.end.x){el.goToNextSlide()}else{el.goToPrevSlide()}el.stopAuto()}}else{if(slider.settings.mode==="horizontal"){distance=slider.touch.end.x-slider.touch.start.x;value=slider.touch.originalPos.left}else{distance=slider.touch.end.y-slider.touch.start.y;value=slider.touch.originalPos.top}if(!slider.settings.infiniteLoop&&(slider.active.index===0&&distance>0||slider.active.last&&distance<0)){setPositionProperty(value,"reset",200)}else{if(Math.abs(distance)>=slider.settings.swipeThreshold){if(distance<0){el.goToNextSlide()}else{el.goToPrevSlide()}el.stopAuto()}else{setPositionProperty(value,"reset",200)}}}slider.viewport.off("touchend MSPointerUp pointerup",onTouchEnd);if(slider.viewport.get(0).releasePointerCapture){slider.viewport.get(0).releasePointerCapture(slider.pointerId)}};var resizeWindow=function(e){if(!slider.initialized){return}if(slider.working){window.setTimeout(resizeWindow,10)}else{el.redrawSlider();slider.settings.onSliderResize.call(el,slider.active.index)}};var applyAriaHiddenAttributes=function(startVisibleIndex){var numberOfSlidesShowing=getNumberSlidesShowing();if(slider.settings.ariaHidden){slider.children.attr("aria-hidden","true");slider.children.slice(startVisibleIndex,startVisibleIndex+numberOfSlidesShowing).attr("aria-hidden","false")}};var setSlideIndex=function(slideIndex){if(slideIndex<0){if(slider.settings.infiniteLoop){return getPagerQty()-1}else{return slider.active.index}}else if(slideIndex>=getPagerQty()){if(slider.settings.infiniteLoop){return 0}else{return slider.active.index}}else{return slideIndex}};el.goToSlide=function(slideIndex,direction){var performTransition,moveBy=0,position={left:0,top:0},lastChild=null,lastShowingIndex,eq,value,requestEl;slider.oldIndex=slider.active.index;slider.active.index=setSlideIndex(slideIndex);if(slider.working||slider.active.index===slider.oldIndex){return}slider.working=true;performTransition=slider.settings.onSlideBefore.call(el,slider.children.eq(slider.active.index),slider.oldIndex,slider.active.index);if(typeof performTransition!=="undefined"&&!performTransition){slider.active.index=slider.oldIndex;slider.working=false;return}if(direction==="next"){if(!slider.settings.onSlideNext.call(el,slider.children.eq(slider.active.index),slider.oldIndex,slider.active.index)){performTransition=false}}else if(direction==="prev"){if(!slider.settings.onSlidePrev.call(el,slider.children.eq(slider.active.index),slider.oldIndex,slider.active.index)){performTransition=false}}slider.active.last=slider.active.index>=getPagerQty()-1;if(slider.settings.pager||slider.settings.pagerCustom){updatePagerActive(slider.active.index)}if(slider.settings.controls){updateDirectionControls()}if(slider.settings.mode==="fade"){if(slider.settings.adaptiveHeight&&slider.viewport.height()!==getViewportHeight()){slider.viewport.animate({height:getViewportHeight()},slider.settings.adaptiveHeightSpeed)}slider.children.filter(":visible").fadeOut(slider.settings.speed).css({zIndex:0});slider.children.eq(slider.active.index).css("zIndex",slider.settings.slideZIndex+1).fadeIn(slider.settings.speed,function(){$(this).css("zIndex",slider.settings.slideZIndex);updateAfterSlideTransition()})}else{if(slider.settings.adaptiveHeight&&slider.viewport.height()!==getViewportHeight()){slider.viewport.animate({height:getViewportHeight()},slider.settings.adaptiveHeightSpeed)}if(!slider.settings.infiniteLoop&&slider.carousel&&slider.active.last){if(slider.settings.mode==="horizontal"){lastChild=slider.children.eq(slider.children.length-1);position=lastChild.position();moveBy=slider.viewport.width()-lastChild.outerWidth()}else{lastShowingIndex=slider.children.length-slider.settings.minSlides;position=slider.children.eq(lastShowingIndex).position()}}else if(slider.carousel&&slider.active.last&&direction==="prev"){eq=slider.settings.moveSlides===1?slider.settings.maxSlides-getMoveBy():(getPagerQty()-1)*getMoveBy()-(slider.children.length-slider.settings.maxSlides);lastChild=el.children(".wpmslider-clone").eq(eq);position=lastChild.position()}else if(direction==="next"&&slider.active.index===0){position=el.find("> .wpmslider-clone").eq(slider.settings.maxSlides).position();slider.active.last=false}else if(slideIndex>=0){requestEl=slideIndex*parseInt(getMoveBy());position=slider.children.eq(requestEl).position()}if(typeof position!=="undefined"){if(slider.settings.mode==="horizontal"){value=-(position.left-moveBy)}else{value=-position.top}setPositionProperty(value,"slide",slider.settings.speed)}else{slider.working=false}}if(slider.settings.ariaHidden){applyAriaHiddenAttributes(slider.active.index*getMoveBy())}};el.goToNextSlide=function(){if(!slider.settings.infiniteLoop&&slider.active.last){return}var pagerIndex=parseInt(slider.active.index)+1;el.goToSlide(pagerIndex,"next")};el.goToPrevSlide=function(){if(!slider.settings.infiniteLoop&&slider.active.index===0){return}var pagerIndex=parseInt(slider.active.index)-1;el.goToSlide(pagerIndex,"prev")};el.startAuto=function(preventControlUpdate){if(slider.interval){return}slider.interval=setInterval(function(){if(slider.settings.autoDirection==="next"){el.goToNextSlide()}else{el.goToPrevSlide()}},slider.settings.pause);if(slider.settings.autoControls&&preventControlUpdate!==true){updateAutoControls("stop")}};el.stopAuto=function(preventControlUpdate){if(!slider.interval){return}clearInterval(slider.interval);slider.interval=null;if(slider.settings.autoControls&&preventControlUpdate!==true){updateAutoControls("start")}};el.getCurrentSlide=function(){return slider.active.index};el.getCurrentSlideElement=function(){return slider.children.eq(slider.active.index)};el.getSlideElement=function(index){return slider.children.eq(index)};el.getSlideCount=function(){return slider.children.length};el.isWorking=function(){return slider.working};el.redrawSlider=function(){slider.children.add(el.find(".wpmslider-clone")).outerWidth(getSlideWidth());slider.viewport.css("height",getViewportHeight());setSlidePosition();if(slider.active.last){slider.active.index=getPagerQty()-1}if(slider.active.index>=getPagerQty()){slider.active.last=true}if(slider.settings.pager&&!slider.settings.pagerCustom){populatePager();updatePagerActive(slider.active.index)}if(slider.settings.ariaHidden){applyAriaHiddenAttributes(slider.active.index*getMoveBy())}};el.destroySlider=function(){if(!slider.initialized){return}slider.initialized=false;$(".wpmslider-clone",this).remove();slider.children.each(function(){if($(this).data("origStyle")!==undefined){$(this).attr("style",$(this).data("origStyle"))}else{$(this).removeAttr("style")}});if($(this).data("origStyle")!==undefined){this.attr("style",$(this).data("origStyle"))}else{$(this).removeAttr("style")}$(this).unwrap().unwrap();if(slider.controls.el){slider.controls.el.remove()}if(slider.controls.next){slider.controls.next.remove()}if(slider.controls.prev){slider.controls.prev.remove()}if(slider.pagerEl&&slider.settings.controls&&!slider.settings.pagerCustom){slider.pagerEl.remove()}$(".wpmslider-caption",this).remove();if(slider.controls.autoEl){slider.controls.autoEl.remove()}clearInterval(slider.interval);clearInterval(slider.visibilityInterval);if(slider.settings.responsive){$(window).off("resize",resizeWindow)}if(slider.settings.keyboardEnabled){$(document).off("keydown",keyPress)}$(this).removeData("strongSlider")};el.reloadSlider=function(settings){
2
- if(settings!==undefined){options=settings}el.destroySlider();init();$(el).data("strongSlider",this)};init();$(el).data("strongSlider",this);viewEl.attr("data-state","init");if(slider.debug)console.log(slider.logAs,"viewport",verge.viewportW(),"x",verge.viewportH());return this}})(jQuery);
1
+ (function($){var defaults={debug:false,logAs:"strongSlider",compat:{lazyload:{active:false,classes:{}}},mode:"horizontal",slideSelector:"div.t-slide",infiniteLoop:true,hideControlOnEnd:false,speed:500,easing:null,slideMargin:0,startSlide:0,randomStart:false,captions:false,adaptiveHeight:false,adaptiveHeightSpeed:500,useCSS:true,preloadImages:"visible",responsive:true,slideZIndex:50,stretch:false,imagesLoaded:true,wrapperClass:"wpmslider-wrapper",touchEnabled:true,swipeThreshold:50,oneToOneTouch:true,preventDefaultSwipeX:true,preventDefaultSwipeY:false,ariaLive:true,ariaHidden:true,keyboardEnabled:false,pager:true,pagerType:"full",pagerShortSeparator:" / ",pagerSelector:null,buildPager:null,pagerCustom:null,controls:true,nextText:"Next",prevText:"Prev",nextSelector:null,prevSelector:null,autoControls:false,startText:"Start",stopText:"Stop",autoControlsCombine:false,autoControlsSelector:null,auto:true,pause:4e3,autoStart:true,autoDirection:"next",stopAutoOnClick:false,autoHover:false,autoDelay:0,autoSlideForOnePage:false,minSlides:1,maxSlides:1,moveSlides:0,slideWidth:0,shrinkItems:false,onSliderLoad:function(){return true},onSlideBefore:function(){return true},onSlideAfter:function(){return true},onSlideNext:function(){return true},onSlidePrev:function(){return true},onSliderResize:function(){return true}};$.fn.strongSlider=function(options){if(this.length===0){return this}var slider={},viewEl=this,el=this.find(".wpmslider-content");if($(el).data("strongSlider")){return}var init=function(){if($(el).data("strongSlider")){return}slider.visibilityInterval=0;slider.hidden=false;var sliderVar=viewEl.data("slider-var");var config={};if(typeof window[sliderVar]!=="undefined"){config=window[sliderVar].config}slider.settings=$.extend({},defaults,config,options);slider.debug=slider.settings.debug;slider.logAs=slider.settings.logAs;if(slider.debug)console.log(slider.logAs,"slider.settings",slider.settings);slider.settings.slideWidth=parseInt(slider.settings.slideWidth);slider.children=el.children(slider.settings.slideSelector);if(slider.children.length<slider.settings.minSlides){slider.settings.minSlides=slider.children.length}if(slider.children.length<slider.settings.maxSlides){slider.settings.maxSlides=slider.children.length}if(slider.settings.randomStart){slider.settings.startSlide=Math.floor(Math.random()*slider.children.length)}slider.active={index:slider.settings.startSlide};slider.carousel=slider.settings.minSlides>1||slider.settings.maxSlides>1;if(slider.carousel){slider.settings.preloadImages="all"}slider.minThreshold=slider.settings.minSlides*slider.settings.slideWidth+(slider.settings.minSlides-1)*slider.settings.slideMargin;slider.maxThreshold=slider.settings.maxSlides*slider.settings.slideWidth+(slider.settings.maxSlides-1)*slider.settings.slideMargin;slider.working=false;slider.controls={};slider.interval=null;slider.animProp=slider.settings.mode==="vertical"?"top":"left";slider.usingCSS=slider.settings.useCSS&&slider.settings.mode!=="fade"&&function(){var div=document.createElement("div");var props=["WebkitPerspective","MozPerspective","OPerspective","msPerspective"];for(var i=0;i<props.length;i++){if(div.style[props[i]]!==undefined){slider.cssPrefix=props[i].replace("Perspective","").toLowerCase();slider.animProp="-"+slider.cssPrefix+"-transform";return true}}return false}();if(slider.settings.mode==="vertical"){slider.settings.maxSlides=slider.settings.minSlides}el.data("origStyle",el.attr("style"));el.children(slider.settings.slideSelector).each(function(){$(this).data("origStyle",$(this).attr("style"))});if(!el.getSlideCount()){return}if(slider.settings.imagesLoaded){viewEl.imagesLoaded(function(){initVisibilityCheck()})}else{initVisibilityCheck()}};var reallyVisible=function(){return viewEl.is(":visible")&&viewEl.css("visibility")!=="hidden"};var compatCheck=function(){if(slider.settings.compat.lazyload){var inProgress=false;for(var i=0,len=slider.settings.compat.lazyload.classes.length;i<len;i++){var startClass=slider.settings.compat.lazyload.classes[i].start;var finishClass=slider.settings.compat.lazyload.classes[i].finish;if(startClass&&finishClass){if(viewEl.find("img."+startClass).length&&!viewEl.find("img."+finishClass).length){inProgress=true}}else if(startClass){if(viewEl.find("img."+startClass).length){inProgress=true}}else if(finishClass){if(!viewEl.find("img."+finishClass).length){inProgress=true}}}if(inProgress){if(slider.debug)console.log(slider.logAs,"lazy loading...");return false}}if(slider.debug)console.log(slider.logAs,"compat check complete");return true};var initVisibilityCheck=function(){if(reallyVisible()&&compatCheck()){clearInterval(slider.visibilityInterval);setup()}else{if(slider.visibilityInterval===0){slider.visibilityInterval=setInterval(initVisibilityCheck,1e3*4)}}};var setup=function(){var preloadSelector=slider.children.eq(slider.settings.startSlide);el.wrap('<div class="'+slider.settings.wrapperClass+'"><div class="wpmslider-viewport"></div></div>');slider.viewport=el.parent();if(slider.settings.ariaLive){slider.viewport.attr("aria-live","polite")}slider.loader=$('<div class="wpmslider-loading" />');slider.viewport.prepend(slider.loader);el.css({width:slider.settings.mode==="horizontal"?slider.children.length*1e3+215+"%":"auto",position:"relative"});if(slider.usingCSS&&slider.settings.easing){el.css("-"+slider.cssPrefix+"-transition-timing-function",slider.settings.easing)}else if(!slider.settings.easing){slider.settings.easing="swing"}slider.viewport.css({width:"100%",overflow:"hidden",position:"relative"});slider.viewport.parent().css({maxWidth:getViewportMaxWidth()});if(!slider.settings.pager&&!slider.settings.controls){slider.viewport.parent().css({margin:"0 auto 0px"})}slider.children.css({float:slider.settings.mode==="horizontal"?"left":"none",position:"relative"});slider.children.css("width",getSlideWidth());if(slider.settings.mode==="horizontal"&&slider.settings.slideMargin>0){slider.children.css("marginRight",slider.settings.slideMargin)}if(slider.settings.mode==="vertical"&&slider.settings.slideMargin>0){slider.children.css("marginBottom",slider.settings.slideMargin)}if(slider.settings.mode==="fade"){slider.children.css({position:"absolute",zIndex:0,display:"none"});slider.children.eq(slider.settings.startSlide).css({zIndex:slider.settings.slideZIndex,display:"block"})}else{slider.children.css({display:"block"})}slider.controls.el=$('<div class="wpmslider-controls" />');if(slider.settings.captions){appendCaptions()}slider.active.last=slider.settings.startSlide===getPagerQty()-1;if(slider.settings.preloadImages==="all"){preloadSelector=slider.children}if(slider.settings.controls){appendControlPrev()}if(slider.settings.auto&&slider.settings.autoControls){appendControlsAuto()}if(slider.settings.pager){appendPager()}if(slider.settings.controls){appendControlNext()}if(slider.settings.controls||slider.settings.autoControls||slider.settings.pager){slider.viewport.after(slider.controls.el)}start()};var start=function(){if(slider.settings.infiniteLoop&&slider.settings.mode!=="fade"){var slice=slider.settings.mode==="vertical"?slider.settings.minSlides:slider.settings.maxSlides;var sliceAppend=slider.children.slice(0,slice).clone(true).addClass("wpmslider-clone");var slicePrepend=slider.children.slice(-slice).clone(true).addClass("wpmslider-clone");if(slider.settings.ariaHidden){sliceAppend.attr("aria-hidden",true);slicePrepend.attr("aria-hidden",true)}el.append(sliceAppend).prepend(slicePrepend)}slider.loader.remove();setSlidePosition();if(slider.settings.mode==="vertical"){slider.settings.adaptiveHeight=true}slider.viewport.height(getViewportHeight());if(slider.settings.stretch){setSlideHeight()}el.redrawSlider();slider.settings.onSliderLoad.call(el,slider.active.index);slider.initialized=true;slider.visibilityInterval=setInterval(visibilityCheck,500);if(slider.settings.responsive){attachListeners()}if(slider.settings.auto&&slider.settings.autoStart&&(getPagerQty()>1||slider.settings.autoSlideForOnePage)){initAuto()}if(slider.settings.pager){updatePagerActive(slider.settings.startSlide)}if(slider.settings.controls){updateDirectionControls()}if(slider.settings.touchEnabled){initTouch()}if(slider.settings.keyboardEnabled){$(document).keydown(keyPress)}};var attachListeners=function(){window.addEventListener("resize",updateLayout,false);window.addEventListener("orientationchange",updateLayout,false);window.addEventListener("blur",function(){pauseEvent("blur")});window.addEventListener("focus",function(){playEvent("blur")})};var updateLayout=_.debounce(function(){resizeWindow()},250);var visibilityCheck=function(){if(!slider.settings.auto){return}if(!reallyVisible()){pauseEvent("hide")}else{playEvent("hide")}if(!verge.inViewport(el)){pauseEvent("scroll")}else{playEvent("scroll")}};var pauseEvent=function(action){if(slider.interval){el.stopAuto(true);slider.autoPaused=action;if(slider.debug)console.log(slider.logAs,"pause",action)}};var playEvent=function(action){if(slider.autoPaused===action){el.startAuto(true);slider.autoPaused=null;if(slider.debug)console.log(slider.logAs,"play",action)}};var setSlideHeight=function(){var heights=slider.children.map(function(){return jQuery(this).actual("outerHeight")}).get();var maxHeight=arrayMax(heights);slider.children.height(maxHeight)};var arrayMax=function(array){return Math.max.apply(Math,array)};var getViewportHeight=function(){var height=0;var children=$();if(slider.settings.mode!=="vertical"&&!slider.settings.adaptiveHeight){children=slider.children}else{if(!slider.carousel){children=slider.children.eq(slider.active.index)}else{var currentIndex=slider.settings.moveSlides===1?slider.active.index:slider.active.index*getMoveBy();children=slider.children.eq(currentIndex);for(var i=1;i<=slider.settings.maxSlides-1;i++){if(currentIndex+i>=slider.children.length){children=children.add(slider.children.eq(i-1))}else{children=children.add(slider.children.eq(currentIndex+i))}}}}if(slider.settings.mode==="vertical"){children.each(function(index){height+=$(this).outerHeight()});if(slider.settings.slideMargin>0){height+=slider.settings.slideMargin*(slider.settings.minSlides-1)}}else{height=Math.max.apply(Math,children.map(function(){return $(this).outerHeight(false)}).get())}if(slider.viewport.css("box-sizing")==="border-box"){height+=parseFloat(slider.viewport.css("padding-top"))+parseFloat(slider.viewport.css("padding-bottom"))+parseFloat(slider.viewport.css("border-top-width"))+parseFloat(slider.viewport.css("border-bottom-width"))}else if(slider.viewport.css("box-sizing")==="padding-box"){height+=parseFloat(slider.viewport.css("padding-top"))+parseFloat(slider.viewport.css("padding-bottom"))}return height};var getViewportMaxWidth=function(){var width="100%";if(slider.settings.slideWidth>0){if(slider.settings.mode==="horizontal"){width=slider.settings.maxSlides*slider.settings.slideWidth+(slider.settings.maxSlides-1)*slider.settings.slideMargin}else{width=slider.settings.slideWidth}}return width};var getSlideWidth=function(){var newElWidth=slider.settings.slideWidth,wrapWidth=slider.viewport.width();if(slider.settings.slideWidth===0||slider.settings.slideWidth>wrapWidth&&!slider.carousel||slider.settings.mode==="vertical"){newElWidth=wrapWidth}else if(slider.settings.maxSlides>1&&slider.settings.mode==="horizontal"){if(wrapWidth>slider.maxThreshold){return newElWidth}else if(wrapWidth<slider.minThreshold){newElWidth=(wrapWidth-slider.settings.slideMargin*(slider.settings.minSlides-1))/slider.settings.minSlides}else if(slider.settings.shrinkItems){newElWidth=Math.floor((wrapWidth+slider.settings.slideMargin)/Math.ceil((wrapWidth+slider.settings.slideMargin)/(newElWidth+slider.settings.slideMargin))-slider.settings.slideMargin)}}return newElWidth};var getNumberSlidesShowing=function(){var slidesShowing=1,childWidth=null;if(slider.settings.mode==="horizontal"&&slider.settings.slideWidth>0){if(slider.viewport.width()<slider.minThreshold){slidesShowing=slider.settings.minSlides}else if(slider.viewport.width()>slider.maxThreshold){slidesShowing=slider.settings.maxSlides}else{childWidth=slider.children.first().width()+slider.settings.slideMargin;slidesShowing=Math.floor((slider.viewport.width()+slider.settings.slideMargin)/childWidth)}}else if(slider.settings.mode==="vertical"){slidesShowing=slider.settings.minSlides}return slidesShowing};var getPagerQty=function(){var pagerQty=0,breakPoint=0,counter=0;if(slider.settings.moveSlides>0){if(slider.settings.infiniteLoop){pagerQty=Math.ceil(slider.children.length/getMoveBy())}else{while(breakPoint<slider.children.length){++pagerQty;breakPoint=counter+getNumberSlidesShowing();counter+=slider.settings.moveSlides<=getNumberSlidesShowing()?slider.settings.moveSlides:getNumberSlidesShowing()}}}else{pagerQty=Math.ceil(slider.children.length/getNumberSlidesShowing())}return pagerQty};var getMoveBy=function(){if(slider.settings.moveSlides>0&&slider.settings.moveSlides<=getNumberSlidesShowing()){return slider.settings.moveSlides}return getNumberSlidesShowing()};var setSlidePosition=function(){var position,lastChild,lastShowingIndex;if(slider.children.length>slider.settings.maxSlides&&slider.active.last&&!slider.settings.infiniteLoop){if(slider.settings.mode==="horizontal"){lastChild=slider.children.last();position=lastChild.position();setPositionProperty(-(position.left-(slider.viewport.width()-lastChild.outerWidth())),"reset",0)}else if(slider.settings.mode==="vertical"){lastShowingIndex=slider.children.length-slider.settings.minSlides;position=slider.children.eq(lastShowingIndex).position();setPositionProperty(-position.top,"reset",0)}}else{position=slider.children.eq(slider.active.index*getMoveBy()).position();if(slider.active.index===getPagerQty()-1){slider.active.last=true}if(position!==undefined){if(slider.settings.mode==="horizontal"){setPositionProperty(-position.left,"reset",0)}else if(slider.settings.mode==="vertical"){setPositionProperty(-position.top,"reset",0)}else if(slider.settings.mode==="none"){setPositionProperty(-position.top,"reset",0)}}}};var setPositionProperty=function(value,type,duration,params){var animateObj,propValue;if(slider.usingCSS){if(slider.settings.mode==="vertical"){propValue="translateY("+value+"px)"}else if(slider.settings.mode==="horizontal"){propValue="translateX("+value+"px"}else if(slider.settings.mode==="none"){propValue="translateY("+value+"px)";duration=0}el.css("-"+slider.cssPrefix+"-transition-duration",duration/1e3+"s");if(type==="slide"){el.css(slider.animProp,propValue);if(duration!==0){el.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd",function(e){if(!$(e.target).is(el)){return}el.off("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd");updateAfterSlideTransition()})}else{updateAfterSlideTransition()}}else if(type==="reset"){el.css(slider.animProp,propValue)}}else{animateObj={};animateObj[slider.animProp]=value;if(type==="slide"){el.animate(animateObj,duration,slider.settings.easing,function(){updateAfterSlideTransition()})}else if(type==="reset"){el.css(slider.animProp,value)}}};var populatePager=function(){var pagerHtml="",linkContent="",pagerQty=getPagerQty();for(var i=0;i<pagerQty;i++){linkContent="";if(slider.settings.buildPager){if(slider.settings.buildPager==="icons"){linkContent=""}if($.isFunction(slider.settings.buildPager)||slider.settings.pagerCustom){linkContent=slider.settings.buildPager(i)}slider.pagerEl.addClass("wpmslider-custom-pager")}else{linkContent=i+1;slider.pagerEl.addClass("wpmslider-default-pager")}pagerHtml+='<div class="wpmslider-pager-item"><a href="" data-slide-index="'+i+'" class="wpmslider-pager-link">'+linkContent+"</a></div>"}slider.pagerEl.html(pagerHtml)};var appendPager=function(){if(!slider.settings.pagerCustom){slider.pagerEl=$('<div class="wpmslider-pager" />');if(slider.settings.pagerSelector){$(slider.settings.pagerSelector).html(slider.pagerEl)}else{slider.controls.el.addClass("wpmslider-has-pager").append(slider.pagerEl)}populatePager()}else{slider.pagerEl=$(slider.settings.pagerCustom)}slider.pagerEl.on("click touchend","a",clickPagerBind)};var appendControlPrev=function(){slider.controls.prev=$('<a class="wpmslider-prev" href="">'+slider.settings.prevText+"</a>");slider.controls.prev.on("click touchend",clickPrevBind);if(slider.settings.prevSelector){$(slider.settings.prevSelector).append(slider.controls.prev)}if(!slider.settings.prevSelector){slider.controls.directionEl=$('<div class="wpmslider-controls-direction" />');slider.controls.directionEl.append(slider.controls.prev);slider.controls.el.addClass("wpmslider-has-controls-direction").append(slider.controls.directionEl)}};var appendControlNext=function(){slider.controls.next=$('<a class="wpmslider-next" href="">'+slider.settings.nextText+"</a>");slider.controls.next.on("click touchend",clickNextBind);if(slider.settings.nextSelector){$(slider.settings.nextSelector).append(slider.controls.next)}if(!slider.settings.nextSelector){slider.controls.directionEl=$('<div class="wpmslider-controls-direction" />');slider.controls.directionEl.append(slider.controls.next);slider.controls.el.addClass("wpmslider-has-controls-direction").append(slider.controls.directionEl)}};var appendControlsAuto=function(){slider.controls.start=$('<div class="wpmslider-controls-auto-item"><a class="wpmslider-start" href="">'+slider.settings.startText+"</a></div>");slider.controls.stop=$('<div class="wpmslider-controls-auto-item"><a class="wpmslider-stop" href="">'+slider.settings.stopText+"</a></div>");slider.controls.autoEl=$('<div class="wpmslider-controls-auto" />');slider.controls.autoEl.on("click",".wpmslider-start",clickStartBind);slider.controls.autoEl.on("click",".wpmslider-stop",clickStopBind);if(slider.settings.autoControlsCombine){slider.controls.autoEl.append(slider.controls.start)}else{slider.controls.autoEl.append(slider.controls.start).append(slider.controls.stop)}if(slider.settings.autoControlsSelector){$(slider.settings.autoControlsSelector).html(slider.controls.autoEl)}else{slider.controls.el.addClass("wpmslider-has-controls-auto").append(slider.controls.autoEl)}updateAutoControls(slider.settings.autoStart?"stop":"start")};var appendCaptions=function(){slider.children.each(function(index){var title=$(this).find("img:first").attr("title");if(title!==undefined&&(""+title).length){$(this).append('<div class="wpmslider-caption"><span>'+title+"</span></div>")}})};var clickNextBind=function(e){e.preventDefault();e.stopPropagation();if(slider.controls.el.hasClass("disabled")){return}if(slider.settings.auto&&slider.settings.stopAutoOnClick){if(slider.debug)console.log(slider.logAs,"stop on navigation");el.stopAuto()}el.goToNextSlide()};var clickPrevBind=function(e){e.preventDefault();e.stopPropagation();if(slider.controls.el.hasClass("disabled")){return}if(slider.settings.auto&&slider.settings.stopAutoOnClick){if(slider.debug)console.log(slider.logAs,"stop on navigation");el.stopAuto()}el.goToPrevSlide()};var clickStartBind=function(e){el.startAuto();e.preventDefault();e.stopPropagation()};var clickStopBind=function(e){el.stopAuto();e.preventDefault();e.stopPropagation()};var clickPagerBind=function(e){var pagerLink,pagerIndex;e.preventDefault();e.stopPropagation();if(slider.controls.el.hasClass("disabled")){return}if(slider.settings.auto&&slider.settings.stopAutoOnClick){if(slider.debug)console.log(slider.logAs,"stop on navigation");el.stopAuto()}pagerLink=$(e.currentTarget);if(pagerLink.attr("data-slide-index")!==undefined){pagerIndex=parseInt(pagerLink.attr("data-slide-index"));if(pagerIndex!==slider.active.index){el.goToSlide(pagerIndex)}}};var updatePagerActive=function(slideIndex){var len=slider.children.length;if(slider.settings.pagerType==="short"){if(slider.settings.maxSlides>1){len=Math.ceil(slider.children.length/slider.settings.maxSlides)}slider.pagerEl.html(slideIndex+1+slider.settings.pagerShortSeparator+len);return}slider.pagerEl.find("a").removeClass("active");slider.pagerEl.each(function(i,el){$(el).find("a").eq(slideIndex).addClass("active")})};var updateAfterSlideTransition=function(){if(slider.settings.infiniteLoop){var position="";if(slider.active.index===0){position=slider.children.eq(0).position()}else if(slider.active.index===getPagerQty()-1&&slider.carousel){position=slider.children.eq((getPagerQty()-1)*getMoveBy()).position()}else if(slider.active.index===slider.children.length-1){position=slider.children.eq(slider.children.length-1).position()}if(position){if(slider.settings.mode==="horizontal"){setPositionProperty(-position.left,"reset",0)}else if(slider.settings.mode==="vertical"){setPositionProperty(-position.top,"reset",0)}}}slider.working=false;slider.settings.onSlideAfter.call(el,slider.children.eq(slider.active.index),slider.oldIndex,slider.active.index)};var updateAutoControls=function(state){if(slider.settings.autoControlsCombine){slider.controls.autoEl.html(slider.controls[state])}else{slider.controls.autoEl.find("a").removeClass("active");slider.controls.autoEl.find("a:not(.wpmslider-"+state+")").addClass("active")}};var updateDirectionControls=function(){if(getPagerQty()===1){slider.controls.prev.addClass("disabled");slider.controls.next.addClass("disabled")}else if(!slider.settings.infiniteLoop&&slider.settings.hideControlOnEnd){if(slider.active.index===0){slider.controls.prev.addClass("disabled");slider.controls.next.removeClass("disabled")}else if(slider.active.index===getPagerQty()-1){slider.controls.next.addClass("disabled");slider.controls.prev.removeClass("disabled")}else{slider.controls.prev.removeClass("disabled");slider.controls.next.removeClass("disabled")}}};var initAuto=function(){if(slider.settings.autoDelay>0){var timeout=setTimeout(el.startAuto,slider.settings.autoDelay)}else{el.startAuto()}if(slider.settings.autoHover){el.hover(function(){pauseEvent("hover")},function(){playEvent("hover")})}};var keyPress=function(e){var activeElementTag=document.activeElement.tagName.toLowerCase(),tagFilters="input|textarea",p=new RegExp(activeElementTag,["i"]),result=p.exec(tagFilters);if(result===null&&verge.inViewport(el)){if(e.keyCode===39){clickNextBind(e);return false}else if(e.keyCode===37){clickPrevBind(e);return false}}};var initTouch=function(){slider.touch={start:{x:0,y:0},end:{x:0,y:0}};slider.viewport.on("touchstart MSPointerDown pointerdown",onTouchStart);slider.viewport.on("click",".wpmslider a",function(e){if(slider.viewport.hasClass("click-disabled")){e.preventDefault();e.stopPropagation();slider.viewport.removeClass("click-disabled")}})};var onTouchStart=function(e){slider.controls.el.addClass("disabled");if(slider.working){e.preventDefault();e.stopPropagation();slider.controls.el.removeClass("disabled")}else{slider.touch.originalPos=el.position();var orig=e.originalEvent,touchPoints=typeof orig.changedTouches!=="undefined"?orig.changedTouches:[orig];var chromePointerEvents=typeof PointerEvent==="function";if(chromePointerEvents){if(orig.pointerId===undefined){return}}slider.touch.start.x=touchPoints[0].pageX;slider.touch.start.y=touchPoints[0].pageY;if(slider.viewport.get(0).setPointerCapture){slider.pointerId=orig.pointerId;if(slider.pointerId===1){slider.viewport.get(0).setPointerCapture(slider.pointerId)}}slider.viewport.on("touchmove MSPointerMove pointermove",onTouchMove);slider.viewport.on("touchend MSPointerUp pointerup",onTouchEnd);slider.viewport.on("MSPointerCancel pointercancel",onPointerCancel)}};var onPointerCancel=function(e){setPositionProperty(slider.touch.originalPos.left,"reset",0);slider.controls.el.removeClass("disabled");slider.viewport.off("MSPointerCancel pointercancel",onPointerCancel);slider.viewport.off("touchmove MSPointerMove pointermove",onTouchMove);slider.viewport.off("touchend MSPointerUp pointerup",onTouchEnd);if(slider.viewport.get(0).releasePointerCapture){slider.viewport.get(0).releasePointerCapture(slider.pointerId)}};var onTouchMove=function(e){var orig=e.originalEvent,touchPoints=typeof orig.changedTouches!=="undefined"?orig.changedTouches:[orig],xMovement=Math.abs(touchPoints[0].pageX-slider.touch.start.x),yMovement=Math.abs(touchPoints[0].pageY-slider.touch.start.y),value=0,change=0;if(xMovement*3>yMovement&&slider.settings.preventDefaultSwipeX){e.preventDefault();e.stopPropagation()}else if(yMovement*3>xMovement&&slider.settings.preventDefaultSwipeY){e.preventDefault();e.stopPropagation()}if(slider.settings.mode!=="fade"&&slider.settings.oneToOneTouch){if(slider.settings.mode==="horizontal"){change=touchPoints[0].pageX-slider.touch.start.x;value=slider.touch.originalPos.left+change}else{change=touchPoints[0].pageY-slider.touch.start.y;value=slider.touch.originalPos.top+change}setPositionProperty(value,"reset",0)}};var onTouchEnd=function(e){slider.viewport.off("touchmove MSPointerMove pointermove",onTouchMove);slider.controls.el.removeClass("disabled");var orig=e.originalEvent,touchPoints=typeof orig.changedTouches!=="undefined"?orig.changedTouches:[orig],value=0,distance=0;slider.touch.end.x=touchPoints[0].pageX;slider.touch.end.y=touchPoints[0].pageY;if(slider.settings.mode==="fade"){distance=Math.abs(slider.touch.start.x-slider.touch.end.x);if(distance>=slider.settings.swipeThreshold){if(slider.touch.start.x>slider.touch.end.x){el.goToNextSlide()}else{el.goToPrevSlide()}el.stopAuto()}}else{if(slider.settings.mode==="horizontal"){distance=slider.touch.end.x-slider.touch.start.x;value=slider.touch.originalPos.left}else{distance=slider.touch.end.y-slider.touch.start.y;value=slider.touch.originalPos.top}if(!slider.settings.infiniteLoop&&(slider.active.index===0&&distance>0||slider.active.last&&distance<0)){setPositionProperty(value,"reset",200)}else{if(Math.abs(distance)>=slider.settings.swipeThreshold){if(distance<0){el.goToNextSlide()}else{el.goToPrevSlide()}el.stopAuto()}else{setPositionProperty(value,"reset",200)}}}slider.viewport.off("touchend MSPointerUp pointerup",onTouchEnd);if(slider.viewport.get(0).releasePointerCapture){slider.viewport.get(0).releasePointerCapture(slider.pointerId)}};var resizeWindow=function(e){if(!slider.initialized){return}if(slider.working){window.setTimeout(resizeWindow,10)}else{el.redrawSlider();slider.settings.onSliderResize.call(el,slider.active.index)}};var applyAriaHiddenAttributes=function(startVisibleIndex){var numberOfSlidesShowing=getNumberSlidesShowing();if(slider.settings.ariaHidden){slider.children.attr("aria-hidden","true");slider.children.slice(startVisibleIndex,startVisibleIndex+numberOfSlidesShowing).attr("aria-hidden","false")}};var setSlideIndex=function(slideIndex){if(slideIndex<0){if(slider.settings.infiniteLoop){return getPagerQty()-1}else{return slider.active.index}}else if(slideIndex>=getPagerQty()){if(slider.settings.infiniteLoop){return 0}else{return slider.active.index}}else{return slideIndex}};el.goToSlide=function(slideIndex,direction){var performTransition,moveBy=0,position={left:0,top:0},lastChild=null,lastShowingIndex,eq,value,requestEl;slider.oldIndex=slider.active.index;slider.active.index=setSlideIndex(slideIndex);if(slider.working||slider.active.index===slider.oldIndex){return}slider.working=true;performTransition=slider.settings.onSlideBefore.call(el,slider.children.eq(slider.active.index),slider.oldIndex,slider.active.index);if(typeof performTransition!=="undefined"&&!performTransition){slider.active.index=slider.oldIndex;slider.working=false;return}if(direction==="next"){if(!slider.settings.onSlideNext.call(el,slider.children.eq(slider.active.index),slider.oldIndex,slider.active.index)){performTransition=false}}else if(direction==="prev"){if(!slider.settings.onSlidePrev.call(el,slider.children.eq(slider.active.index),slider.oldIndex,slider.active.index)){performTransition=false}}slider.active.last=slider.active.index>=getPagerQty()-1;if(slider.settings.pager||slider.settings.pagerCustom){updatePagerActive(slider.active.index)}if(slider.settings.controls){updateDirectionControls()}if(slider.settings.mode==="fade"){if(slider.settings.adaptiveHeight&&slider.viewport.height()!==getViewportHeight()){slider.viewport.animate({height:getViewportHeight()},slider.settings.adaptiveHeightSpeed)}slider.children.filter(":visible").fadeOut(slider.settings.speed).css({zIndex:0});slider.children.eq(slider.active.index).css("zIndex",slider.settings.slideZIndex+1).fadeIn(slider.settings.speed,function(){$(this).css("zIndex",slider.settings.slideZIndex);updateAfterSlideTransition()})}else{if(slider.settings.adaptiveHeight&&slider.viewport.height()!==getViewportHeight()){slider.viewport.animate({height:getViewportHeight()},slider.settings.adaptiveHeightSpeed)}if(!slider.settings.infiniteLoop&&slider.carousel&&slider.active.last){if(slider.settings.mode==="horizontal"){lastChild=slider.children.eq(slider.children.length-1);position=lastChild.position();moveBy=slider.viewport.width()-lastChild.outerWidth()}else{lastShowingIndex=slider.children.length-slider.settings.minSlides;position=slider.children.eq(lastShowingIndex).position()}}else if(slider.carousel&&slider.active.last&&direction==="prev"){eq=slider.settings.moveSlides===1?slider.settings.maxSlides-getMoveBy():(getPagerQty()-1)*getMoveBy()-(slider.children.length-slider.settings.maxSlides);lastChild=el.children(".wpmslider-clone").eq(eq);position=lastChild.position()}else if(direction==="next"&&slider.active.index===0){position=el.find("> .wpmslider-clone").eq(slider.settings.maxSlides).position();slider.active.last=false}else if(slideIndex>=0){requestEl=slideIndex*parseInt(getMoveBy());position=slider.children.eq(requestEl).position()}if(typeof position!=="undefined"){if(slider.settings.mode==="horizontal"){value=-(position.left-moveBy)}else{value=-position.top}setPositionProperty(value,"slide",slider.settings.speed)}else{slider.working=false}}if(slider.settings.ariaHidden){applyAriaHiddenAttributes(slider.active.index*getMoveBy())}};el.goToNextSlide=function(){if(!slider.settings.infiniteLoop&&slider.active.last){return}var pagerIndex=parseInt(slider.active.index)+1;el.goToSlide(pagerIndex,"next")};el.goToPrevSlide=function(){if(!slider.settings.infiniteLoop&&slider.active.index===0){return}var pagerIndex=parseInt(slider.active.index)-1;el.goToSlide(pagerIndex,"prev")};el.startAuto=function(preventControlUpdate){if(slider.interval){return}slider.interval=setInterval(function(){if(slider.settings.autoDirection==="next"){el.goToNextSlide()}else{el.goToPrevSlide()}},slider.settings.pause);if(slider.settings.autoControls&&preventControlUpdate!==true){updateAutoControls("stop")}};el.stopAuto=function(preventControlUpdate){if(!slider.interval){return}clearInterval(slider.interval);slider.interval=null;if(slider.settings.autoControls&&preventControlUpdate!==true){updateAutoControls("start")}};el.getCurrentSlide=function(){return slider.active.index};el.getCurrentSlideElement=function(){return slider.children.eq(slider.active.index)};el.getSlideElement=function(index){return slider.children.eq(index)};el.getSlideCount=function(){return slider.children.length};el.isWorking=function(){return slider.working};el.redrawSlider=function(){slider.children.add(el.find(".wpmslider-clone")).outerWidth(getSlideWidth());slider.viewport.css("height",getViewportHeight());setSlidePosition();if(slider.active.last){slider.active.index=getPagerQty()-1}if(slider.active.index>=getPagerQty()){slider.active.last=true}if(slider.settings.pager&&!slider.settings.pagerCustom){populatePager();updatePagerActive(slider.active.index)}if(slider.settings.ariaHidden){applyAriaHiddenAttributes(slider.active.index*getMoveBy())}};el.destroySlider=function(){if(!slider.initialized){return}slider.initialized=false;$(".wpmslider-clone",this).remove();slider.children.each(function(){if($(this).data("origStyle")!==undefined){$(this).attr("style",$(this).data("origStyle"))}else{$(this).removeAttr("style")}});if($(this).data("origStyle")!==undefined){this.attr("style",$(this).data("origStyle"))}else{$(this).removeAttr("style")}$(this).unwrap().unwrap();if(slider.controls.el){slider.controls.el.remove()}if(slider.controls.next){slider.controls.next.remove()}if(slider.controls.prev){
2
+ slider.controls.prev.remove()}if(slider.pagerEl&&slider.settings.controls&&!slider.settings.pagerCustom){slider.pagerEl.remove()}$(".wpmslider-caption",this).remove();if(slider.controls.autoEl){slider.controls.autoEl.remove()}clearInterval(slider.interval);clearInterval(slider.visibilityInterval);if(slider.settings.responsive){$(window).off("resize",resizeWindow)}if(slider.settings.keyboardEnabled){$(document).off("keydown",keyPress)}$(this).removeData("strongSlider")};el.reloadSlider=function(settings){if(settings!==undefined){options=settings}el.destroySlider();init();$(el).data("strongSlider",this)};init();$(el).data("strongSlider",this);viewEl.attr("data-state","init");if(slider.debug)console.log(slider.logAs,"viewport",verge.viewportW(),"x",verge.viewportH());return this}})(jQuery);
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: cdillon27
3
  Tags: testimonials, testimonial slider, testimonial form, reviews, star ratings
4
  Requires at least: 3.7
5
  Tested up to: 4.9.5
6
- Stable tag: 2.30.9
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -74,7 +74,7 @@ A variety of templates are included that work well in most themes.
74
 
75
  For ultimate control and seamless integration, copy any template to your theme and customize it.
76
 
77
- Use the template function to display a view in your template file:
78
 
79
  `<?php if ( function_exists( 'strong_testimonials_view' ) ) {
80
  strong_testimonials_view( $id );
@@ -136,6 +136,8 @@ Activate the plugin. Look for "Testimonials" in the admin menu.
136
 
137
  `Read some of our [testimonial_count] testimonials!`
138
 
 
 
139
  = Can I add testimonials from YouTube, Twitter, Instagram and Facebook? =
140
 
141
  Yes. The plugin supports the [WordPress embed](https://codex.wordpress.org/Embeds) feature for inserting testimonials from [these sources](https://codex.wordpress.org/Embeds#Does_This_Work_With_Any_URL.3F).
@@ -178,9 +180,9 @@ Undeniably, yes.
178
 
179
  This [screenshot](http://www.screencast.com/t/TPMRWM0yug) shows where I immediately start looking for clues before asking for more information and potentially waiting hours or days for a response (it happens).
180
 
181
- I can determine what theme you're using, what plugins are active, whether you're using any caching/minification/optimization (do you need to clear your cache?), if there are any JavaScript errors in your theme or another plugin (more common than you may think), and somewhat how the testimonial view is configured.
182
 
183
- If you prefer not to post your URL publicly, start a private support ticket at [support.strongplugins.com](https://support.strongplugins.com).
184
 
185
  == Screenshots ==
186
 
@@ -195,11 +197,24 @@ If you prefer not to post your URL publicly, start a private support ticket at [
195
 
196
  == Changelog ==
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  = 2.30.9 - May 6, 2018 =
199
  * Fix bug in add-on activation process.
200
 
201
  = 2.30.8 - April 26, 2018 =
202
- * Fix incorrect textdomains.
203
  * Fix bug in form validation translation files.
204
  * Remove obsolete German translation.
205
  * Update translation files.
@@ -258,5 +273,5 @@ See changelog.txt for previous versions.
258
 
259
  == Upgrade Notice ==
260
 
261
- = 2.30.9 =
262
- Better template options. Improved compatibility. Minor bug fixes.
3
  Tags: testimonials, testimonial slider, testimonial form, reviews, star ratings
4
  Requires at least: 3.7
5
  Tested up to: 4.9.5
6
+ Stable tag: 2.31
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
74
 
75
  For ultimate control and seamless integration, copy any template to your theme and customize it.
76
 
77
+ The template function will add a view to your custome theme templates:
78
 
79
  `<?php if ( function_exists( 'strong_testimonials_view' ) ) {
80
  strong_testimonials_view( $id );
136
 
137
  `Read some of our [testimonial_count] testimonials!`
138
 
139
+ [testimonial_average_rating] - To display the average rating of all your testimonials. Includes stars! *(Documentation coming soon.)*
140
+
141
  = Can I add testimonials from YouTube, Twitter, Instagram and Facebook? =
142
 
143
  Yes. The plugin supports the [WordPress embed](https://codex.wordpress.org/Embeds) feature for inserting testimonials from [these sources](https://codex.wordpress.org/Embeds#Does_This_Work_With_Any_URL.3F).
180
 
181
  This [screenshot](http://www.screencast.com/t/TPMRWM0yug) shows where I immediately start looking for clues before asking for more information and potentially waiting hours or days for a response (it happens).
182
 
183
+ I can usually determine what theme you're using, what plugins are active, whether you're using any caching/minification/optimization (do you need to clear your cache?), if there are any JavaScript errors in your theme or another plugin (more common than you may think), and somewhat how the testimonial view is configured.
184
 
185
+ If you prefer, start a private support ticket at [support.strongplugins.com](https://support.strongplugins.com).
186
 
187
  == Screenshots ==
188
 
197
 
198
  == Changelog ==
199
 
200
+ = 2.31 - May 15, 2018 =
201
+ * Add `[testimonial_average_rating]` shortcode.
202
+ * Add compatibility option for script controller.
203
+ * Add compatibility option for lazy loading images.
204
+ * Minor template style tweaks for small screens.
205
+ * Use empty star icon instead of full icon in different color.
206
+ * Change default message "Required field" to "Required".
207
+ * Improve exception handling.
208
+ * Improve Pjax compatibility.
209
+ * Apply JavaScript coding standard.
210
+ * Add console logging for slider when `SCRIPT_DEBUG` enabled.
211
+ * Minor admin style tweaks.
212
+
213
  = 2.30.9 - May 6, 2018 =
214
  * Fix bug in add-on activation process.
215
 
216
  = 2.30.8 - April 26, 2018 =
217
+ * Fix incorrect text domains.
218
  * Fix bug in form validation translation files.
219
  * Remove obsolete German translation.
220
  * Update translation files.
273
 
274
  == Upgrade Notice ==
275
 
276
+ = 2.31 =
277
+ New [testimonial_average_rating] shortcode. More compatibility options.
strong-testimonials.php CHANGED
@@ -4,7 +4,7 @@
4
  * Plugin URI: https://strongplugins.com/plugins/strong-testimonials/
5
  * Description: Collect and display your testimonials or reviews.
6
  * Author: Chris Dillon
7
- * Version: 2.30.9
8
  *
9
  * Author URI: https://strongplugins.com/
10
  * Text Domain: strong-testimonials
@@ -34,7 +34,7 @@ if ( ! defined( 'ABSPATH' ) ) {
34
  exit;
35
  }
36
 
37
- define( 'WPMTST_VERSION', '2.30.9' );
38
  define( 'WPMTST_PLUGIN', plugin_basename( __FILE__ ) ); // strong-testimonials/strong-testimonials.php
39
  define( 'WPMTST', dirname( WPMTST_PLUGIN ) ); // strong-testimonials
40
  define( 'STRONGPLUGINS_STORE_URL', 'https://strongplugins.com' );
@@ -45,7 +45,7 @@ if ( ! class_exists( 'Strong_Testimonials' ) ) :
45
  /**
46
  * Main plugin class.
47
  *
48
- * @property Strong_Testimonials_Shortcodes shortcodes
49
  * @property Strong_Testimonials_Render render
50
  * @property Strong_Mail mail
51
  * @property Strong_Templates templates
@@ -61,9 +61,9 @@ final class Strong_Testimonials {
61
  public $plugin_data;
62
 
63
  /**
64
- * @var Strong_Testimonials_Shortcodes
65
  */
66
- public $shortcodes;
67
 
68
  /**
69
  * @var Strong_Testimonials_Render
@@ -190,11 +190,14 @@ final class Strong_Testimonials {
190
  * Instantiate our classes.
191
  */
192
  public function init() {
193
- $this->shortcodes = new Strong_Testimonials_Shortcodes();
194
  $this->render = new Strong_Testimonials_Render();
195
  $this->mail = new Strong_Mail();
196
  $this->templates = new Strong_Templates();
197
  $this->form = new Strong_Testimonials_Form();
 
 
 
198
  }
199
 
200
  /**
@@ -207,7 +210,9 @@ final class Strong_Testimonials {
207
  private function includes() {
208
  require_once WPMTST_INC . 'class-strong-log.php';
209
 
210
- require_once WPMTST_INC . 'class-strong-testimonials-shortcodes.php';
 
 
211
  require_once WPMTST_INC . 'class-strong-testimonials-render.php';
212
  require_once WPMTST_INC . 'class-strong-view.php';
213
  require_once WPMTST_INC . 'class-strong-view-display.php';
@@ -240,6 +245,8 @@ final class Strong_Testimonials {
240
  require_once WPMTST_ADMIN . 'menu/class-strong-testimonials-menu-fields.php';
241
  require_once WPMTST_ADMIN . 'menu/class-strong-testimonials-menu-settings.php';
242
  require_once WPMTST_ADMIN . 'menu/class-strong-testimonials-menu-views.php';
 
 
243
 
244
  require_once WPMTST_ADMIN . 'settings/class-strong-testimonials-settings.php';
245
  require_once WPMTST_ADMIN . 'settings/class-strong-testimonials-settings-general.php';
4
  * Plugin URI: https://strongplugins.com/plugins/strong-testimonials/
5
  * Description: Collect and display your testimonials or reviews.
6
  * Author: Chris Dillon
7
+ * Version: 2.31
8
  *
9
  * Author URI: https://strongplugins.com/
10
  * Text Domain: strong-testimonials
34
  exit;
35
  }
36
 
37
+ define( 'WPMTST_VERSION', '2.31' );
38
  define( 'WPMTST_PLUGIN', plugin_basename( __FILE__ ) ); // strong-testimonials/strong-testimonials.php
39
  define( 'WPMTST', dirname( WPMTST_PLUGIN ) ); // strong-testimonials
40
  define( 'STRONGPLUGINS_STORE_URL', 'https://strongplugins.com' );
45
  /**
46
  * Main plugin class.
47
  *
48
+ * @property Strong_Testimonials_View_Shortcode shortcode
49
  * @property Strong_Testimonials_Render render
50
  * @property Strong_Mail mail
51
  * @property Strong_Templates templates
61
  public $plugin_data;
62
 
63
  /**
64
+ * @var Strong_Testimonials_View_Shortcode
65
  */
66
+ public $shortcode;
67
 
68
  /**
69
  * @var Strong_Testimonials_Render
190
  * Instantiate our classes.
191
  */
192
  public function init() {
193
+ $this->shortcode = new Strong_Testimonials_View_Shortcode();
194
  $this->render = new Strong_Testimonials_Render();
195
  $this->mail = new Strong_Mail();
196
  $this->templates = new Strong_Templates();
197
  $this->form = new Strong_Testimonials_Form();
198
+
199
+ new Strong_Testimonials_Count_Shortcode();
200
+ new Strong_Testimonials_Average_Shortcode();
201
  }
202
 
203
  /**
210
  private function includes() {
211
  require_once WPMTST_INC . 'class-strong-log.php';
212
 
213
+ require_once WPMTST_INC . 'class-strong-testimonials-shortcode.php';
214
+ require_once WPMTST_INC . 'class-strong-testimonials-shortcode-count.php';
215
+ require_once WPMTST_INC . 'class-strong-testimonials-shortcode-average.php';
216
  require_once WPMTST_INC . 'class-strong-testimonials-render.php';
217
  require_once WPMTST_INC . 'class-strong-view.php';
218
  require_once WPMTST_INC . 'class-strong-view-display.php';
245
  require_once WPMTST_ADMIN . 'menu/class-strong-testimonials-menu-fields.php';
246
  require_once WPMTST_ADMIN . 'menu/class-strong-testimonials-menu-settings.php';
247
  require_once WPMTST_ADMIN . 'menu/class-strong-testimonials-menu-views.php';
248
+ require_once WPMTST_ADMIN . 'menu/class-strong-testimonials-menu-shortcodes.php';
249
+ require_once WPMTST_ADMIN . 'class-strong-testimonials-page-shortcodes.php';
250
 
251
  require_once WPMTST_ADMIN . 'settings/class-strong-testimonials-settings.php';
252
  require_once WPMTST_ADMIN . 'settings/class-strong-testimonials-settings-general.php';
templates-scss/bold/content.scss CHANGED
@@ -13,12 +13,13 @@ $template: bold;
13
 
14
  .testimonial {
15
  margin-bottom: 1em;
 
16
  text-align: center;
17
  width: 100%;
18
  }
19
 
20
  .testimonial-inner {
21
- /* custom background color is applied here */
22
  padding: 20px;
23
  border-radius: 3px;
24
  }
@@ -27,8 +28,15 @@ $template: bold;
27
  @include paragraphs;
28
  }
29
 
 
 
 
 
 
 
 
30
  .testimonial-image {
31
- margin: 10px auto 20px;
32
 
33
  img {
34
  border-radius: 3px;
@@ -41,11 +49,6 @@ $template: bold;
41
  }
42
  }
43
 
44
- .testimonial-content {
45
- font-size: 2.2em;
46
- line-height: 1.4;
47
- }
48
-
49
  .testimonial-client {
50
  font-size: 1.2em;
51
  margin-top: 1em;
@@ -101,3 +104,13 @@ $template: bold;
101
  padding-right: 50px;
102
  }
103
  }
 
 
 
 
 
 
 
 
 
 
13
 
14
  .testimonial {
15
  margin-bottom: 1em;
16
+ padding: 0; // theme compat
17
  text-align: center;
18
  width: 100%;
19
  }
20
 
21
  .testimonial-inner {
22
+ // custom background color is applied here
23
  padding: 20px;
24
  border-radius: 3px;
25
  }
28
  @include paragraphs;
29
  }
30
 
31
+ .testimonial-content {
32
+ background: inherit; // theme compat
33
+ font-size: 2em;
34
+ line-height: 1.3;
35
+ padding: 0; // theme compat
36
+ }
37
+
38
  .testimonial-image {
39
+ margin: 0 auto 20px;
40
 
41
  img {
42
  border-radius: 3px;
49
  }
50
  }
51
 
 
 
 
 
 
52
  .testimonial-client {
53
  font-size: 1.2em;
54
  margin-top: 1em;
104
  padding-right: 50px;
105
  }
106
  }
107
+
108
+ /* Responsive
109
+ -----------------------------------------------*/
110
+ @media only screen and (max-width: 640px) {
111
+ .strong-view.#{$template} {
112
+ .testimonial-inner {
113
+ //padding: 20px 0;
114
+ }
115
+ }
116
+ }
templates/bold/content.css CHANGED
@@ -70,11 +70,11 @@ Thanks https://css-tricks.com/minimum-paragraph-widths/
70
  }
71
  .strong-view.bold .testimonial {
72
  margin-bottom: 1em;
 
73
  text-align: center;
74
  width: 100%;
75
  }
76
  .strong-view.bold .testimonial-inner {
77
- /* custom background color is applied here */
78
  padding: 20px;
79
  border-radius: 3px;
80
  }
@@ -86,8 +86,14 @@ Thanks https://css-tricks.com/minimum-paragraph-widths/
86
  margin-bottom: 0;
87
  padding-bottom: 0;
88
  }
 
 
 
 
 
 
89
  .strong-view.bold .testimonial-image {
90
- margin: 10px auto 20px;
91
  }
92
  .strong-view.bold .testimonial-image img {
93
  border-radius: 3px;
@@ -97,10 +103,6 @@ Thanks https://css-tricks.com/minimum-paragraph-widths/
97
  text-decoration: none;
98
  box-shadow: none;
99
  }
100
- .strong-view.bold .testimonial-content {
101
- font-size: 2.2em;
102
- line-height: 1.4;
103
- }
104
  .strong-view.bold .testimonial-client {
105
  font-size: 1.2em;
106
  margin-top: 1em;
@@ -212,3 +214,6 @@ Thanks https://css-tricks.com/minimum-paragraph-widths/
212
  padding-left: 50px;
213
  padding-right: 50px;
214
  }
 
 
 
70
  }
71
  .strong-view.bold .testimonial {
72
  margin-bottom: 1em;
73
+ padding: 0;
74
  text-align: center;
75
  width: 100%;
76
  }
77
  .strong-view.bold .testimonial-inner {
 
78
  padding: 20px;
79
  border-radius: 3px;
80
  }
86
  margin-bottom: 0;
87
  padding-bottom: 0;
88
  }
89
+ .strong-view.bold .testimonial-content {
90
+ background: inherit;
91
+ font-size: 2em;
92
+ line-height: 1.3;
93
+ padding: 0;
94
+ }
95
  .strong-view.bold .testimonial-image {
96
+ margin: 0 auto 20px;
97
  }
98
  .strong-view.bold .testimonial-image img {
99
  border-radius: 3px;
103
  text-decoration: none;
104
  box-shadow: none;
105
  }
 
 
 
 
106
  .strong-view.bold .testimonial-client {
107
  font-size: 1.2em;
108
  margin-top: 1em;
214
  padding-left: 50px;
215
  padding-right: 50px;
216
  }
217
+
218
+ /* Responsive
219
+ -----------------------------------------------*/