Completed
Push — add/pathinfo-sitemap ( eb9d33...02fba8 )
by Jeremy
14:23 queued 04:10
created

Presentations::presentation_shortcode()   F

Complexity

Conditions 14
Paths 4608

Size

Total Lines 129
Code Lines 80

Duplication

Lines 23
Ratio 17.83 %

Importance

Changes 0
Metric Value
cc 14
eloc 80
nc 4608
nop 2
dl 23
loc 129
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
		// Bail without 3.0.
90
		if ( ! function_exists( '__return_false' ) ) {
91
			return;
92
		}
93
94
		$this->presentation_initialized   = false;
95
		$this->scripts_and_style_included = false;
96
97
		// Registers shortcodes
98
		add_action( 'wp_head', array( &$this, 'add_scripts' ), 1 );
99
100
		add_shortcode( 'presentation', array( &$this, 'presentation_shortcode' ) );
101
		add_shortcode( 'slide',        array( &$this, 'slide_shortcode' ) );
102
	}
103
104
	function add_scripts() {
105
		$this->scripts_and_style_included = false;
106
107
		if ( empty( $GLOBALS['posts'] ) || ! is_array( $GLOBALS['posts'] ) ) {
108
			return;
109
		}
110
111 View Code Duplication
		foreach ( $GLOBALS['posts'] as $p ) {
112
			if ( has_shortcode( $p->post_content, 'presentation' ) ) {
113
				$this->scripts_and_style_included = true;
114
				break;
115
			}
116
		}
117
118
		if ( ! $this->scripts_and_style_included ) {
119
			return;
120
		}
121
122
		$plugin = plugin_dir_url( __FILE__ );
123
		// Add CSS
124
		wp_enqueue_style( 'presentations', $plugin . 'css/style.css' );
125
		// Add JavaScript
126
		wp_enqueue_script( 'jquery' );
127
		wp_enqueue_script( 'jmpress', $plugin . 'js/jmpress.min.js', array( 'jquery' ), '0.4.5', true );
128
		wp_enqueue_script( 'presentations', $plugin . 'js/main.js', array( 'jquery', 'jmpress' ), false, true );
129
	}
130
131
	function presentation_shortcode( $atts, $content = '' ) {
132
		// Mark that we've found a valid [presentation] shortcode
133
		$this->presentation_initialized = true;
134
135
		$atts = shortcode_atts(
136
			array(
137
				'duration'    => '',
138
				'height'      => '',
139
				'width'       => '',
140
				'bgcolor'     => '',
141
				'bgimg'       => '',
142
				'autoplay'    => '',
143
144
				// Settings
145
				'transition'  => '',
146
				'scale'       => '',
147
				'rotate'      => '',
148
				'fade'        => '',
149
				'fadebullets' => '',
150
			), $atts, 'presentation'
151
		);
152
153
		$this->presentation_settings = array(
154
			'transition'  => 'down',
155
			'scale'       => 1,
156
			'rotate'      => 0,
157
			'fade'        => 'on',
158
			'fadebullets' => 0,
159
			'last'        => array(
160
				'x'      => 0,
161
				'y'      => 0,
162
				'scale'  => 1,
163
				'rotate' => 0,
164
			),
165
		);
166
167
		// Set the presentation-wide settings
168 View Code Duplication
		if ( '' != trim( $atts['transition'] ) ) {
169
			$this->presentation_settings['transition'] = $atts['transition'];
170
		}
171
172 View Code Duplication
		if ( '' != trim( $atts['scale'] ) ) {
173
			$this->presentation_settings['scale'] = floatval( $atts['scale'] );
174
		}
175
176 View Code Duplication
		if ( '' != trim( $atts['rotate'] ) ) {
177
			$this->presentation_settings['rotate'] = floatval( $atts['rotate'] );
178
		}
179
180 View Code Duplication
		if ( '' != trim( $atts['fade'] ) ) {
181
			$this->presentation_settings['fade'] = $atts['fade'];
182
		}
183
184 View Code Duplication
		if ( '' != trim( $atts['fadebullets'] ) ) {
185
			$this->presentation_settings['fadebullets'] = $atts['fadebullets'];
186
		}
187
188
		// Set any settings the slides don't care about
189
		if ( '' != trim( $atts['duration'] ) ) {
190
			$duration = floatval( $atts['duration'] ) . 's';
191
		} else {
192
			$duration = '1s';
193
		}
194
195
		// Autoplay durations are set in milliseconds
196
		if ( '' != trim( $atts['autoplay'] ) ) {
197
			$autoplay = floatval( $atts['autoplay'] ) * 1000;
198
		} else {
199
			$autoplay = 0;
200
		} // No autoplay
201
202
		// Set the presentation size as specified or with some nicely sized dimensions
203 View Code Duplication
		if ( '' != trim( $atts['width'] ) ) {
204
			$this->presentation_settings['width'] = intval( $atts['width'] );
205
		} else {
206
			$this->presentation_settings['width'] = 480;
207
		}
208
209 View Code Duplication
		if ( '' != trim( $atts['height'] ) ) {
210
			$this->presentation_settings['height'] = intval( $atts['height'] );
211
		} else {
212
			$this->presentation_settings['height'] = 370;
213
		}
214
215
		// Hide the content by default in case the scripts fail
216
		$style = 'display: none; width: ' . $this->presentation_settings['width'] . 'px; height: ' . $this->presentation_settings['height'] . 'px;';
217
218
		// Check for background color XOR background image
219
		// Use a white background if nothing specified
220
		if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) {
221
			$style .= ' background-image: url("' . esc_url( $matches[0] ) . '");';
222 View Code Duplication
		} else if ( '' != trim( $atts['bgcolor'] ) ) {
223
			$style .= ' background-color: ' . esc_attr( $atts['bgcolor'] ) . ';';
224
		} else {
225
			$style .= ' background-color: #fff;';
226
		}
227
228
		// Not supported message style is inlined incase the style sheet doesn't get included
229
		$out = "<section class='presentation-wrapper'>";
230
		$out .= "<p class='not-supported-msg' style='display: inherit; padding: 25%; text-align: center;'>";
231
		$out .= __( 'This slideshow could not be started. Try refreshing the page or viewing it in another browser.', 'jetpack' ) . '</p>';
232
233
		// Bail out unless the scripts were added
234
		if ( $this->scripts_and_style_included ) {
235
			$out .= sprintf(
236
				'<div class="presentation" duration="%s" data-autoplay="%s" style="%s">',
237
				esc_attr( $duration ),
238
				esc_attr( $autoplay ),
239
				esc_attr( $style )
240
			);
241
			$out .= "<div class='nav-arrow-left'></div>";
242
			$out .= "<div class='nav-arrow-right'></div>";
243
			$out .= "<div class='nav-fullscreen-button'></div>";
244
245
			if ( $autoplay ) {
246
				$out .= '<div class="autoplay-overlay" style="display: none;"><p class="overlay-msg">';
247
				$out .= __( 'Click to autoplay the presentation!', 'jetpack' );
248
				$out .= '</p></div>';
249
			}
250
251
			$out .= do_shortcode( $content );
252
		}
253
254
		$out .= '</section>';
255
256
		$this->presentation_initialized = false;
257
258
		return $out;
259
	}
260
261
	function slide_shortcode( $atts, $content = '' ) {
262
		// Bail out unless wrapped by a [presentation] shortcode
263
		if ( ! $this->presentation_initialized ) {
264
			return $content;
265
		}
266
267
		$atts = shortcode_atts(
268
			array(
269
				'transition'  => '',
270
				'scale'       => '',
271
				'rotate'      => '',
272
				'fade'        => '',
273
				'fadebullets' => '',
274
				'bgcolor'     => '',
275
				'bgimg'       => '',
276
			), $atts, 'slide'
277
		);
278
279
		// Determine positioning based on transition
280 View Code Duplication
		if ( '' == trim( $atts['transition'] ) ) {
281
			$atts['transition'] = $this->presentation_settings['transition'];
282
		}
283
284
		// Setting the content scale
285 View Code Duplication
		if ( '' == trim( $atts['scale'] ) ) {
286
			$atts['scale'] = $this->presentation_settings['scale'];
287
		}
288
289
		if ( '' == trim( $atts['scale'] ) ) {
290
			$scale = 1;
291
		} else {
292
			$scale = floatval( $atts['scale'] );
293
		}
294
295
		if ( $scale < 0 ) {
296
			$scale *= -1;
297
		}
298
299
		// Setting the content rotation
300 View Code Duplication
		if ( '' == trim( $atts['rotate'] ) ) {
301
			$atts['rotate'] = $this->presentation_settings['rotate'];
302
		}
303
304
		if ( '' == trim( $atts['rotate'] ) ) {
305
			$rotate = 0;
306
		} else {
307
			$rotate = floatval( $atts['rotate'] );
308
		}
309
310
		// Setting if the content should fade
311 View Code Duplication
		if ( '' == trim( $atts['fade'] ) ) {
312
			$atts['fade'] = $this->presentation_settings['fade'];
313
		}
314
315
		if ( 'on' == $atts['fade'] || 'true' == $atts['fade'] ) {
316
			$fade = 'fade';
317
		} else {
318
			$fade = '';
319
		}
320
321
		// Setting if bullets should fade on step changes
322 View Code Duplication
		if ( '' == trim( $atts['fadebullets'] ) ) {
323
			$atts['fadebullets'] = $this->presentation_settings['fadebullets'];
324
		}
325
326
		if ( 'on' == $atts['fadebullets'] || 'true' == $atts['fadebullets'] ) {
327
			$fadebullets = 'fadebullets';
328
		} else {
329
			$fadebullets = '';
330
		}
331
332
		$coords = $this->get_coords(
333
			array(
334
				'transition' => $atts['transition'],
335
				'scale'      => $scale,
336
				'rotate'     => $rotate,
337
			)
338
		);
339
340
		$x = $coords['x'];
341
		$y = $coords['y'];
342
343
		// Check for background color XOR background image
344
		// Use a white background if nothing specified
345
		if ( preg_match( '/https?\:\/\/[^\'"\s]*/', $atts['bgimg'], $matches ) ) {
346
			$style = 'background-image: url("' . esc_url( $matches[0] ) . '");';
347 View Code Duplication
		} else if ( '' != trim( $atts['bgcolor'] ) ) {
348
			$style = 'background-color: ' . esc_attr( $atts['bgcolor'] ) . ';';
349
		} else {
350
			$style = '';
351
		}
352
353
		// Put everything together and let jmpress do the magic!
354
		$out = sprintf(
355
			'<div class="step %s %s" data-x="%s" data-y="%s" data-scale="%s" data-rotate="%s" style="%s">',
356
			esc_attr( $fade ),
357
			esc_attr( $fadebullets ),
358
			esc_attr( $x ),
359
			esc_attr( $y ),
360
			esc_attr( $scale ),
361
			esc_attr( $rotate ),
362
			esc_attr( $style )
363
		);
364
365
		$out .= '<div class="slide-content">';
366
		$out .= do_shortcode( $content );
367
		$out .= '</div></div>';
368
369
		return $out;
370
	}
371
372
	/**
373
	 * Determines the position of the next slide based on the position and scaling of the previous slide.
374
	 *
375
	 * @param array $args : an array with the following key-value pairs
376
	 *                    string $transition: the transition name, "up", "down", "left", or "right"
377
	 *                    float $scale: the scale of the next slide (used to determine the position of the slide after that)
378
	 *
379
	 * @return array with the 'x' and 'y' coordinates of the slide
380
	 */
381
	function get_coords( $args ) {
382
		if ( 0 == $args['scale'] ) {
383
			$args['scale'] = 1;
384
		}
385
386
		$width  = $this->presentation_settings['width'];
387
		$height = $this->presentation_settings['height'];
388
		$last   = $this->presentation_settings['last'];
389
		$scale  = $last['scale'];
390
391
		$next = array(
392
			'x'      => $last['x'],
393
			'y'      => $last['y'],
394
			'scale'  => $args['scale'],
395
			'rotate' => $args['rotate'],
396
		);
397
398
		// All angles are measured from the vertical axis, so everything is backwards!
399
		$diagAngle = atan2( $width, $height );
400
		$diagonal  = sqrt( pow( $width, 2 ) + pow( $height, 2 ) );
401
402
		// We offset the angles by the angle formed by the diagonal so that
403
		// we can multiply the sines directly against the diagonal length
404
		$theta = deg2rad( $last['rotate'] ) - $diagAngle;
405
		$phi   = deg2rad( $next['rotate'] ) - $diagAngle;
406
407
		// We start by displacing by the slide dimensions
408
		$totalHorizDisp = $width * $scale;
409
		$totalVertDisp  = $height * $scale;
410
411
		// If the previous slide was rotated, we add the incremental offset from the rotation
412
		// Namely the difference between the regular dimension (no rotation) and the component
413
		// of the diagonal for that angle
414
		$totalHorizDisp += ( ( ( abs( sin( $theta ) ) * $diagonal ) - $width ) / 2 ) * $scale;
415
		$totalVertDisp += ( ( ( abs( cos( $theta ) ) * $diagonal ) - $height ) / 2 ) * $scale;
416
417
		// Similarly, we check if the current slide has been rotated and add whatever additional
418
		// offset has been added. This is so that two rotated corners don't clash with each other.
419
		// Note: we are checking the raw angle relative to the vertical axis, NOT the diagonal angle.
420
		if ( 0 !== $next['rotate'] % 180 ) {
421
			$totalHorizDisp += ( abs( ( sin( $phi ) * $diagonal ) - $width ) / 2 ) * $next['scale'];
422
			$totalVertDisp += ( abs( ( cos( $phi ) * $diagonal ) - $height ) / 2 ) * $next['scale'];
423
		}
424
425
		switch ( trim( $args['transition'] ) ) {
426
			case 'none':
427
				break;
428
429
			case 'left':
430
				$next['x'] -= $totalHorizDisp;
431
				break;
432
433
			case 'right':
434
				$next['x'] += $totalHorizDisp;
435
				break;
436
437
			case 'up':
438
				$next['y'] -= $totalVertDisp;
439
				break;
440
441
			case 'down':
442
			default:
443
				$next['y'] += $totalVertDisp;
444
				break;
445
		}
446
447
		$this->presentation_settings['last'] = $next;
448
449
		return $next;
450
	}
451
}
452
453
$GLOBALS['presentations'] = new Presentations();
454
endif;
455