PluginProbe
CoolClock / 4.2
CoolClock v4.2
4.3.9 4.3.8 trunk 0.1 2.0 2.9.8 3.0 3.1 3.2 3.3 4.0 4.1 4.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7
← All changes | includes/class-coolclock.php +117 -349 trunk4.2 View file →
@@ -5,29 +5,32 @@
5 5 */
6 6
7 7 class CoolClock {
8 8
9 - static ?string $plugin_version;
9 + static $plugin_version;
10 10
11 - static $script_version = '3.2.2';
11 + static $script_version = '3.1.0';
12 12
13 - private static ?string $plugin_url;
13 + private static $plugin_url;
14 14
15 - private static ?string $plugin_basename;
15 + private static $plugin_basename;
16 16
17 17 private static $min = '.min';
18 18
19 19 static $add_script = false;
20 20
21 + static $add_moreskins = false;
22 +
23 + private static $done_excanvas = false;
24 +
21 25 static $defaults = array(
22 - 'skin' => 'swissrail',
26 + 'skin' => 'swissRail',
23 27 'radius' => 100,
24 - 'noseconds' => false, // true to hide second hand
28 + 'noseconds' => false, // Hide seconds
25 29 'gmtoffset' => '', // GMT offset
26 - 'showdigital' => '', // show digital time or date
27 - 'scale' => '', // Define alternative clock type: 'logClock' logarithmic or 'logClockRev' reversed
28 - 'font' => '', // Define font size and family for digital time, default '15px monospace'
29 - 'fontcolor' => '' // Define font color for digital time, default '#333'
30 + 'showdigital' => '', // Show digital time or date
31 + 'scale' => 'linear', // Define type of clock linear/logarithmic/log reversed
32 + 'digitalcolor' => '#333'
30 33 );
31 34
32 35 static $showdigital_options = array(
33 36 '' => '',
@@ -33,275 +36,113 @@
33 36 '' => '',
34 37 'digital12' => 'showDigital'
35 38 );
36 39
40 + static $advanced = false;
41 +
37 42 static $advanced_defaults = array(
38 43 'subtext' => '',
39 44 'align' => 'center'
40 45 );
41 46
42 - static $more_skins_config = array();
47 + static $default_skins = array('swissRail','chunkySwiss','chunkySwissOnBlack');
43 48
44 - static $advanced_skins_config = array();
49 + static $more_skins = array('fancy','machine','simonbaird_com','classic','modern','simple','securephp','Tes2','Lev','Sand','Sun','Tor','Cold','Babosa','Tumb','Stone','Disc','watermelon','mister');
45 50
46 - static $skins_config = array();
51 + static $advanced_skins = array();
47 52
48 - /**
49 - * DEPRICATED ARGUMENTS
50 - * keep these for backward compatibility with old advanced extension
51 - */
52 - static $default_skins = array('swissRail');
53 - static $more_skins = array();
54 - static $advanced_skins = array();
55 - static $advanced = false;
56 - /* end unused arguments */
53 + static $advanced_skins_config = array();
57 54
58 55 static $clock_types = array(
59 56 'linear' => '',
60 - 'logclock' => 'logClock',
61 - 'logclockrev' => 'logClockRev'
57 + 'logClock' => 'logClock',
58 + 'logClockRev' => 'logClockRev'
62 59 );
63 60
64 - static $allowed_tags = array(
65 - 'a' => array(
66 - 'href' => array(),
67 - 'title' => array(),
68 - 'target' => array()
69 - ),
70 - 'br' => array(),
71 - 'em' => array(),
72 - 'strong' => array(),
73 - );
74 -
75 61 /**
76 - * Constructor
77 - *
78 - * @since 4.3
79 - *
80 - * @param string $plugin_file Plugin file path
81 - * @param string $plugin_version Plugin version
62 + * MAIN
82 63 */
83 - public function __construct( string $plugin_file, string $plugin_version ) {
84 - // VARS
85 - self::$plugin_url = plugins_url( '/', $plugin_file );
86 - self::$plugin_basename = plugin_basename( $plugin_file );
87 - self::$plugin_version = $plugin_version;
88 64
89 - if ( defined('WP_DEBUG') && WP_DEBUG ) {
90 - self::$min = '';
91 - }
92 -
93 - // widgets
94 - add_action( 'widgets_init', array( __CLASS__, 'register_widget' ) );
95 -
96 - // enqueue scripts but only if shortcode or widget has been used
97 - // so it has to be done as late as the wp_footer action
98 - add_action( 'wp_footer', array( __CLASS__, 'enqueue_scripts' ), 1 );
99 -
100 - add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_meta_links' ), 10, 2);
101 -
102 - // backward compat
103 - add_filter( 'coolclock_shortcode', array( __CLASS__, 'filter_shortcode'), 10, 3 );
104 - add_filter( 'coolclock_widget', array( __CLASS__, 'filter_widget'), 10, 3 );
105 -
106 - /**************
107 - * SHORTCODE
108 - **************/
109 -
110 - add_shortcode( 'coolclock', array( 'CoolClock_Shortcode', 'handle_shortcode' ) );
111 -
112 - // prevent texturizing shortcode content
113 - add_filter( 'no_texturize_shortcodes', array( 'CoolClock_Shortcode', 'no_wptexturize') );
114 - }
115 -
116 - /**
117 - * Build canvas output
118 - *
119 - * @since 2.0
120 - *
121 - * @param array $atts Array of sanitized attributes
122 - *
123 - * @return string Canvas tag
124 - */
125 65 public static function canvas( $atts ) {
126 - /**
127 - * ARRAY VALUES
128 - * skin @param string Skin ID. Must be one of these: 'swissRail' (default skin), 'chunkySwiss', 'chunkySwissOnBlack', 'fancy', 'machine', 'simonbaird_com', 'classic', 'modern', 'simple', 'securephp', 'Tes2', 'Lev', 'Sand', 'Sun', 'Tor', 'Cold', 'Babosa', 'Tumb', 'Stone', 'Disc', 'watermelon' or 'mister'.
129 - * If the Advanced extension is activated, there is also 'minimal' available.
130 - * radius @param int Define the clock radius.
131 - * noseconds @param bool True to hide the second hand.
132 - * gmtoffset @param float Timezone offset relative the Greenwhich Mean Time
133 - * showdigital @param string|bool Set to 'digital12' to show the time in 12h digital format (with am/pm).
134 - * font @param string Set to a font size, family and style for the digital time
135 - * fontcolor @param string Set to a color value to change the digital time color
136 - * scale @param string Optional alternative clock scale 'logClock' or 'logClockRev'
137 - * subtext @param string Optional text, centered below the clock
138 - * align @param string Sets floating of the clock: 'left', 'right' or 'center'
139 - */
66 + extract( $atts );
140 67
141 - // get defaults for missing attributes
142 - $defaults = array_merge( self::$defaults, self::$advanced_defaults );
143 -
144 - $atts = apply_filters( 'coolclock_atts', $atts, $defaults );
145 -
146 - // CoolClock fields array
147 - $fields = array();
148 - $fields[] = 'CoolClock';
149 - // skin id
150 - $fields[] = !empty( $atts['skin'] ) ? $atts['skin'] : $defaults['skin'];
151 - // radius
152 - $fields[] = !empty( $atts['radius'] ) && is_numeric($atts['radius']) ? (int) $atts['radius'] : $defaults['radius'];
153 - // noseconds
154 - $noseconds = isset( $atts['noseconds'] ) ? (bool) $atts['noseconds'] : $defaults['noseconds'];
155 - $fields[] = $noseconds ? 'noSeconds' : '';
156 - // gmt offset
157 - $fields[] = isset( $atts['gmtoffset'] ) && is_numeric( $atts['gmtoffset'] ) ? (float) $atts['gmtoffset'] : $defaults['gmtoffset'];
158 - // show digital
159 - $showdigital = isset($atts['showdigital']) ? $atts['showdigital'] : $defaults['showdigital'];
160 - if ( true === $showdigital )
161 - $showdigital = 'digital12';
162 - $fields[] = isset( self::$showdigital_options[$showdigital] ) ? self::$showdigital_options[$showdigital] : '';
163 - // clock type
164 - $scale = isset( $atts['scale'] ) ? strtolower( $atts['scale'] ) : $defaults['scale'];
165 - $fields[] = isset( self::$clock_types[$scale] ) ? self::$clock_types[$scale] : '';
166 - // set font color
167 - $fields[] = isset( $atts['fontcolor'] ) ? $atts['fontcolor'] : $defaults['fontcolor'];
168 -
169 - $fields = apply_filters( 'coolclock_fields_array', $fields, $atts, $defaults );
170 -
171 - // build output
172 68 $output = '';
173 69
174 - $styles = apply_filters( 'coolclock_canvas_styles', array(), $atts, $defaults );
175 -
176 - // canvas parameters
177 - $output .= '<canvas class="' . implode( ':', array_map('esc_attr', $fields) ) . '"' . CoolClock::inline_style( $styles ) . '></canvas>';
178 -
179 - // sub text
180 - $subtext = ( isset( $atts['subtext'] ) ) ? $atts['subtext'] : $defaults['subtext'];
181 - if ( !empty( $subtext ) )
182 - $output .= '<div class="coolclock-subtext">' . $subtext . '</div>';
183 -
184 - return $output;
185 - }
186 -
187 - /**
188 - * Create inline style attribute from array
189 - *
190 - * @since 4.3
191 - *
192 - * @param array $styles array with style parameters and their values
193 - *
194 - * @return string inline style attribute style="..." complete with leading space
195 - */
196 - public static function inline_style( $styles ) {
197 - $style_arr = array();
198 -
199 - foreach ( $styles as $key => $value ) {
200 - $style_arr[] = $key . ':' . $value;
70 + if ( ! self::$done_excanvas ){
71 + $output .= '<!--[if lte IE 8]>';
72 + $output .= '<script type=\'text/javascript\' src=\'' . self::$plugin_url . 'js/excanvas' . self::$min . '.js\'></script>';
73 + $output .= '<![endif]-->' . PHP_EOL;
74 + self::$done_excanvas = true;
201 75 }
202 76
203 - $style = ! empty($style_arr) ? ' style="' . implode( ';', $style_arr ) . '"' : '';
77 + $output .= '<div class="coolclock';
204 78
205 - return $style;
206 - }
79 + // align class ans style
80 + $output .= ( $align ) ? ' align' . $align : '';
81 + $output .= '" style="width:' . 2 * $radius . 'px;max-width:100%;height:auto">';
82 + // canvas parameters
83 + $output .= '<canvas class="CoolClock:' . $skin . ':' . $radius . ':';
84 + $output .= ( $noseconds == 'true' || $noseconds == '1' ) ? 'noSeconds:' : ':';
85 + $output .= $gmtoffset;
207 86
208 - /**
209 - * Parse skin name and user skin parameters
210 - *
211 - * @since 3.2.0
212 - *
213 - * @param string $skin_name skin name
214 - * @param string $skin_parms skin parameters, preferably in JSON format
215 - *
216 - * @return string either found matching skin name or 'invalid_or_missing_skin' on failure
217 - */
218 - public static function parse_skin( $skin_name, $skin_parms = '' ) {
219 - $skin = strtolower( $skin_name ); // user input, sanitize!
220 - $skin = preg_replace( '/[^a-z0-9_-]/', '', $skin );
87 + // show digital
88 + if ( $showdigital == 'true' || $showdigital == '1' )
89 + $showdigital = 'digital12'; // backward compat
221 90
222 - // check for empty or default skin first
223 - if ( empty($skin) || $skin === self::$defaults['skin'] ) {
224 - // return the matching skin name
225 - return self::$defaults['skin'];
226 - }
91 + if ( isset(self::$showdigital_options[$showdigital]) )
92 + $output .= ':'.self::$showdigital_options[$showdigital];
93 + else
94 + $output .= ':';
227 95
228 - // short-circuit if skin name is already in the config array
229 - if ( array_key_exists( $skin, self::$skins_config ) ) {
230 - // return the matching skin name
231 - return $skin;
232 - }
96 + // set type
97 + if ( isset(self::$clock_types[$scale]) )
98 + $output .= ':'.self::$clock_types[$scale];
99 + else
100 + $output .= ':';
233 101
234 - // search in the more_skins and advanced_skins arrays
235 - $all_skins = self::get_all_skins();
236 - $skin_array = array();
102 + // set font
103 + if ( isset($font) )
104 + $output .= ':'.$font;
105 + else
106 + $output .= ':';
237 107
238 - if ( array_key_exists( $skin, $all_skins ) ) {
239 - // fetch parameters from skins array
240 - $skin_array = is_array( $all_skins[$skin] ) ? $all_skins[$skin] : self::skin_array( $all_skins[$skin] );
241 - } else {
242 - // try to build a skin config from passed parameters (user input, sanitize!)
243 - $skin_array = self::skin_array( $skin_parms );
108 + // set font color
109 + if ( isset($digitalcolor) )
110 + $output .= ':'.$digitalcolor;
111 + else
112 + $output .= ':';
244 113
245 - if ( empty( $skin_array ) ) {
246 - // set faulty skin name
247 - return 'no_skin_found';
248 - }
249 - }
114 + $output .= '"></canvas>';
115 + $output .= ( $subtext ) ? '<div style="width:100%;text-align:center;padding-bottom:10px">' . $subtext . '</div></div>' : '</div>';
250 116
251 - // add found skin parameters to the config array
252 - self::$skins_config[$skin] = $skin_array;
253 -
254 - // return the matching skin name
255 - return $skin;
117 + return $output;
256 118 }
257 119
258 - /**
259 - * Get all available skins
260 - *
261 - * @since 3.2.0
262 - *
263 - * @return array array of all skins
264 - */
265 - public static function get_all_skins() {
266 -
267 - if ( empty( self::$more_skins_config ) ) {
268 - self::$more_skins_config = include COOLCLOCK_DIR . 'includes/moreskins.php';
269 - }
270 -
271 - return array_merge( self::$more_skins_config, self::$advanced_skins_config );
272 - }
273 -
274 - /**
275 - * Enqueue scripts
276 - *
277 - * @since 3.2.0
278 - */
279 120 public static function enqueue_scripts() {
280 - // bail if we don't need script
281 121 if ( ! self::$add_script )
282 122 return;
283 123
284 - $script = '';
124 + wp_enqueue_script( 'coolclock', self::$plugin_url . 'js/coolclock' . self::$min . '.js', array('jquery'), self::$script_version, true );
285 125
286 - if ( !empty( self::$skins_config ) ) {
126 + if ( self::$add_moreskins )
127 + wp_enqueue_script( 'coolclock-moreskins', self::$plugin_url . 'js/moreskins' . self::$min . '.js', array('coolclock'), self::$script_version, true );
287 128
288 - $skins = wp_json_encode( self::$skins_config );
289 - if ( false === $skins ) {
290 - $skins = '{} /* skin parse error, please fix your custom skin */';
291 - }
129 + if ( is_array( self::$advanced_skins_config ) && !empty( self::$advanced_skins_config ) ) {
130 + $script = 'jQuery.extend(CoolClock.config.skins, {' . PHP_EOL;
131 + // loop through plugin custom skins
132 + foreach (self::$advanced_skins_config as $key => $value)
133 + $script .= $key.':{'.$value.'},' . PHP_EOL;
134 + $script .= '});';
292 135
293 - $script .= 'CoolClock.config.skins = ' . $skins . ';';
136 + if ( self::$add_moreskins )
137 + wp_add_inline_script( 'coolclock-moreskins', $script );
138 + else
139 + wp_add_inline_script( 'coolclock', $script );
294 140 }
141 + }
295 142
296 - $script .= PHP_EOL . 'if(document.readyState!="loading"&&document.addEventListener){document.addEventListener("DOMContentLoaded",function(){CoolClock.findAndCreateClocks();})}else{CoolClock.findAndCreateClocks();};';
297 -
298 - wp_enqueue_script( 'coolclock', self::$plugin_url . 'js/coolclock' . self::$min . '.js', false, self::$script_version, true );
299 -
300 - wp_add_inline_script( 'coolclock', $script );
301 -
302 - // called late so should end up in the footer
303 - wp_enqueue_style( 'coolclock', self::$plugin_url . 'css/coolclock' . self::$min . '.css', array(), self::$script_version );
143 + public static function textdomain() {
144 + load_plugin_textdomain( 'coolclock', false, dirname(self::$plugin_basename).'/languages' );
304 145 }
305 146
306 147 public static function register_widget() {
307 148 register_widget("CoolClock_Widget");
@@ -306,17 +147,12 @@
306 147 public static function register_widget() {
307 148 register_widget("CoolClock_Widget");
308 149 }
309 150
310 - /**
311 - * Add links to plugin's description in the plugins list
312 - *
313 - * @param array $links Array of links to display
314 - * @param string $file Plugin file path
315 - */
316 - public static function plugin_meta_links( array $links, string $file ) {
151 + // add links to plugin's description
152 + public static function plugin_meta_links($links, $file) {
317 153 $support_link = '<a target="_blank" href="https://wordpress.org/support/plugin/coolclock/">' . __('Support','coolclock') . '</a>';
318 - $rate_link = '<a target="_blank" href="https://wordpress.org/support/plugin/coolclock/reviews/">' . __('Rate this plugin','coolclock') . '</a>';
154 + $rate_link = '<a target="_blank" href="https://wordpress.org/support/plugin/coolclock/reviews/?filter=5#new-post">' . __('Rate ★★★★★','coolclock') . '</a>';
319 155
320 156 if ( $file == self::$plugin_basename ) {
321 157 $links[] = $support_link;
322 158 $links[] = $rate_link;
@@ -324,124 +160,56 @@
324 160
325 161 return $links;
326 162 }
327 163
328 - /**
329 - * Turn custom skin user input into an array
330 - *
331 - * @since 2.0
332 - *
333 - * @param string $skin
334 - *
335 - * @return array array of skin parameters
336 - */
337 - public static function skin_array( $skin ) {
338 - // remove everything following a ; to thwart any script injection
339 - $parts = explode( ';', $skin, 2 );
340 - $sanitized = $parts[0];
341 - // strip all kind of whitespace
342 - $sanitized = preg_replace("/\s+/", '', $sanitized);;
343 - $sanitized = ltrim( $sanitized, '{' );
344 - $sanitized = rtrim( $sanitized, '}' ) . '}';
345 - // by now, the string should start with a double quote
346 - if ( 0 !== strpos( $sanitized, '"' ) ) {
347 - // regex for (re)wrapping all keys in double quotes
348 - $sanitized = preg_replace( "/(['\"])?([a-zA-Z0-9_]+)(['\"])?:([^\/])/", '"$2":$4', $sanitized );
349 - }
164 + public static function colorval( $color )
165 + {
166 + $color = strip_tags( $color );
167 + $color = trim( $color );
350 168
351 - // fist attempt to decode json string
352 - $skin_array = json_decode( '{' . $sanitized . '}', true );
169 + if (substr($color, 0, 1) == '#') {
170 + if ( ctype_xdigit(substr($color, 1)) )
171 + return $color;
353 172
354 - // not valid json? then do it the hard way
355 - if ( null === $skin_array ) :
173 + return substr($color, 1);
174 + }
356 175
357 - // remove all spaces and tabs
358 - $sanitized = str_replace( array( ' ', "\t", '"', "'" ), '', $sanitized );
176 + return ctype_xdigit($color) ? '#'.$color : $color;
177 + }
359 178
360 - // break it all up in little parts
361 - // this converts valid skin javascript object into json, but messes up all else :/
362 - $elements = explode( '},', $sanitized );
179 + /**
180 + * INIT
181 + */
363 182
364 - // start fresh
365 - $skin_array = array();
183 + public function __construct( $plugin_file, $plugin_version ) {
184 + // VARS
185 + self::$plugin_url = plugins_url( '/', $plugin_file );
186 + self::$plugin_basename = plugin_basename( $plugin_file );
187 + self::$plugin_version = $plugin_version;
366 188
367 - // and build array
368 - foreach( $elements as $element ) {
369 - $pair = explode( ':{', $element );
370 - // validate key
371 - $part = str_replace( '{', '', $pair[0] );
372 - if ( ! in_array( $part, array('outerBorder','smallIndicator','largeIndicator','hourHand','minuteHand','secondHand','secondDecoration') ) )
373 - continue;
374 - // constuct value
375 - $value = array();
376 - $parameters = explode( ',', $pair[1] );
377 - for( $i=0; $i < count( $parameters ); $i++ ) {
378 - $pairs = explode( ':', $parameters[$i] );
379 - $parm_val = str_replace( '}', '', $pairs[1] );
380 - $value[$pairs[0]] = is_numeric($parm_val) ? (float) $parm_val : (string) $parm_val;
381 - }
382 - $skin_array[$part] = $value;
383 - }
189 + if ( defined('WP_DEBUG') && WP_DEBUG ) {
190 + self::$min = '';
191 + }
384 192
385 - endif;
193 + // text domain
194 + add_action( 'plugins_loaded', array( __CLASS__, 'textdomain' ) );
386 195
387 - return $skin_array;
388 - }
196 + // widgets
197 + add_action( 'widgets_init', array( __CLASS__, 'register_widget' ) );
389 198
390 - /**
391 - * Sanitize color value user input
392 - *
393 - * @since 4.2
394 - *
395 - * @param string $color
396 - *
397 - * @return string hex color value or text for named color
398 - */
399 - public static function colorval( $color ) {
400 - $color = wp_strip_all_tags( $color );
401 - $color = trim( $color );
402 - $color = str_replace( array( '"', '\'', ':'), '', $color );
403 - $color_arr = explode( ' ', $color, 2 );
404 - $color = esc_attr( $color_arr[0] );
199 + // enqueue scripts but only if shortcode or widget has been used
200 + // so it has to be done as late as the wp_footer action
201 + add_action( 'wp_footer', array( __CLASS__, 'enqueue_scripts' ), 1 );
405 202
406 - if ( substr($color, 0, 1) == '#' ) {
407 - if ( ctype_xdigit( substr( $color, 1 ) ) )
408 - return $color;
203 + add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_meta_links' ), 10, 2);
409 204
410 - return substr( $color, 1 );
411 - }
205 + /**************
206 + * SHORTCODE
207 + **************/
412 208
413 - return ctype_xdigit( $color ) ? '#'.$color : $color;
414 - }
209 + add_shortcode( 'coolclock', array( 'CoolClock_Shortcode', 'handle_shortcode' ) );
415 210
416 - /**
417 - * Filter shortcode output
418 - *
419 - * @since 4.3
420 - *
421 - * @param string $output output
422 - * @param array $atts array of shortcode attributes
423 - * @param string $content shortcode content
424 - *
425 - * @return string output
426 - */
427 - public static function filter_shortcode( $output, $atts, $content ) {
428 - // add backward compat filter
429 - return apply_filters( 'coolclock_shortcode_advanced', $output, $atts, $content );
430 - }
211 + // prevent texturizing shortcode content
212 + add_filter( 'no_texturize_shortcodes', array( 'CoolClock_Shortcode', 'no_wptexturize') );
213 + }
431 214
432 - /**
433 - * Filter widget output
434 - *
435 - * @since 4.3
436 - *
437 - * @param string $output output
438 - * @param array $args array of widget parameters
439 - * @param array $instance widget instance array parameters
440 - *
441 - * @return string output
442 - */
443 - public static function filter_widget( $output, $args, $instance ) {
444 - // add backward compat filter
445 - return apply_filters( 'coolclock_widget_advanced', $output, $args, $instance );
446 - }
447 215 }