PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 6.2.2
Jetpack – WP Security, Backup, Speed, & Growth v6.2.2
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / shortcodes / presentations.php

presentations.php in Jetpack – WP Security, Backup, Speed, & Growth 6.2.2, at modules/shortcodes/presentations.php

462 lines 14.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Presentations
4 Plugin URI: http://automattic.com/wordpress-plugins/
5 Description: Presentations plugin based on the work done by <a href="http://darylkoop.com/">Daryl Koopersmith</a>. Powered by jmpress.js
6 Version: 0.2
7 Author: Automattic
8 Author URI: http://automattic.com/wordpress-plugins/
9
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25
26 /**
27 * Known issues:
28 *
29 * - IE 7/8 are not supported by jmpress and presentations will not work
30 * - IE 9 will not animate transitions at all, though it's possible to at least
31 * switch between slides.
32 * - Infinite Scroll themes will not load presentations properly unless the post
33 * happens to be on the first loaded page. The permalink page will function
34 * properly, however.
35 * - Exiting fullscreen mode will not properly reset the scroll locations in Safari
36 */
37
38
39 /*
40 HOW TO: How the plugin settings are organized and which features are supported.
41
42 The entire presentation should be wrapped with a [presentation] shortcode, and every
43 individual slide should be wrapped with a [slide] shortcode. Any settings supported
44 by [slide] can be set into [presentation], which will apply that setting for the entire
45 presentation unless overridden by individual slides.
46
47 - [presentation] only settings:
48 - duration: transition durations, default is one second.
49 - height: content height, default is 400px
50 - width: content width, default is 550px
51 - autoplay: delay between transitions in seconds, default 3s
52 when set the presentation will automatically transition between slides
53 as long as the presentation remains in focus
54
55 - [slide] settings:
56 - transition: specifies where the next slide will be placed relative
57 to the last one before it. Supported values are "up", "down"
58 "left", "right", or "none". Default value is "down".
59
60 - scale: scales the content relative to other slides, default value is one
61
62 - rotate: rotates the content by the specified degrees, default is zero
63
64 - fade: slides will fade in and out during transition. Values of "on" or
65 "true" will enable fading, while values of "no" or "false" will
66 disable it. Default value is "on"
67
68 - bgcolor: specifies a background color for the slides. Any CSS valid value
69 is permitted. Default color is transparent.
70
71 - bgimg: specifies an image url which will fill the background. Image is
72 set to fill the background 100% width and height
73
74 - fadebullets: any html <li> tags will start out with an opacity of 0 and any
75 subsequent slide transitions will show the bullets one by one
76 */
77
78 if ( ! class_exists( 'Presentations' ) ) :
79 class Presentations {
80
81 private $presentation_settings;
82 private $presentation_initialized;
83 private $scripts_and_style_included;
84
85 /**
86 * Constructor
87 */
88 function __construct() {
89 $this->presentation_initialized = false;
90 $this->scripts_and_style_included = false;
91
92 // Registers shortcodes
93 add_action( 'wp_head', array( &$this, 'add_scripts' ), 1 );
94
95 add_shortcode( 'presentation', array( &$this, 'presentation_shortcode' ) );
96 add_shortcode( 'slide', array( &$this, 'slide_shortcode' ) );
97 }
98
99 function add_scripts() {
100 $this->scripts_and_style_included = false;
101
102 if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) {
103 return;
104 }
105
106 foreach ( $GLOBALS['posts'] as $p ) {
107 if ( has_shortcode( $p->post_content, 'presentation' ) ) {
108 $this->scripts_and_style_included = true;
109 break;
110 }
111 }
112
113 if ( ! $this->scripts_and_style_included ) {
114 return;
115 }
116
117 $plugin = plugin_dir_url( __FILE__ );
118 // Add CSS
119 wp_enqueue_style( 'presentations', $plugin . 'css/style.css' );
120 // Add JavaScript
121 wp_enqueue_script( 'jquery' );
122 wp_enqueue_script(
123 'jmpress',
124 Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/jmpress.min.js', 'modules/shortcodes/js/jmpress.js' ),
125 array( 'jquery' ),
126 '0.4.5',
127 true
128 );
129 wp_enqueue_script(
130 'presentations',
131 Jetpack::get_file_url_for_environment( '_inc/build/shortcodes/js/main.min.js', 'modules/shortcodes/js/main.js' ),
132 array( 'jquery', 'jmpress' ),
133 false,
134 true
135 );
136 }
137
138 function presentation_shortcode( $atts, $content = '' ) {
139 // Mark that we've found a valid [presentation] shortcode
140 $this->presentation_initialized = true;
141
142 $atts = shortcode_atts(
143 array(
144 'duration' => '',
145 'height' => '',
146 'width' => '',
147 'bgcolor' => '',
148 'bgimg' => '',
149 'autoplay' => '',
150
151 // Settings
152 'transition' => '',
153 'scale' => '',
154 'rotate' => '',
155 'fade' => '',
156 'fadebullets' => '',
157 ), $atts, 'presentation'
158 );
159
160 $this->presentation_settings = array(
161 'transition' => 'down',
162 'scale' => 1,
163 'rotate' => 0,
164 'fade' => 'on',
165 'fadebullets' => 0,
166 'last' => array(
167 'x' => 0,
168 'y' => 0,
169 'scale' => 1,
170 'rotate' => 0,
171 ),
172 );
173
174 // Set the presentation-wide settings
175 if ( '' != trim( $atts['transition'] ) ) {
176 $this->presentation_settings['transition'] = $atts['transition'];
177 }
178
179 if ( '' != trim( $atts['scale'] ) ) {
180 $this->presentation_settings['scale'] = floatval( $atts['scale'] );
181 }
182
183 if ( '' != trim( $atts['rotate'] ) ) {
184 $this->presentation_settings['rotate'] = floatval( $atts['rotate'] );
185 }
186
187 if ( '' != trim( $atts['fade'] ) ) {
188 $this->presentation_settings['fade'] = $atts['fade'];
189 }
190
191 if ( '' != trim( $atts['fadebullets'] ) ) {
192 $this->presentation_settings['fadebullets'] = $atts['fadebullets'];
193 }
194
195 // Set any settings the slides don't care about
196 if ( '' != trim( $atts['duration'] ) ) {
197 $duration = floatval( $atts['duration'] ) . 's';
198 } else {
199 $duration = '1s';
200 }
201
202 // Autoplay durations are set in milliseconds
203 if ( '' != trim( $atts['autoplay'] ) ) {
204 $autoplay = floatval( $atts['autoplay'] ) * 1000;
205 } else {
206 $autoplay = 0;
207 } // No autoplay
208
209 // Set the presentation size as specified or with some nicely sized dimensions
210 if ( '' != trim( $atts['width'] ) ) {
211 $this->presentation_settings['width'] = intval( $atts['width'] );
212 } else {
213 $this->presentation_settings['width'] = 480;
214 }
215
216 if ( '' != trim( $atts['height'] ) ) {
217 $this->presentation_settings['height'] = intval( $atts['height'] );
218 } else {
219 $this->presentation_settings['height'] = 370;
220 }
221
222 // Hide the content by default in case the scripts fail
223 $style = 'display: none; width: ' . $this->presentation_settings['width'] . 'px; height: ' . $this->presentation_settings['height'] . 'px;';
224
225 // Check for background color XOR background image
226 // Use a white background if nothing specified
227 if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) {
228 $style .= ' background-image: url("' . esc_url( $matches[0] ) . '");';
229 } else if ( '' != trim( $atts['bgcolor'] ) ) {
230 $style .= ' background-color: ' . esc_attr( $atts['bgcolor'] ) . ';';
231 } else {
232 $style .= ' background-color: #fff;';
233 }
234
235 // Not supported message style is inlined incase the style sheet doesn't get included
236 $out = "<section class='presentation-wrapper'>";
237 $out .= "<p class='not-supported-msg' style='display: inherit; padding: 25%; text-align: center;'>";
238 $out .= __( 'This slideshow could not be started. Try refreshing the page or viewing it in another browser.', 'jetpack' ) . '</p>';
239
240 // Bail out unless the scripts were added
241 if ( $this->scripts_and_style_included ) {
242 $out .= sprintf(
243 '<div class="presentation" duration="%s" data-autoplay="%s" style="%s">',
244 esc_attr( $duration ),
245 esc_attr( $autoplay ),
246 esc_attr( $style )
247 );
248 $out .= "<div class='nav-arrow-left'></div>";
249 $out .= "<div class='nav-arrow-right'></div>";
250 $out .= "<div class='nav-fullscreen-button'></div>";
251
252 if ( $autoplay ) {
253 $out .= '<div class="autoplay-overlay" style="display: none;"><p class="overlay-msg">';
254 $out .= __( 'Click to autoplay the presentation!', 'jetpack' );
255 $out .= '</p></div>';
256 }
257
258 $out .= do_shortcode( $content );
259 }
260
261 $out .= '</section>';
262
263 $this->presentation_initialized = false;
264
265 return $out;
266 }
267
268 function slide_shortcode( $atts, $content = '' ) {
269 // Bail out unless wrapped by a [presentation] shortcode
270 if ( ! $this->presentation_initialized ) {
271 return $content;
272 }
273
274 $atts = shortcode_atts(
275 array(
276 'transition' => '',
277 'scale' => '',
278 'rotate' => '',
279 'fade' => '',
280 'fadebullets' => '',
281 'bgcolor' => '',
282 'bgimg' => '',
283 ), $atts, 'slide'
284 );
285
286 // Determine positioning based on transition
287 if ( '' == trim( $atts['transition'] ) ) {
288 $atts['transition'] = $this->presentation_settings['transition'];
289 }
290
291 // Setting the content scale
292 if ( '' == trim( $atts['scale'] ) ) {
293 $atts['scale'] = $this->presentation_settings['scale'];
294 }
295
296 if ( '' == trim( $atts['scale'] ) ) {
297 $scale = 1;
298 } else {
299 $scale = floatval( $atts['scale'] );
300 }
301
302 if ( $scale < 0 ) {
303 $scale *= -1;
304 }
305
306 // Setting the content rotation
307 if ( '' == trim( $atts['rotate'] ) ) {
308 $atts['rotate'] = $this->presentation_settings['rotate'];
309 }
310
311 if ( '' == trim( $atts['rotate'] ) ) {
312 $rotate = 0;
313 } else {
314 $rotate = floatval( $atts['rotate'] );
315 }
316
317 // Setting if the content should fade
318 if ( '' == trim( $atts['fade'] ) ) {
319 $atts['fade'] = $this->presentation_settings['fade'];
320 }
321
322 if ( 'on' == $atts['fade'] || 'true' == $atts['fade'] ) {
323 $fade = 'fade';
324 } else {
325 $fade = '';
326 }
327
328 // Setting if bullets should fade on step changes
329 if ( '' == trim( $atts['fadebullets'] ) ) {
330 $atts['fadebullets'] = $this->presentation_settings['fadebullets'];
331 }
332
333 if ( 'on' == $atts['fadebullets'] || 'true' == $atts['fadebullets'] ) {
334 $fadebullets = 'fadebullets';
335 } else {
336 $fadebullets = '';
337 }
338
339 $coords = $this->get_coords(
340 array(
341 'transition' => $atts['transition'],
342 'scale' => $scale,
343 'rotate' => $rotate,
344 )
345 );
346
347 $x = $coords['x'];
348 $y = $coords['y'];
349
350 // Check for background color XOR background image
351 // Use a white background if nothing specified
352 if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) {
353 $style = 'background-image: url("' . esc_url( $matches[0] ) . '");';
354 } else if ( '' != trim( $atts['bgcolor'] ) ) {
355 $style = 'background-color: ' . esc_attr( $atts['bgcolor'] ) . ';';
356 } else {
357 $style = '';
358 }
359
360 // Put everything together and let jmpress do the magic!
361 $out = sprintf(
362 '<div class="step %s %s" data-x="%s" data-y="%s" data-scale="%s" data-rotate="%s" style="%s">',
363 esc_attr( $fade ),
364 esc_attr( $fadebullets ),
365 esc_attr( $x ),
366 esc_attr( $y ),
367 esc_attr( $scale ),
368 esc_attr( $rotate ),
369 esc_attr( $style )
370 );
371
372 $out .= '<div class="slide-content">';
373 $out .= do_shortcode( $content );
374 $out .= '</div></div>';
375
376 return $out;
377 }
378
379 /**
380 * Determines the position of the next slide based on the position and scaling of the previous slide.
381 *
382 * @param array $args : an array with the following key-value pairs
383 * string $transition: the transition name, "up", "down", "left", or "right"
384 * float $scale: the scale of the next slide (used to determine the position of the slide after that)
385 *
386 * @return array with the 'x' and 'y' coordinates of the slide
387 */
388 function get_coords( $args ) {
389 if ( 0 == $args['scale'] ) {
390 $args['scale'] = 1;
391 }
392
393 $width = $this->presentation_settings['width'];
394 $height = $this->presentation_settings['height'];
395 $last = $this->presentation_settings['last'];
396 $scale = $last['scale'];
397
398 $next = array(
399 'x' => $last['x'],
400 'y' => $last['y'],
401 'scale' => $args['scale'],
402 'rotate' => $args['rotate'],
403 );
404
405 // All angles are measured from the vertical axis, so everything is backwards!
406 $diagAngle = atan2( $width, $height );
407 $diagonal = sqrt( pow( $width, 2 ) + pow( $height, 2 ) );
408
409 // We offset the angles by the angle formed by the diagonal so that
410 // we can multiply the sines directly against the diagonal length
411 $theta = deg2rad( $last['rotate'] ) - $diagAngle;
412 $phi = deg2rad( $next['rotate'] ) - $diagAngle;
413
414 // We start by displacing by the slide dimensions
415 $totalHorizDisp = $width * $scale;
416 $totalVertDisp = $height * $scale;
417
418 // If the previous slide was rotated, we add the incremental offset from the rotation
419 // Namely the difference between the regular dimension (no rotation) and the component
420 // of the diagonal for that angle
421 $totalHorizDisp += ( ( ( abs( sin( $theta ) ) * $diagonal ) - $width ) / 2 ) * $scale;
422 $totalVertDisp += ( ( ( abs( cos( $theta ) ) * $diagonal ) - $height ) / 2 ) * $scale;
423
424 // Similarly, we check if the current slide has been rotated and add whatever additional
425 // offset has been added. This is so that two rotated corners don't clash with each other.
426 // Note: we are checking the raw angle relative to the vertical axis, NOT the diagonal angle.
427 if ( 0 !== $next['rotate'] % 180 ) {
428 $totalHorizDisp += ( abs( ( sin( $phi ) * $diagonal ) - $width ) / 2 ) * $next['scale'];
429 $totalVertDisp += ( abs( ( cos( $phi ) * $diagonal ) - $height ) / 2 ) * $next['scale'];
430 }
431
432 switch ( trim( $args['transition'] ) ) {
433 case 'none':
434 break;
435
436 case 'left':
437 $next['x'] -= $totalHorizDisp;
438 break;
439
440 case 'right':
441 $next['x'] += $totalHorizDisp;
442 break;
443
444 case 'up':
445 $next['y'] -= $totalVertDisp;
446 break;
447
448 case 'down':
449 default:
450 $next['y'] += $totalVertDisp;
451 break;
452 }
453
454 $this->presentation_settings['last'] = $next;
455
456 return $next;
457 }
458 }
459
460 $GLOBALS['presentations'] = new Presentations();
461 endif;
462