Passed
Push — master ( de7162...f256de )
by Brian
739:27 queued 623:54
created

AyeCode_UI_Settings::get_url()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 3
eloc 8
c 1
b 0
f 1
nc 2
nop 0
dl 0
loc 16
rs 10
1
<?php
2
/**
3
 * A class for adjusting AyeCode UI settings on WordPress
4
 *
5
 * This class can be added to any plugin or theme and will add a settings screen to WordPress to control Bootstrap settings.
6
 *
7
 * @link https://github.com/AyeCode/wp-ayecode-ui
8
 *
9
 * @internal This file should not be edited directly but pulled from the github repo above.
10
 */
11
12
/**
13
 * Bail if we are not in WP.
14
 */
15
if ( ! defined( 'ABSPATH' ) ) {
16
	exit;
17
}
18
19
/**
20
 * Only add if the class does not already exist.
21
 */
22
if ( ! class_exists( 'AyeCode_UI_Settings' ) ) {
23
24
	/**
25
	 * A Class to be able to change settings for Font Awesome.
26
	 *
27
	 * Class AyeCode_UI_Settings
28
	 * @ver 1.0.0
29
	 * @todo decide how to implement textdomain
30
	 */
31
	class AyeCode_UI_Settings {
32
33
		/**
34
		 * Class version version.
35
		 *
36
		 * @var string
37
		 */
38
		public $version = '1.0.1';
39
40
		/**
41
		 * Class textdomain.
42
		 *
43
		 * @var string
44
		 */
45
		public $textdomain = 'aui';
46
47
		/**
48
		 * Latest version of Bootstrap at time of publish published.
49
		 *
50
		 * @var string
51
		 */
52
		public $latest = "4.3.1";
53
54
		/**
55
		 * Current version of select2 being used.
56
		 *
57
		 * @var string
58
		 */
59
		public $select2_version = "4.0.11";
60
61
		/**
62
		 * The title.
63
		 *
64
		 * @var string
65
		 */
66
		public $name = 'AyeCode UI';
67
68
		/**
69
		 * The relative url to the assets.
70
		 *
71
		 * @var string
72
		 */
73
		public $url = '';
74
75
		/**
76
		 * Holds the settings values.
77
		 *
78
		 * @var array
79
		 */
80
		private $settings;
81
82
		/**
83
		 * AyeCode_UI_Settings instance.
84
		 *
85
		 * @access private
86
		 * @since  1.0.0
87
		 * @var    AyeCode_UI_Settings There can be only one!
88
		 */
89
		private static $instance = null;
90
91
		/**
92
		 * Main AyeCode_UI_Settings Instance.
93
		 *
94
		 * Ensures only one instance of AyeCode_UI_Settings is loaded or can be loaded.
95
		 *
96
		 * @since 1.0.0
97
		 * @static
98
		 * @return AyeCode_UI_Settings - Main instance.
99
		 */
100
		public static function instance() {
101
			if ( ! isset( self::$instance ) && ! ( self::$instance instanceof AyeCode_UI_Settings ) ) {
102
				self::$instance = new AyeCode_UI_Settings;
103
104
				add_action( 'init', array( self::$instance, 'init' ) ); // set settings
105
106
				if ( is_admin() ) {
107
					add_action( 'admin_menu', array( self::$instance, 'menu_item' ) );
108
					add_action( 'admin_init', array( self::$instance, 'register_settings' ) );
109
110
					// Maybe show example page
111
					add_action( 'template_redirect', array( self::$instance,'maybe_show_examples' ) );
112
				}
113
114
				add_action( 'customize_register', array( self::$instance, 'customizer_settings' ));
115
116
				do_action( 'ayecode_ui_settings_loaded' );
117
			}
118
119
			return self::$instance;
120
		}
121
122
		/**
123
		 * Initiate the settings and add the required action hooks.
124
		 */
125
		public function init() {
126
			$this->settings = $this->get_settings();
127
			$this->url = $this->get_url();
128
129
			/**
130
			 * Maybe load CSS
131
			 *
132
			 * We load super early in case there is a theme version that might change the colors
133
			 */
134
			if ( $this->settings['css'] ) {
135
				add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ), 1 );
136
			}
137
			if ( $this->settings['css_backend'] ) {
138
				add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_style' ), 1 );
139
			}
140
141
			// maybe load JS
142
			if ( $this->settings['js'] ) {
143
				add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ), 1 );
144
			}
145
			if ( $this->settings['js_backend'] ) {
146
				add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), 1 );
147
			}
148
149
			// Maybe set the HTML font size
150
			if ( $this->settings['html_font_size'] ) {
151
				add_action( 'wp_footer', array( $this, 'html_font_size' ), 10 );
152
			}
153
154
155
		}
156
157
		/**
158
		 * Add a html font size to the footer.
159
		 */
160
		public function html_font_size(){
161
			$this->settings = $this->get_settings();
162
			echo "<style>html{font-size:".absint($this->settings['html_font_size'])."px;}</style>";
163
		}
164
165
		/**
166
		 * Adds the Font Awesome styles.
167
		 */
168
		public function enqueue_style() {
169
			
170
			$css_setting = current_action() == 'wp_enqueue_scripts' ? 'css' : 'css_backend';
171
172
			if($this->settings[$css_setting]){
173
				$compatibility = $this->settings[$css_setting]=='core' ? false : true;
174
				$url = $this->settings[$css_setting]=='core' ? $this->url.'assets/css/ayecode-ui.css' : $this->url.'assets/css/ayecode-ui-compatibility.css';
175
				wp_register_style( 'ayecode-ui', $url, array(), $this->latest );
176
				wp_enqueue_style( 'ayecode-ui' );
177
178
179
				// fix some wp-admin issues
180
				if(is_admin()){
181
					$custom_css = "
182
                body{
183
                    background-color: #f1f1f1;
184
                    font-family: -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;
185
                    font-size:13px;
186
                }
187
                a {
188
				    color: #0073aa;
189
				    text-decoration: underline;
190
				}
191
                label {
192
				    display: initial;
193
				    margin-bottom: 0;
194
				}
195
				input, select {
196
				    margin: 1px;
197
				    line-height: initial;
198
				}
199
				th, td, div, h2 {
200
				    box-sizing: content-box;
201
				}
202
				p {
203
				    font-size: 13px;
204
				    line-height: 1.5;
205
				    margin: 1em 0;
206
				}
207
				h1, h2, h3, h4, h5, h6 {
208
				    display: block;
209
				    font-weight: 600;
210
				}
211
				h2,h3 {
212
				    font-size: 1.3em;
213
				    margin: 1em 0
214
				}
215
                ";
216
					wp_add_inline_style( 'ayecode-ui', $custom_css );
217
				}
218
219
				// custom changes
220
				wp_add_inline_style( 'ayecode-ui', self::custom_css($compatibility) );
221
222
			}
223
		}
224
225
		/**
226
		 * Get inline script used if bootstrap enqueued
227
		 *
228
		 * If this remains small then its best to use this than to add another JS file.
229
		 */
230
		public function inline_script(){
231
			ob_start();
232
			?>
233
			<script>
234
235
				/**
236
				 * An AUI bootstrap adaptation of GreedyNav.js ( by Luke Jackson ).
237
				 *
238
				 * Simply add the class `greedy` to any <nav> menu and it will do the rest.
239
				 * Licensed under the MIT license - http://opensource.org/licenses/MIT
240
				 * @ver 0.0.1
241
				 */
242
				function aui_init_greedy_nav(){
243
					jQuery('nav.greedy').each(function(i, obj) {
244
245
						// Check if already initialized, if so continue.
246
						if(jQuery(this).hasClass("being-greedy")){return true;}
247
248
						// Make sure its always expanded
249
						jQuery(this).addClass('navbar-expand');
250
251
						// vars
252
						var $vlinks = jQuery(this).find('.navbar-nav').addClass("being-greedy w-100");
253
						jQuery($vlinks).append('<li class="nav-item list-unstyled ml-auto greedy-btn d-none ">' +
254
							'<a href="javascript:void(0)" data-toggle="dropdown" class="nav-link"><i class="fas fa-ellipsis-h"></i> <span class="greedy-count badge badge-dark badge-pill"></span></a>' +
255
							'<div class="dropdown"><ul class="greedy-links dropdown-menu  dropdown-menu-right"></ul></div>' +
256
							'</li>');
257
						var $hlinks = jQuery(this).find('.greedy-links');
258
						var $btn = jQuery(this).find('.greedy-btn');
259
260
						var numOfItems = 0;
261
						var totalSpace = 0;
262
						var closingTime = 1000;
263
						var breakWidths = [];
264
265
						// Get initial state
266
						$vlinks.children().outerWidth(function(i, w) {
267
							totalSpace += w;
268
							numOfItems += 1;
269
							breakWidths.push(totalSpace);
270
						});
271
272
						var availableSpace, numOfVisibleItems, requiredSpace, buttonSpace ,timer;
273
274
						/*
275
						 The check function.
276
						 */
277
						function check() {
278
279
							// Get instant state
280
							buttonSpace = $btn.width();
281
							availableSpace = $vlinks.width() - 10;
282
							numOfVisibleItems = $vlinks.children().length;
283
							requiredSpace = breakWidths[numOfVisibleItems - 1];
284
285
							// There is not enough space
286
							if (numOfVisibleItems > 1 && requiredSpace > availableSpace) {
287
								$vlinks.children().last().prev().prependTo($hlinks);
288
								numOfVisibleItems -= 1;
289
								check();
290
								// There is more than enough space
291
							} else if (availableSpace > breakWidths[numOfVisibleItems]) {
292
								$hlinks.children().first().insertBefore($btn);
293
								numOfVisibleItems += 1;
294
								check();
295
							}
296
							// Update the button accordingly
297
							jQuery($btn).find(".greedy-count").html( numOfItems - numOfVisibleItems);
298
							if (numOfVisibleItems === numOfItems) {
299
								$btn.addClass('d-none');
300
							} else $btn.removeClass('d-none');
301
						}
302
303
						// Window listeners
304
						jQuery(window).resize(function() {
305
							check();
306
						});
307
308
						// do initial check
309
						check();
310
					});
311
				}
312
313
				/**
314
				 * Initiate Select2 items.
315
				 */
316
				function aui_init_select2(){
317
					jQuery("select.aui-select2").select2();
318
				}
319
320
				/**
321
				 * A function to convert a time value to a "ago" time text.
322
				 *
323
				 * @param selector string The .class selector
324
				 */
325
				function aui_time_ago(selector) {
326
327
					var templates = {
328
						prefix: "",
329
						suffix: " ago",
330
						seconds: "less than a minute",
331
						minute: "about a minute",
332
						minutes: "%d minutes",
333
						hour: "about an hour",
334
						hours: "about %d hours",
335
						day: "a day",
336
						days: "%d days",
337
						month: "about a month",
338
						months: "%d months",
339
						year: "about a year",
340
						years: "%d years"
341
					};
342
					var template = function (t, n) {
343
						return templates[t] && templates[t].replace(/%d/i, Math.abs(Math.round(n)));
344
					};
345
346
					var timer = function (time) {
347
						if (!time)
348
							return;
349
						time = time.replace(/\.\d+/, ""); // remove milliseconds
350
						time = time.replace(/-/, "/").replace(/-/, "/");
351
						time = time.replace(/T/, " ").replace(/Z/, " UTC");
352
						time = time.replace(/([\+\-]\d\d)\:?(\d\d)/, " $1$2"); // -04:00 -> -0400
353
						time = new Date(time * 1000 || time);
354
355
						var now = new Date();
356
						var seconds = ((now.getTime() - time) * .001) >> 0;
357
						var minutes = seconds / 60;
358
						var hours = minutes / 60;
359
						var days = hours / 24;
360
						var years = days / 365;
361
362
						return templates.prefix + (
363
								seconds < 45 && template('seconds', seconds) ||
364
								seconds < 90 && template('minute', 1) ||
365
								minutes < 45 && template('minutes', minutes) ||
366
								minutes < 90 && template('hour', 1) ||
367
								hours < 24 && template('hours', hours) ||
368
								hours < 42 && template('day', 1) ||
369
								days < 30 && template('days', days) ||
370
								days < 45 && template('month', 1) ||
371
								days < 365 && template('months', days / 30) ||
372
								years < 1.5 && template('year', 1) ||
373
								template('years', years)
374
							) + templates.suffix;
375
					};
376
377
					var elements = document.getElementsByClassName(selector);
378
					for (var i in elements) {
379
						var $this = elements[i];
380
						if (typeof $this === 'object') {
381
							$this.innerHTML = '<i class="far fa-clock"></i> ' + timer($this.getAttribute('title') || $this.getAttribute('datetime'));
382
						}
383
					}
384
					// update time every minute
385
					setTimeout(aui_time_ago, 60000);
386
387
				}
388
389
				/**
390
				 * Initiate tooltips on the page.
391
				 */
392
				function aui_init_tooltips(){
393
					jQuery('[data-toggle="tooltip"]').tooltip();
394
					jQuery('[data-toggle="popover"]').popover();
395
					jQuery('[data-toggle="popover-html"]').popover({
396
						html: true
397
					});
398
				}
399
400
				// run on window loaded
401
				jQuery(window).load(function() {
402
					// init tooltips
403
					aui_init_tooltips();
404
405
					// init select2
406
					aui_init_select2();
407
408
					// init Greedy nav
409
					aui_init_greedy_nav();
410
411
					// Set times to time ago
412
					aui_time_ago('timeago');
413
				});
414
			</script>
415
			<?php
416
			$output = ob_get_clean();
417
418
			/*
419
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
420
			 */
421
			return str_replace( array(
422
				'<script>',
423
				'</script>'
424
			), '', $output );
425
		}
426
427
		/**
428
		 * Get inline script used if bootstrap file browser enqueued.
429
		 *
430
		 * If this remains small then its best to use this than to add another JS file.
431
		 */
432
		public function inline_script_file_browser(){
433
			ob_start();
434
			?>
435
			<script>
436
				// run on doc ready
437
				jQuery(document).ready(function () {
438
					bsCustomFileInput.init();
439
				});
440
			</script>
441
			<?php
442
			$output = ob_get_clean();
443
444
			/*
445
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
446
			 */
447
			return str_replace( array(
448
				'<script>',
449
				'</script>'
450
			), '', $output );
451
		}
452
453
		/**
454
		 * Adds the Font Awesome JS.
455
		 */
456
		public function enqueue_scripts() {
457
458
			$js_setting = current_action() == 'wp_enqueue_scripts' ? 'js' : 'js_backend';
459
			
460
			// select2
461
			wp_register_script( 'select2', $this->url.'assets/js/select2.min.js', array('jquery'), $this->select2_version );
462
463
			// Bootstrap file browser
464
			wp_register_script( 'aui-custom-file-input', $url = $this->url.'assets/js/bs-custom-file-input.min.js', array('jquery'), $this->select2_version );
465
			wp_add_inline_script( 'aui-custom-file-input', $this->inline_script_file_browser() );
466
467
			$load_inline = false;
468
469
			if($this->settings[$js_setting]=='core-popper'){
470
				// Bootstrap bundle
471
				$url = $this->url.'assets/js/bootstrap.bundle.min.js';
472
				wp_register_script( 'bootstrap-js-bundle', $url, array('select2','jquery'), $this->latest );
473
				wp_enqueue_script( 'bootstrap-js-bundle' );
474
				$script = $this->inline_script();
475
				wp_add_inline_script( 'bootstrap-js-bundle', $script );
476
			}elseif($this->settings[$js_setting]=='popper'){
477
				$url = $this->url.'assets/js/popper.min.js';
478
				wp_register_script( 'bootstrap-js-popper', $url, array('jquery'), $this->latest );
479
				wp_enqueue_script( 'bootstrap-js-popper' );
480
				$load_inline = true;
481
			}else{
482
				$load_inline = true;
483
			}
484
485
			// Load needed inline scripts by faking the loading of a script if the main script is not being loaded
486
			if($load_inline){
487
				wp_register_script( 'bootstrap-dummy', '',array('jquery') );
488
				wp_enqueue_script( 'bootstrap-dummy' );
489
				$script = $this->inline_script();
490
				wp_add_inline_script( 'bootstrap-dummy', $script  );
491
			}
492
			
493
		}
494
495
		/**
496
		 * Get the url path to the current folder.
497
		 *
498
		 * @return string
499
		 */
500
		public function get_url() {
501
502
			$url = '';
503
			// check if we are inside a plugin
504
			$file_dir = str_replace( "/includes","", wp_normalize_path( dirname( __FILE__ ) ) );
505
506
			// add check in-case user has changed wp-content dir name.
507
			$wp_content_folder_name = basename(WP_CONTENT_DIR);
508
			$dir_parts = explode("/$wp_content_folder_name/",$file_dir);
509
			$url_parts = explode("/$wp_content_folder_name/",plugins_url());
510
511
			if(!empty($url_parts[0]) && !empty($dir_parts[1])){
512
				$url = trailingslashit( $url_parts[0]."/$wp_content_folder_name/".$dir_parts[1] );
513
			}
514
515
			return $url;
516
		}
517
518
		/**
519
		 * Register the database settings with WordPress.
520
		 */
521
		public function register_settings() {
522
			register_setting( 'ayecode-ui-settings', 'ayecode-ui-settings' );
523
		}
524
525
		/**
526
		 * Add the WordPress settings menu item.
527
		 * @since 1.0.10 Calling function name direct will fail theme check so we don't.
528
		 */
529
		public function menu_item() {
530
			$menu_function = 'add' . '_' . 'options' . '_' . 'page'; // won't pass theme check if function name present in theme
531
			call_user_func( $menu_function, $this->name, $this->name, 'manage_options', 'ayecode-ui-settings', array(
532
				$this,
533
				'settings_page'
534
			) );
535
		}
536
537
		/**
538
		 * Get a list of themes and their default JS settings.
539
		 * 
540
		 * @return array
541
		 */
542
		public function theme_js_settings(){
543
			return array(
544
				'ayetheme' => 'popper',
545
				'listimia' => 'required',
546
				'listimia_backend' => 'core-popper',
547
				'avada'    => 'required',
548
			);
549
		}
550
551
		/**
552
		 * Get the current Font Awesome output settings.
553
		 *
554
		 * @return array The array of settings.
555
		 */
556
		public function get_settings() {
557
558
			$db_settings = get_option( 'ayecode-ui-settings' );
559
			$js_default = 'core-popper';
560
			$js_default_backend = $js_default;
561
562
			// maybe set defaults (if no settings set)
563
			if(empty($db_settings)){
564
				$active_theme = strtolower( get_template() ); // active parent theme.
565
				$theme_js_settings = self::theme_js_settings();
0 ignored issues
show
Bug Best Practice introduced by
The method AyeCode_UI_Settings::theme_js_settings() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

565
				/** @scrutinizer ignore-call */ 
566
    $theme_js_settings = self::theme_js_settings();
Loading history...
566
				if(isset($theme_js_settings[$active_theme])){
567
					$js_default = $theme_js_settings[$active_theme];
568
					$js_default_backend = isset($theme_js_settings[$active_theme."_backend"]) ? $theme_js_settings[$active_theme."_backend"] : $js_default;
569
				}
570
			}
571
572
			$defaults = array(
573
				'css'       => 'compatibility', // core, compatibility
574
				'js'        => $js_default, // js to load, core-popper, popper
575
				'html_font_size'        => '16', // js to load, core-popper, popper
576
				'css_backend'       => 'compatibility', // core, compatibility
577
				'js_backend'        => $js_default_backend, // js to load, core-popper, popper
578
579
			);
580
581
			$settings = wp_parse_args( $db_settings, $defaults );
582
583
			/**
584
			 * Filter the Bootstrap settings.
585
			 *
586
			 * @todo if we add this filer people might use it and then it defeates the purpose of this class :/
587
			 */
588
			return $this->settings = apply_filters( 'ayecode-ui-settings', $settings, $db_settings, $defaults );
589
		}
590
591
592
		/**
593
		 * The settings page html output.
594
		 */
595
		public function settings_page() {
596
			if ( ! current_user_can( 'manage_options' ) ) {
597
				wp_die( __( 'You do not have sufficient permissions to access this page.', 'aui' ) );
598
			}
599
			?>
600
			<div class="wrap">
601
				<h1><?php echo $this->name; ?></h1>
602
				<p><?php _e("Here you can adjust settings if you are having compatibility issues.","aui");?></p>
603
				<form method="post" action="options.php">
604
					<?php
605
					settings_fields( 'ayecode-ui-settings' );
606
					do_settings_sections( 'ayecode-ui-settings' );
607
					?>
608
609
					<h2><?php _e( 'Frontend', 'aui' ); ?></h2>
610
					<table class="form-table wpbs-table-settings">
611
						<tr valign="top">
612
							<th scope="row"><label
613
									for="wpbs-css"><?php _e( 'Load CSS', 'aui' ); ?></label></th>
614
							<td>
615
								<select name="ayecode-ui-settings[css]" id="wpbs-css">
616
									<option	value="compatibility" <?php selected( $this->settings['css'], 'compatibility' ); ?>><?php _e( 'Compatibility Mode', 'aui' ); ?></option>
617
									<option value="core" <?php selected( $this->settings['css'], 'core' ); ?>><?php _e( 'Full Mode', 'aui' ); ?></option>
618
									<option	value="" <?php selected( $this->settings['css'], '' ); ?>><?php _e( 'Disabled', 'aui' ); ?></option>
619
								</select>
620
							</td>
621
						</tr>
622
623
						<tr valign="top">
624
							<th scope="row"><label
625
									for="wpbs-js"><?php _e( 'Load JS', 'aui' ); ?></label></th>
626
							<td>
627
								<select name="ayecode-ui-settings[js]" id="wpbs-js">
628
									<option	value="core-popper" <?php selected( $this->settings['js'], 'core-popper' ); ?>><?php _e( 'Core + Popper (default)', 'aui' ); ?></option>
629
									<option value="popper" <?php selected( $this->settings['js'], 'popper' ); ?>><?php _e( 'Popper', 'aui' ); ?></option>
630
									<option value="required" <?php selected( $this->settings['js'], 'required' ); ?>><?php _e( 'Required functions only', 'aui' ); ?></option>
631
									<option	value="" <?php selected( $this->settings['js'], '' ); ?>><?php _e( 'Disabled (not recommended)', 'aui' ); ?></option>
632
								</select>
633
							</td>
634
						</tr>
635
636
						<tr valign="top">
637
							<th scope="row"><label
638
									for="wpbs-font_size"><?php _e( 'HTML Font Size (px)', 'aui' ); ?></label></th>
639
							<td>
640
								<input type="number" name="ayecode-ui-settings[html_font_size]" id="wpbs-font_size" value="<?php echo absint( $this->settings['html_font_size']); ?>" placeholder="16" />
641
								<p class="description" ><?php _e("Our font sizing is rem (responsive based) here you can set the html font size in-case your theme is setting it too low.","aui");?></p>
642
							</td>
643
						</tr>
644
645
					</table>
646
647
					<h2><?php _e( 'Backend', 'aui' ); ?> (wp-admin)</h2>
648
					<table class="form-table wpbs-table-settings">
649
						<tr valign="top">
650
							<th scope="row"><label
651
									for="wpbs-css"><?php _e( 'Load CSS', 'aui' ); ?></label></th>
652
							<td>
653
								<select name="ayecode-ui-settings[css_backend]" id="wpbs-css">
654
									<option	value="compatibility" <?php selected( $this->settings['css_backend'], 'compatibility' ); ?>><?php _e( 'Compatibility Mode', 'aui' ); ?></option>
655
									<option value="core" <?php selected( $this->settings['css_backend'], 'core' ); ?>><?php _e( 'Full Mode', 'aui' ); ?></option>
656
									<option	value="" <?php selected( $this->settings['css_backend'], '' ); ?>><?php _e( 'Disabled', 'aui' ); ?></option>
657
								</select>
658
							</td>
659
						</tr>
660
661
						<tr valign="top">
662
							<th scope="row"><label
663
									for="wpbs-js"><?php _e( 'Load JS', 'aui' ); ?></label></th>
664
							<td>
665
								<select name="ayecode-ui-settings[js_backend]" id="wpbs-js">
666
									<option	value="core-popper" <?php selected( $this->settings['js_backend'], 'core-popper' ); ?>><?php _e( 'Core + Popper (default)', 'aui' ); ?></option>
667
									<option value="popper" <?php selected( $this->settings['js_backend'], 'popper' ); ?>><?php _e( 'Popper', 'aui' ); ?></option>
668
									<option value="required" <?php selected( $this->settings['js_backend'], 'required' ); ?>><?php _e( 'Required functions only', 'aui' ); ?></option>
669
									<option	value="" <?php selected( $this->settings['js_backend'], '' ); ?>><?php _e( 'Disabled (not recommended)', 'aui' ); ?></option>
670
								</select>
671
							</td>
672
						</tr>
673
674
					</table>
675
676
					<?php
677
					submit_button();
678
					?>
679
				</form>
680
681
				<div id="wpbs-version"><?php echo $this->version; ?></div>
682
			</div>
683
684
			<?php
685
		}
686
687
		public function customizer_settings($wp_customize){
688
			$wp_customize->add_section('aui_settings', array(
689
				'title'    => __('AyeCode UI'),
690
				'priority' => 120,
691
			));
692
693
			//  =============================
694
			//  = Color Picker              =
695
			//  =============================
696
			$wp_customize->add_setting('aui_options[color_primary]', array(
697
				'default'           => '#1e73be',
698
				'sanitize_callback' => 'sanitize_hex_color',
699
				'capability'        => 'edit_theme_options',
700
				'type'              => 'option',
701
				'transport'         => 'refresh',
702
			));
703
			$wp_customize->add_control( new WP_Customize_Color_Control($wp_customize, 'color_primary', array(
704
				'label'    => __('Primary Color'),
705
				'section'  => 'aui_settings',
706
				'settings' => 'aui_options[color_primary]',
707
			)));
708
709
			$wp_customize->add_setting('aui_options[color_secondary]', array(
710
				'default'           => '#6c757d',
711
				'sanitize_callback' => 'sanitize_hex_color',
712
				'capability'        => 'edit_theme_options',
713
				'type'              => 'option',
714
				'transport'         => 'refresh',
715
			));
716
			$wp_customize->add_control( new WP_Customize_Color_Control($wp_customize, 'color_secondary', array(
717
				'label'    => __('Secondary Color'),
718
				'section'  => 'aui_settings',
719
				'settings' => 'aui_options[color_secondary]',
720
			)));
721
		}
722
723
724
		public static function custom_css($compatibility = true) {
725
			$settings = get_option('aui_options');
726
727
			ob_start();
728
			?>
729
			<style>
730
				<?php
731
					if(!empty($settings['color_primary']) && $settings['color_primary'] != "#1e73be"){
732
						echo self::css_primary($settings['color_primary'],$compatibility);
733
					}
734
735
					if(!empty($settings['color_secondary']) && $settings['color_secondary'] != "#6c757d"){
736
						echo self::css_secondary($settings['color_secondary'],$compatibility);
737
					}
738
                ?>
739
			</style>
740
			<?php
741
742
743
			/*
744
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
745
			 */
746
			return str_replace( array(
747
				'<style>',
748
				'</style>'
749
			), '', ob_get_clean());
750
		}
751
752
		public static function css_primary($color_code,$compatibility){;
753
			$color_code = sanitize_hex_color($color_code);
754
			if(!$color_code){return '';}
755
			/**
756
			 * c = color, b = background color, o = border-color, f = fill
757
			 */
758
			$selectors = array(
759
				'a' => array('c'),
760
				'.btn-primary' => array('b','o'),
761
				'.btn-primary.disabled' => array('b','o'),
762
				'.btn-primary:disabled' => array('b','o'),
763
				'.btn-outline-primary' => array('c','o'),
764
				'.btn-outline-primary:hover' => array('b','o'),
765
				'.btn-outline-primary:not(:disabled):not(.disabled).active' => array('b','o'),
766
				'.btn-outline-primary:not(:disabled):not(.disabled):active' => array('b','o'),
767
				'.show>.btn-outline-primary.dropdown-toggle' => array('b','o'),
768
				'.btn-link' => array('c'),
769
				'.dropdown-item.active' => array('b'),
770
				'.custom-control-input:checked~.custom-control-label::before' => array('b','o'),
771
				'.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before' => array('b','o'),
772
//				'.custom-range::-webkit-slider-thumb' => array('b'), // these break the inline rules...
773
//				'.custom-range::-moz-range-thumb' => array('b'),
774
//				'.custom-range::-ms-thumb' => array('b'),
775
				'.nav-pills .nav-link.active' => array('b'),
776
				'.nav-pills .show>.nav-link' => array('b'),
777
				'.page-link' => array('c'),
778
				'.page-item.active .page-link' => array('b','o'),
779
				'.badge-primary' => array('b'),
780
				'.alert-primary' => array('b','o'),
781
				'.progress-bar' => array('b'),
782
				'.list-group-item.active' => array('b','o'),
783
				'.bg-primary' => array('b','f'),
784
				'.btn-link.btn-primary' => array('c'),
785
				'.select2-container .select2-results__option--highlighted.select2-results__option[aria-selected=true]' => array('b'),
786
			);
787
788
			$important_selectors = array(
789
				'.bg-primary' => array('b','f'),
790
				'.border-primary' => array('o'),
791
				'.text-primary' => array('c'),
792
			);
793
794
			$color = array();
795
			$color_i = array();
796
			$background = array();
797
			$background_i = array();
798
			$border = array();
799
			$border_i = array();
800
			$fill = array();
801
			$fill_i = array();
802
803
			$output = '';
804
805
			// build rules into each type
806
			foreach($selectors as $selector => $types){
807
				$selector = $compatibility ? ".bsui ".$selector : $selector;
808
				$types = array_combine($types,$types);
809
				if(isset($types['c'])){$color[] = $selector;}
810
				if(isset($types['b'])){$background[] = $selector;}
811
				if(isset($types['o'])){$border[] = $selector;}
812
				if(isset($types['f'])){$fill[] = $selector;}
813
			}
814
815
			// build rules into each type
816
			foreach($important_selectors as $selector => $types){
817
				$selector = $compatibility ? ".bsui ".$selector : $selector;
818
				$types = array_combine($types,$types);
819
				if(isset($types['c'])){$color_i[] = $selector;}
820
				if(isset($types['b'])){$background_i[] = $selector;}
821
				if(isset($types['o'])){$border_i[] = $selector;}
822
				if(isset($types['f'])){$fill_i[] = $selector;}
823
			}
824
825
			// add any color rules
826
			if(!empty($color)){
827
				$output .= implode(",",$color) . "{color: $color_code;} ";
828
			}
829
			if(!empty($color_i)){
830
				$output .= implode(",",$color_i) . "{color: $color_code !important;} ";
831
			}
832
833
			// add any background color rules
834
			if(!empty($background)){
835
				$output .= implode(",",$background) . "{background-color: $color_code;} ";
836
			}
837
			if(!empty($background_i)){
838
				$output .= implode(",",$background_i) . "{background-color: $color_code !important;} ";
839
			}
840
841
			// add any border color rules
842
			if(!empty($border)){
843
				$output .= implode(",",$border) . "{border-color: $color_code;} ";
844
			}
845
			if(!empty($border_i)){
846
				$output .= implode(",",$border_i) . "{border-color: $color_code !important;} ";
847
			}
848
849
			// add any fill color rules
850
			if(!empty($fill)){
851
				$output .= implode(",",$fill) . "{fill: $color_code;} ";
852
			}
853
			if(!empty($fill_i)){
854
				$output .= implode(",",$fill_i) . "{fill: $color_code !important;} ";
855
			}
856
857
858
			$prefix = $compatibility ? ".bsui " : "";
859
860
			// darken
861
			$darker_075 = self::css_hex_lighten_darken($color_code,"-0.075");
0 ignored issues
show
Bug introduced by
'-0.075' of type string is incompatible with the type double expected by parameter $adjustPercent of AyeCode_UI_Settings::css_hex_lighten_darken(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

861
			$darker_075 = self::css_hex_lighten_darken($color_code,/** @scrutinizer ignore-type */ "-0.075");
Loading history...
862
			$darker_10 = self::css_hex_lighten_darken($color_code,"-0.10");
863
			$darker_125 = self::css_hex_lighten_darken($color_code,"-0.125");
864
865
			// lighten
866
			$lighten_25 = self::css_hex_lighten_darken($color_code,"0.25");
867
868
			// opacity see https://css-tricks.com/8-digit-hex-codes/
869
			$op_25 = $color_code."40"; // 25% opacity
870
871
872
			// button states
873
			$output .= $prefix ." .btn-primary:hover{background-color: ".$darker_075.";    border-color: ".$darker_10.";} ";
874
			$output .= $prefix ." .btn-outline-primary:not(:disabled):not(.disabled):active:focus, $prefix .btn-outline-primary:not(:disabled):not(.disabled).active:focus, .show>$prefix .btn-outline-primary.dropdown-toggle:focus{box-shadow: 0 0 0 0.2rem $op_25;} ";
875
			$output .= $prefix ." .btn-primary:not(:disabled):not(.disabled):active, $prefix .btn-primary:not(:disabled):not(.disabled).active, .show>$prefix .btn-primary.dropdown-toggle{background-color: ".$darker_10.";    border-color: ".$darker_125.";} ";
876
			$output .= $prefix ." .btn-primary:not(:disabled):not(.disabled):active:focus, $prefix .btn-primary:not(:disabled):not(.disabled).active:focus, .show>$prefix .btn-primary.dropdown-toggle:focus {box-shadow: 0 0 0 0.2rem $op_25;} ";
877
878
879
			// dropdown's
880
			$output .= $prefix ." .dropdown-item.active, $prefix .dropdown-item:active{background-color: $color_code;} ";
881
882
883
			// input states
884
			$output .= $prefix ." .form-control:focus{border-color: ".$lighten_25.";box-shadow: 0 0 0 0.2rem $op_25;} ";
885
886
			// page link
887
			$output .= $prefix ." .page-link:focus{box-shadow: 0 0 0 0.2rem $op_25;} ";
888
889
			return $output;
890
		}
891
892
		public static function css_secondary($color_code,$compatibility){;
893
			$color_code = sanitize_hex_color($color_code);
894
			if(!$color_code){return '';}
895
			/**
896
			 * c = color, b = background color, o = border-color, f = fill
897
			 */
898
			$selectors = array(
899
				'.btn-secondary' => array('b','o'),
900
				'.btn-secondary.disabled' => array('b','o'),
901
				'.btn-secondary:disabled' => array('b','o'),
902
				'.btn-outline-secondary' => array('c','o'),
903
				'.btn-outline-secondary:hover' => array('b','o'),
904
				'.btn-outline-secondary.disabled' => array('c'),
905
				'.btn-outline-secondary:disabled' => array('c'),
906
				'.btn-outline-secondary:not(:disabled):not(.disabled):active' => array('b','o'),
907
				'.btn-outline-secondary:not(:disabled):not(.disabled).active' => array('b','o'),
908
				'.btn-outline-secondary.dropdown-toggle' => array('b','o'),
909
				'.badge-secondary' => array('b'),
910
				'.alert-secondary' => array('b','o'),
911
				'.btn-link.btn-secondary' => array('c'),
912
				);
913
914
			$important_selectors = array(
915
				'.bg-secondary' => array('b','f'),
916
				'.border-secondary' => array('o'),
917
				'.text-secondary' => array('c'),
918
			);
919
920
			$color = array();
921
			$color_i = array();
922
			$background = array();
923
			$background_i = array();
924
			$border = array();
925
			$border_i = array();
926
			$fill = array();
927
			$fill_i = array();
928
929
			$output = '';
930
931
			// build rules into each type
932
			foreach($selectors as $selector => $types){
933
				$selector = $compatibility ? ".bsui ".$selector : $selector;
934
				$types = array_combine($types,$types);
935
				if(isset($types['c'])){$color[] = $selector;}
936
				if(isset($types['b'])){$background[] = $selector;}
937
				if(isset($types['o'])){$border[] = $selector;}
938
				if(isset($types['f'])){$fill[] = $selector;}
939
			}
940
941
			// build rules into each type
942
			foreach($important_selectors as $selector => $types){
943
				$selector = $compatibility ? ".bsui ".$selector : $selector;
944
				$types = array_combine($types,$types);
945
				if(isset($types['c'])){$color_i[] = $selector;}
946
				if(isset($types['b'])){$background_i[] = $selector;}
947
				if(isset($types['o'])){$border_i[] = $selector;}
948
				if(isset($types['f'])){$fill_i[] = $selector;}
949
			}
950
951
			// add any color rules
952
			if(!empty($color)){
953
				$output .= implode(",",$color) . "{color: $color_code;} ";
954
			}
955
			if(!empty($color_i)){
956
				$output .= implode(",",$color_i) . "{color: $color_code !important;} ";
957
			}
958
959
			// add any background color rules
960
			if(!empty($background)){
961
				$output .= implode(",",$background) . "{background-color: $color_code;} ";
962
			}
963
			if(!empty($background_i)){
964
				$output .= implode(",",$background_i) . "{background-color: $color_code !important;} ";
965
			}
966
967
			// add any border color rules
968
			if(!empty($border)){
969
				$output .= implode(",",$border) . "{border-color: $color_code;} ";
970
			}
971
			if(!empty($border_i)){
972
				$output .= implode(",",$border_i) . "{border-color: $color_code !important;} ";
973
			}
974
975
			// add any fill color rules
976
			if(!empty($fill)){
977
				$output .= implode(",",$fill) . "{fill: $color_code;} ";
978
			}
979
			if(!empty($fill_i)){
980
				$output .= implode(",",$fill_i) . "{fill: $color_code !important;} ";
981
			}
982
983
984
			$prefix = $compatibility ? ".bsui " : "";
985
986
			// darken
987
			$darker_075 = self::css_hex_lighten_darken($color_code,"-0.075");
0 ignored issues
show
Bug introduced by
'-0.075' of type string is incompatible with the type double expected by parameter $adjustPercent of AyeCode_UI_Settings::css_hex_lighten_darken(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

987
			$darker_075 = self::css_hex_lighten_darken($color_code,/** @scrutinizer ignore-type */ "-0.075");
Loading history...
988
			$darker_10 = self::css_hex_lighten_darken($color_code,"-0.10");
989
			$darker_125 = self::css_hex_lighten_darken($color_code,"-0.125");
990
991
			// lighten
992
			$lighten_25 = self::css_hex_lighten_darken($color_code,"0.25");
0 ignored issues
show
Unused Code introduced by
The assignment to $lighten_25 is dead and can be removed.
Loading history...
993
994
			// opacity see https://css-tricks.com/8-digit-hex-codes/
995
			$op_25 = $color_code."40"; // 25% opacity
996
997
998
			// button states
999
			$output .= $prefix ." .btn-secondary:hover{background-color: ".$darker_075.";    border-color: ".$darker_10.";} ";
1000
			$output .= $prefix ." .btn-outline-secondary:not(:disabled):not(.disabled):active:focus, $prefix .btn-outline-secondary:not(:disabled):not(.disabled).active:focus, .show>$prefix .btn-outline-secondary.dropdown-toggle:focus{box-shadow: 0 0 0 0.2rem $op_25;} ";
1001
			$output .= $prefix ." .btn-secondary:not(:disabled):not(.disabled):active, $prefix .btn-secondary:not(:disabled):not(.disabled).active, .show>$prefix .btn-secondary.dropdown-toggle{background-color: ".$darker_10.";    border-color: ".$darker_125.";} ";
1002
			$output .= $prefix ." .btn-secondary:not(:disabled):not(.disabled):active:focus, $prefix .btn-secondary:not(:disabled):not(.disabled).active:focus, .show>$prefix .btn-secondary.dropdown-toggle:focus {box-shadow: 0 0 0 0.2rem $op_25;} ";
1003
1004
1005
			return $output;
1006
		}
1007
1008
		/**
1009
		 * Increases or decreases the brightness of a color by a percentage of the current brightness.
1010
		 *
1011
		 * @param   string  $hexCode        Supported formats: `#FFF`, `#FFFFFF`, `FFF`, `FFFFFF`
1012
		 * @param   float   $adjustPercent  A number between -1 and 1. E.g. 0.3 = 30% lighter; -0.4 = 40% darker.
1013
		 *
1014
		 * @return  string
1015
		 */
1016
		public static function css_hex_lighten_darken($hexCode, $adjustPercent) {
1017
			$hexCode = ltrim($hexCode, '#');
1018
1019
			if (strlen($hexCode) == 3) {
1020
				$hexCode = $hexCode[0] . $hexCode[0] . $hexCode[1] . $hexCode[1] . $hexCode[2] . $hexCode[2];
1021
			}
1022
1023
			$hexCode = array_map('hexdec', str_split($hexCode, 2));
1024
1025
			foreach ($hexCode as & $color) {
1026
				$adjustableLimit = $adjustPercent < 0 ? $color : 255 - $color;
1027
				$adjustAmount = ceil($adjustableLimit * $adjustPercent);
1028
1029
				$color = str_pad(dechex($color + $adjustAmount), 2, '0', STR_PAD_LEFT);
0 ignored issues
show
Bug introduced by
$color + $adjustAmount of type double is incompatible with the type integer expected by parameter $number of dechex(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1029
				$color = str_pad(dechex(/** @scrutinizer ignore-type */ $color + $adjustAmount), 2, '0', STR_PAD_LEFT);
Loading history...
1030
			}
1031
1032
			return '#' . implode($hexCode);
1033
		}
1034
1035
		/**
1036
		 * Check if we should display examples.
1037
		 */
1038
		public function maybe_show_examples(){
1039
			if(current_user_can('manage_options') && isset($_REQUEST['preview-aui'])){
1040
				echo "<head>";
1041
				wp_head();
1042
				echo "</head>";
1043
				echo "<body>";
1044
				echo $this->get_examples();
1045
				echo "</body>";
1046
				exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1047
			}
1048
		}
1049
1050
		/**
1051
		 * Get developer examples.
1052
		 * 
1053
		 * @return string
1054
		 */
1055
		public function get_examples(){
1056
			$output = '';
1057
1058
1059
			// open form
1060
			$output .= "<form class='p-5 m-5 border rounded'>";
1061
1062
			// input example
1063
			$output .= aui()->input(array(
1064
				'type'  =>  'text',
1065
				'id'    =>  'text-example',
1066
				'name'    =>  'text-example',
1067
				'placeholder'   => 'text placeholder',
1068
				'title'   => 'Text input example',
1069
				'value' =>  '',
1070
				'required'  => false,
1071
				'help_text' => 'help text',
1072
				'label' => 'Text input example label'
1073
			));
1074
1075
			// input example
1076
			$output .= aui()->input(array(
1077
				'type'  =>  'url',
1078
				'id'    =>  'text-example2',
1079
				'name'    =>  'text-example',
1080
				'placeholder'   => 'url placeholder',
1081
				'title'   => 'Text input example',
1082
				'value' =>  '',
1083
				'required'  => false,
1084
				'help_text' => 'help text',
1085
				'label' => 'Text input example label'
1086
			));
1087
1088
			// checkbox example
1089
			$output .= aui()->input(array(
1090
				'type'  =>  'checkbox',
1091
				'id'    =>  'checkbox-example',
1092
				'name'    =>  'checkbox-example',
1093
				'placeholder'   => 'checkbox-example',
1094
				'title'   => 'Checkbox example',
1095
				'value' =>  '1',
1096
				'checked'   => true,
1097
				'required'  => false,
1098
				'help_text' => 'help text',
1099
				'label' => 'Checkbox checked'
1100
			));
1101
1102
			// checkbox example
1103
			$output .= aui()->input(array(
1104
				'type'  =>  'checkbox',
1105
				'id'    =>  'checkbox-example2',
1106
				'name'    =>  'checkbox-example2',
1107
				'placeholder'   => 'checkbox-example',
1108
				'title'   => 'Checkbox example',
1109
				'value' =>  '1',
1110
				'checked'   => false,
1111
				'required'  => false,
1112
				'help_text' => 'help text',
1113
				'label' => 'Checkbox un-checked'
1114
			));
1115
1116
			// switch example
1117
			$output .= aui()->input(array(
1118
				'type'  =>  'checkbox',
1119
				'id'    =>  'switch-example',
1120
				'name'    =>  'switch-example',
1121
				'placeholder'   => 'checkbox-example',
1122
				'title'   => 'Switch example',
1123
				'value' =>  '1',
1124
				'checked'   => true,
1125
				'switch'    => true,
1126
				'required'  => false,
1127
				'help_text' => 'help text',
1128
				'label' => 'Switch on'
1129
			));
1130
1131
			// switch example
1132
			$output .= aui()->input(array(
1133
				'type'  =>  'checkbox',
1134
				'id'    =>  'switch-example2',
1135
				'name'    =>  'switch-example2',
1136
				'placeholder'   => 'checkbox-example',
1137
				'title'   => 'Switch example',
1138
				'value' =>  '1',
1139
				'checked'   => false,
1140
				'switch'    => true,
1141
				'required'  => false,
1142
				'help_text' => 'help text',
1143
				'label' => 'Switch off'
1144
			));
1145
1146
			// close form
1147
			$output .= "</form>";
1148
1149
			return $output;
1150
		}
1151
1152
	}
1153
1154
	/**
1155
	 * Run the class if found.
1156
	 */
1157
	AyeCode_UI_Settings::instance();
1158
}