Passed
Push — master ( 5d2154...beaeba )
by Brian
03:53
created

AyeCode_UI_Settings::constants()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 5
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 4
c 0
b 0
f 0
dl 0
loc 5
rs 10
cc 3
nc 4
nop 0
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
103
				self::$instance = new AyeCode_UI_Settings;
104
105
				add_action( 'init', array( self::$instance, 'init' ) ); // set settings
106
107
				if ( is_admin() ) {
108
					add_action( 'admin_menu', array( self::$instance, 'menu_item' ) );
109
					add_action( 'admin_init', array( self::$instance, 'register_settings' ) );
110
111
					// Maybe show example page
112
					add_action( 'template_redirect', array( self::$instance,'maybe_show_examples' ) );
113
				}
114
115
				add_action( 'customize_register', array( self::$instance, 'customizer_settings' ));
116
117
				do_action( 'ayecode_ui_settings_loaded' );
118
			}
119
120
			return self::$instance;
121
		}
122
123
		/**
124
		 * Setup some constants.
125
		 */
126
		public function constants(){
127
			define('AUI_PRIMARY_COLOR_ORIGINAL', "#1e73be");
128
			define('AUI_SECONDARY_COLOR_ORIGINAL', '#6c757d');
129
			if (!defined('AUI_PRIMARY_COLOR')) define('AUI_PRIMARY_COLOR', AUI_PRIMARY_COLOR_ORIGINAL);
130
			if (!defined('AUI_SECONDARY_COLOR')) define('AUI_SECONDARY_COLOR', AUI_SECONDARY_COLOR_ORIGINAL);
131
		}
132
133
		/**
134
		 * Initiate the settings and add the required action hooks.
135
		 */
136
		public function init() {
137
			$this->constants();
138
			$this->settings = $this->get_settings();
139
			$this->url = $this->get_url();
140
141
			/**
142
			 * Maybe load CSS
143
			 *
144
			 * We load super early in case there is a theme version that might change the colors
145
			 */
146
			if ( $this->settings['css'] ) {
147
				add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_style' ), 1 );
148
			}
149
			if ( $this->settings['css_backend'] && $this->load_admin_scripts() ) {
150
				add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_style' ), 1 );
151
			}
152
153
			// maybe load JS
154
			if ( $this->settings['js'] ) {
155
				add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ), 1 );
156
			}
157
			if ( $this->settings['js_backend'] && $this->load_admin_scripts() ) {
158
				add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), 1 );
159
			}
160
161
			// Maybe set the HTML font size
162
			if ( $this->settings['html_font_size'] ) {
163
				add_action( 'wp_footer', array( $this, 'html_font_size' ), 10 );
164
			}
165
166
167
		}
168
169
		/**
170
		 * Check if we should load the admin scripts or not.
171
		 *
172
		 * @return bool
173
		 */
174
		public function load_admin_scripts(){
175
			$result = true;
176
177
			if(!empty($this->settings['disable_admin'])){
178
				$url_parts = explode("\n",$this->settings['disable_admin']);
179
				foreach($url_parts as $part){
180
					if( strpos($_SERVER['REQUEST_URI'], trim($part)) !== false ){
181
						return false; // return early, no point checking further
182
					}
183
				}
184
			}
185
186
			return $result;
187
		}
188
189
		/**
190
		 * Add a html font size to the footer.
191
		 */
192
		public function html_font_size(){
193
			$this->settings = $this->get_settings();
194
			echo "<style>html{font-size:".absint($this->settings['html_font_size'])."px;}</style>";
195
		}
196
197
		/**
198
		 * Adds the Font Awesome styles.
199
		 */
200
		public function enqueue_style() {
201
202
			$css_setting = current_action() == 'wp_enqueue_scripts' ? 'css' : 'css_backend';
203
204
			if($this->settings[$css_setting]){
205
				$compatibility = $this->settings[$css_setting]=='core' ? false : true;
206
				$url = $this->settings[$css_setting]=='core' ? $this->url.'assets/css/ayecode-ui.css' : $this->url.'assets/css/ayecode-ui-compatibility.css';
207
				wp_register_style( 'ayecode-ui', $url, array(), $this->latest );
208
				wp_enqueue_style( 'ayecode-ui' );
209
210
				// flatpickr
211
				wp_register_style( 'flatpickr', $this->url.'assets/css/flatpickr.min.css', array(), $this->latest );
212
213
214
				// fix some wp-admin issues
215
				if(is_admin()){
216
					$custom_css = "
217
                body{
218
                    background-color: #f1f1f1;
219
                    font-family: -apple-system,BlinkMacSystemFont,\"Segoe UI\",Roboto,Oxygen-Sans,Ubuntu,Cantarell,\"Helvetica Neue\",sans-serif;
220
                    font-size:13px;
221
                }
222
                a {
223
				    color: #0073aa;
224
				    text-decoration: underline;
225
				}
226
                label {
227
				    display: initial;
228
				    margin-bottom: 0;
229
				}
230
				input, select {
231
				    margin: 1px;
232
				    line-height: initial;
233
				}
234
				th, td, div, h2 {
235
				    box-sizing: content-box;
236
				}
237
				p {
238
				    font-size: 13px;
239
				    line-height: 1.5;
240
				    margin: 1em 0;
241
				}
242
				h1, h2, h3, h4, h5, h6 {
243
				    display: block;
244
				    font-weight: 600;
245
				}
246
				h2,h3 {
247
				    font-size: 1.3em;
248
				    margin: 1em 0
249
				}
250
                ";
251
252
					// @todo, remove once fixed :: fix for this bug https://github.com/WordPress/gutenberg/issues/14377
253
					$custom_css .= "
254
						.edit-post-sidebar input[type=color].components-text-control__input{
255
						    padding: 0;
256
						}
257
					";
258
					wp_add_inline_style( 'ayecode-ui', $custom_css );
259
				}
260
261
				// custom changes
262
				wp_add_inline_style( 'ayecode-ui', self::custom_css($compatibility) );
263
264
			}
265
		}
266
267
		/**
268
		 * Get inline script used if bootstrap enqueued
269
		 *
270
		 * If this remains small then its best to use this than to add another JS file.
271
		 */
272
		public function inline_script(){
273
			ob_start();
274
			?>
275
			<script>
276
				
277
				/**
278
				 * An AUI bootstrap adaptation of GreedyNav.js ( by Luke Jackson ).
279
				 *
280
				 * Simply add the class `greedy` to any <nav> menu and it will do the rest.
281
				 * Licensed under the MIT license - http://opensource.org/licenses/MIT
282
				 * @ver 0.0.1
283
				 */
284
				function aui_init_greedy_nav(){
285
					jQuery('nav.greedy').each(function(i, obj) {
286
287
						// Check if already initialized, if so continue.
288
						if(jQuery(this).hasClass("being-greedy")){return true;}
289
290
						// Make sure its always expanded
291
						jQuery(this).addClass('navbar-expand');
292
293
						// vars
294
						var $vlinks = '';
295
						var $dDownClass = '';
296
						if(jQuery(this).find('.navbar-nav').length){
297
							if(jQuery(this).find('.navbar-nav').hasClass("being-greedy")){return true;}
298
							$vlinks = jQuery(this).find('.navbar-nav').addClass("being-greedy w-100").removeClass('overflow-hidden');
299
						}else if(jQuery(this).find('.nav').length){
300
							if(jQuery(this).find('.nav').hasClass("being-greedy")){return true;}
301
							$vlinks = jQuery(this).find('.nav').addClass("being-greedy w-100").removeClass('overflow-hidden');
302
							$dDownClass = ' mt-2 ';
303
						}else{
304
							return false;
305
						}
306
307
						jQuery($vlinks).append('<li class="nav-item list-unstyled ml-auto greedy-btn d-none dropdown ">' +
308
							'<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>' +
309
							'<ul class="greedy-links dropdown-menu  dropdown-menu-right '+$dDownClass+'"></ul>' +
310
							'</li>');
311
312
						var $hlinks = jQuery(this).find('.greedy-links');
313
						var $btn = jQuery(this).find('.greedy-btn');
314
315
						var numOfItems = 0;
316
						var totalSpace = 0;
317
						var closingTime = 1000;
318
						var breakWidths = [];
319
320
						// Get initial state
321
						$vlinks.children().outerWidth(function(i, w) {
322
							totalSpace += w;
323
							numOfItems += 1;
324
							breakWidths.push(totalSpace);
325
						});
326
327
						var availableSpace, numOfVisibleItems, requiredSpace, buttonSpace ,timer;
328
329
						/*
330
						 The check function.
331
						 */
332
						function check() {
333
334
							// Get instant state
335
							buttonSpace = $btn.width();
336
							availableSpace = $vlinks.width() - 10;
337
							numOfVisibleItems = $vlinks.children().length;
338
							requiredSpace = breakWidths[numOfVisibleItems - 1];
339
340
							// There is not enough space
341
							if (numOfVisibleItems > 1 && requiredSpace > availableSpace) {
342
								$vlinks.children().last().prev().prependTo($hlinks);
343
								numOfVisibleItems -= 1;
344
								check();
345
								// There is more than enough space
346
							} else if (availableSpace > breakWidths[numOfVisibleItems]) {
347
								$hlinks.children().first().insertBefore($btn);
348
								numOfVisibleItems += 1;
349
								check();
350
							}
351
							// Update the button accordingly
352
							jQuery($btn).find(".greedy-count").html( numOfItems - numOfVisibleItems);
353
							if (numOfVisibleItems === numOfItems) {
354
								$btn.addClass('d-none');
355
							} else $btn.removeClass('d-none');
356
						}
357
358
						// Window listeners
359
						jQuery(window).resize(function() {
360
							check();
361
						});
362
363
						// do initial check
364
						check();
365
					});
366
				}
367
368
				/**
369
				 * Initiate Select2 items.
370
				 */
371
				function aui_init_select2(){
372
					jQuery("select.aui-select2").select2();
373
				}
374
375
				/**
376
				 * A function to convert a time value to a "ago" time text.
377
				 *
378
				 * @param selector string The .class selector
379
				 */
380
				function aui_time_ago(selector) {
381
382
					var templates = {
383
						prefix: "",
384
						suffix: " ago",
385
						seconds: "less than a minute",
386
						minute: "about a minute",
387
						minutes: "%d minutes",
388
						hour: "about an hour",
389
						hours: "about %d hours",
390
						day: "a day",
391
						days: "%d days",
392
						month: "about a month",
393
						months: "%d months",
394
						year: "about a year",
395
						years: "%d years"
396
					};
397
					var template = function (t, n) {
398
						return templates[t] && templates[t].replace(/%d/i, Math.abs(Math.round(n)));
399
					};
400
401
					var timer = function (time) {
402
						if (!time)
403
							return;
404
						time = time.replace(/\.\d+/, ""); // remove milliseconds
405
						time = time.replace(/-/, "/").replace(/-/, "/");
406
						time = time.replace(/T/, " ").replace(/Z/, " UTC");
407
						time = time.replace(/([\+\-]\d\d)\:?(\d\d)/, " $1$2"); // -04:00 -> -0400
408
						time = new Date(time * 1000 || time);
409
410
						var now = new Date();
411
						var seconds = ((now.getTime() - time) * .001) >> 0;
412
						var minutes = seconds / 60;
413
						var hours = minutes / 60;
414
						var days = hours / 24;
415
						var years = days / 365;
416
417
						return templates.prefix + (
418
								seconds < 45 && template('seconds', seconds) ||
419
								seconds < 90 && template('minute', 1) ||
420
								minutes < 45 && template('minutes', minutes) ||
421
								minutes < 90 && template('hour', 1) ||
422
								hours < 24 && template('hours', hours) ||
423
								hours < 42 && template('day', 1) ||
424
								days < 30 && template('days', days) ||
425
								days < 45 && template('month', 1) ||
426
								days < 365 && template('months', days / 30) ||
427
								years < 1.5 && template('year', 1) ||
428
								template('years', years)
429
							) + templates.suffix;
430
					};
431
432
					var elements = document.getElementsByClassName(selector);
433
					for (var i in elements) {
434
						var $this = elements[i];
435
						if (typeof $this === 'object') {
436
							$this.innerHTML = '<i class="far fa-clock"></i> ' + timer($this.getAttribute('title') || $this.getAttribute('datetime'));
437
						}
438
					}
439
					// update time every minute
440
					setTimeout(aui_time_ago, 60000);
441
442
				}
443
444
				/**
445
				 * Initiate tooltips on the page.
446
				 */
447
				function aui_init_tooltips(){
448
					jQuery('[data-toggle="tooltip"]').tooltip();
449
					jQuery('[data-toggle="popover"]').popover();
450
					jQuery('[data-toggle="popover-html"]').popover({
451
						html: true
452
					});
453
454
					// fix popover container compatibility
455
					jQuery('[data-toggle="popover"],[data-toggle="popover-html"]').on('inserted.bs.popover', function () {
456
						jQuery('body > .popover').wrapAll("<div class='bsui' />");
457
					});
458
				}
459
460
				/**
461
				 * Initiate flatpickrs on the page.
462
				 */
463
				$aui_doing_init_flatpickr = false;
464
				function aui_init_flatpickr(){
465
					if ( jQuery.isFunction(jQuery.fn.flatpickr) && !$aui_doing_init_flatpickr) {
466
						$aui_doing_init_flatpickr = true;
467
						jQuery('input[data-aui-init="flatpickr"]:not(.flatpickr-input)').flatpickr();
468
					}
469
					$aui_doing_init_flatpickr = false;
470
				}
471
472
				function aui_modal($title,$body,$footer,$dismissible,$class,$dialog_class) {
473
					if(!$class){$class = '';}
474
					if(!$dialog_class){$dialog_class = '';}
475
					if(!$body){$body = '<div class="text-center"><div class="spinner-border" role="status"></div></div>';}
476
					// remove it first
477
					jQuery('.aui-modal').modal('hide').modal('dispose').remove();
478
					jQuery('.modal-backdrop').remove();
479
480
					var $modal = '';
481
482
					$modal += '<div class="modal aui-modal fade shadow bsui '+$class+'" tabindex="-1">'+
483
						'<div class="modal-dialog modal-dialog-centered '+$dialog_class+'">'+
484
							'<div class="modal-content">';
485
486
					if($title) {
487
						$modal += '<div class="modal-header">' +
488
						'<h5 class="modal-title">' + $title + '</h5>';
489
490
						if ($dismissible) {
491
							$modal += '<button type="button" class="close" data-dismiss="modal" aria-label="Close">' +
492
								'<span aria-hidden="true">&times;</span>' +
493
								'</button>';
494
						}
495
496
						$modal += '</div>';
497
					}
498
					$modal += '<div class="modal-body">'+
499
									$body+
500
								'</div>';
501
502
					if($footer){
503
						$modal += '<div class="modal-footer">'+
504
							$footer +
505
							'</div>';
506
					}
507
508
					$modal +='</div>'+
509
						'</div>'+
510
					'</div>';
511
512
					jQuery('body').append($modal);
513
514
					jQuery('.aui-modal').modal('hide').modal({
515
						//backdrop: 'static'
516
					});
517
				}
518
519
				/**
520
				 * Show / hide fields depending on conditions.
521
				 */
522
				function aui_conditional_fields(form){
523
					jQuery(form).find(".aui-conditional-field").each(function () {
524
525
						var $element_require = jQuery(this).data('element-require');
526
527
						if ($element_require) {
528
529
							$element_require = $element_require.replace("&#039;", "'"); // replace single quotes
530
							$element_require = $element_require.replace("&quot;", '"'); // replace double quotes
531
532
							if (aui_check_form_condition($element_require,form)) {
533
								jQuery(this).removeClass('d-none');
534
							} else {
535
								jQuery(this).addClass('d-none');
536
							}
537
						}
538
					});
539
				}
540
541
				/**
542
				 * Check form condition
543
				 */
544
				function aui_check_form_condition(condition,form) {
545
					if(form){
546
						condition = condition.replace("(form)", "('"+form+"')");
547
					}
548
					return new Function("return " + condition+";")();
549
				}
550
551
				/**
552
				 * A function to determine if a element is on screen.
553
				 */
554
				jQuery.fn.aui_isOnScreen = function(){
555
556
					var win = jQuery(window);
557
558
					var viewport = {
559
						top : win.scrollTop(),
560
						left : win.scrollLeft()
561
					};
562
					viewport.right = viewport.left + win.width();
563
					viewport.bottom = viewport.top + win.height();
564
565
					var bounds = this.offset();
566
					bounds.right = bounds.left + this.outerWidth();
567
					bounds.bottom = bounds.top + this.outerHeight();
568
569
					return (!(viewport.right < bounds.left || viewport.left > bounds.right || viewport.bottom < bounds.top || viewport.top > bounds.bottom));
570
571
				};
572
573
				/**
574
				 * Maybe show multiple carousel items if set to do so.
575
				 */ 
576
				function aui_carousel_maybe_show_multiple_items($carousel){
577
					var $items = {};
578
					var $item_count = 0;
579
580
					// maybe backup
581
					if(!jQuery($carousel).find('.carousel-inner-original').length){
582
						jQuery($carousel).append('<div class="carousel-inner-original d-none">'+jQuery($carousel).find('.carousel-inner').html()+'</div>');
583
					}
584
585
					// Get the original items html
586
					jQuery($carousel).find('.carousel-inner-original .carousel-item').each(function () {
587
						$items[$item_count] = jQuery(this).html();
588
						$item_count++;
589
					});
590
591
					// bail if no items
592
					if(!$item_count){return;}
593
594
					if(jQuery(window).width() <= 576){
595
						// maybe restore original
596
						if(jQuery($carousel).find('.carousel-inner').hasClass('aui-multiple-items') && jQuery($carousel).find('.carousel-inner-original').length){
597
							jQuery($carousel).find('.carousel-inner').removeClass('aui-multiple-items').html(jQuery($carousel).find('.carousel-inner-original').html());
598
							jQuery($carousel).find(".carousel-indicators li").removeClass("d-none");
599
						}
600
601
					}else{
602
						// new items
603
						var $md_count = jQuery($carousel).data('limit_show');
604
						var $new_items = '';
605
						var $new_items_count = 0;
606
						var $new_item_count = 0;
607
						var $closed = true;
608
						Object.keys($items).forEach(function(key,index) {
609
610
							// close
611
							if(index != 0 && Number.isInteger(index/$md_count) ){
612
								$new_items += '</div></div>';
613
								$closed = true;
614
							}
615
616
							// open
617
							if(index == 0 || Number.isInteger(index/$md_count) ){
618
								$active = index == 0 ? 'active' : '';
619
								$new_items += '<div class="carousel-item '+$active+'"><div class="row m-0">';
620
								$closed = false;
621
								$new_items_count++;
622
								$new_item_count = 0;
623
							}
624
625
							// content
626
							$new_items += '<div class="col pr-1 pl-0">'+$items[index]+'</div>';
627
							$new_item_count++;
628
629
630
						});
631
632
						// close if not closed in the loop
633
						if(!$closed){
634
							// check for spares
635
							if($md_count-$new_item_count > 0){
636
								$placeholder_count = $md_count-$new_item_count;
637
								while($placeholder_count > 0){
638
									$new_items += '<div class="col pr-1 pl-0"></div>';
639
									$placeholder_count--;
640
								}
641
642
							}
643
644
							$new_items += '</div></div>';
645
						}
646
647
						// insert the new items
648
						jQuery($carousel).find('.carousel-inner').addClass('aui-multiple-items').html($new_items);
649
650
						// fix any lazyload images in the active slider
651
						jQuery($carousel).find('.carousel-item.active img').each(function () {
652
							// fix the srcset
653
							if(real_srcset = jQuery(this).attr("data-srcset")){
654
								if(!jQuery(this).attr("srcset")) jQuery(this).attr("srcset",real_srcset);
655
							}
656
							// fix the src
657
							if(real_src = jQuery(this).attr("data-src")){
658
								if(!jQuery(this).attr("srcset"))  jQuery(this).attr("src",real_src);
659
							}
660
						});
661
662
						// maybe fix carousel indicators
663
						$hide_count = $new_items_count-1;
664
						jQuery($carousel).find(".carousel-indicators li:gt("+$hide_count+")").addClass("d-none");
665
					}
666
667
					// trigger a global action to say we have
668
					jQuery( window ).trigger( "aui_carousel_multiple" );
669
				}
670
671
				/**
672
				 * Init Multiple item carousels.
673
				 */ 
674
				function aui_init_carousel_multiple_items(){
675
					jQuery(window).resize(function(){
676
						jQuery('.carousel-multiple-items').each(function () {
677
							aui_carousel_maybe_show_multiple_items(this);
678
						});
679
					});
680
681
					// run now
682
					jQuery('.carousel-multiple-items').each(function () {
683
						aui_carousel_maybe_show_multiple_items(this);
684
					});
685
				}
686
687
				/**
688
				 * Allow navs to use multiple sub menus.
689
				 */
690
				function init_nav_sub_menus(){
691
692
					jQuery('.navbar-multi-sub-menus').each(function(i, obj) {
693
						// Check if already initialized, if so continue.
694
						if(jQuery(this).hasClass("has-sub-sub-menus")){return true;}
695
696
						// Make sure its always expanded
697
						jQuery(this).addClass('has-sub-sub-menus');
698
699
						jQuery(this).find( '.dropdown-menu a.dropdown-toggle' ).on( 'click', function ( e ) {
700
							var $el = jQuery( this );
701
							$el.toggleClass('active-dropdown');
702
							var $parent = jQuery( this ).offsetParent( ".dropdown-menu" );
703
							if ( !jQuery( this ).next().hasClass( 'show' ) ) {
704
								jQuery( this ).parents( '.dropdown-menu' ).first().find( '.show' ).removeClass( "show" );
705
							}
706
							var $subMenu = jQuery( this ).next( ".dropdown-menu" );
707
							$subMenu.toggleClass( 'show' );
708
709
							jQuery( this ).parent( "li" ).toggleClass( 'show' );
710
711
							jQuery( this ).parents( 'li.nav-item.dropdown.show' ).on( 'hidden.bs.dropdown', function ( e ) {
712
								jQuery( '.dropdown-menu .show' ).removeClass( "show" );
713
								$el.removeClass('active-dropdown');
714
							} );
715
716
							if ( !$parent.parent().hasClass( 'navbar-nav' ) ) {
717
								$el.next().addClass('position-relative border-top border-bottom');
718
							}
719
720
							return false;
721
						} );
722
723
					});
724
725
				}
726
				
727
728
				/**
729
				 * Initiate all AUI JS.
730
				 */
731
				function aui_init(){
732
					// nav menu submenus
733
					init_nav_sub_menus();
734
					
735
					// init tooltips
736
					aui_init_tooltips();
737
738
					// init select2
739
					aui_init_select2();
740
741
					// init flatpickr
742
					aui_init_flatpickr();
743
744
					// init Greedy nav
745
					aui_init_greedy_nav();
746
747
					// Set times to time ago
748
					aui_time_ago('timeago');
749
					
750
					// init multiple item carousels
751
					aui_init_carousel_multiple_items();
752
				}
753
754
				// run on window loaded
755
				jQuery(window).on("load",function() {
756
					aui_init();
757
				});
758
759
			</script>
760
			<?php
761
			$output = ob_get_clean();
762
763
			/*
764
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
765
			 */
766
			return str_replace( array(
767
				'<script>',
768
				'</script>'
769
			), '', $output );
770
		}
771
772
		/**
773
		 * Get inline script used if bootstrap file browser enqueued.
774
		 *
775
		 * If this remains small then its best to use this than to add another JS file.
776
		 */
777
		public function inline_script_file_browser(){
778
			ob_start();
779
			?>
780
			<script>
781
				// run on doc ready
782
				jQuery(document).ready(function () {
783
					bsCustomFileInput.init();
784
				});
785
			</script>
786
			<?php
787
			$output = ob_get_clean();
788
789
			/*
790
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
791
			 */
792
			return str_replace( array(
793
				'<script>',
794
				'</script>'
795
			), '', $output );
796
		}
797
798
		/**
799
		 * Adds the Font Awesome JS.
800
		 */
801
		public function enqueue_scripts() {
802
803
			$js_setting = current_action() == 'wp_enqueue_scripts' ? 'js' : 'js_backend';
804
805
			// select2
806
			wp_register_script( 'select2', $this->url.'assets/js/select2.min.js', array('jquery'), $this->select2_version );
807
808
			// flatpickr
809
			wp_register_script( 'flatpickr', $this->url.'assets/js/flatpickr.min.js', array(), $this->latest );
810
811
			// Bootstrap file browser
812
			wp_register_script( 'aui-custom-file-input', $url = $this->url.'assets/js/bs-custom-file-input.min.js', array('jquery'), $this->select2_version );
813
			wp_add_inline_script( 'aui-custom-file-input', $this->inline_script_file_browser() );
814
815
			$load_inline = false;
816
817
			if($this->settings[$js_setting]=='core-popper'){
818
				// Bootstrap bundle
819
				$url = $this->url.'assets/js/bootstrap.bundle.min.js';
820
				wp_register_script( 'bootstrap-js-bundle', $url, array('select2','jquery'), $this->latest );
821
				// if in admin then add to footer for compatibility.
822
				is_admin() ? wp_enqueue_script( 'bootstrap-js-bundle', '', null, null, true ) : wp_enqueue_script( 'bootstrap-js-bundle');
823
				$script = $this->inline_script();
824
				wp_add_inline_script( 'bootstrap-js-bundle', $script );
825
			}elseif($this->settings[$js_setting]=='popper'){
826
				$url = $this->url.'assets/js/popper.min.js';
827
				wp_register_script( 'bootstrap-js-popper', $url, array('jquery'), $this->latest );
828
				wp_enqueue_script( 'bootstrap-js-popper' );
829
				$load_inline = true;
830
			}else{
831
				$load_inline = true;
832
			}
833
834
			// Load needed inline scripts by faking the loading of a script if the main script is not being loaded
835
			if($load_inline){
836
				wp_register_script( 'bootstrap-dummy', '',array('jquery') );
837
				wp_enqueue_script( 'bootstrap-dummy' );
838
				$script = $this->inline_script();
839
				wp_add_inline_script( 'bootstrap-dummy', $script  );
840
			}
841
842
		}
843
844
		/**
845
		 * Enqueue flatpickr if called.
846
		 */
847
		public function enqueue_flatpickr(){
848
			wp_enqueue_style( 'flatpickr' );
849
			wp_enqueue_script( 'flatpickr' );
850
		}
851
852
		/**
853
		 * Get the url path to the current folder.
854
		 *
855
		 * @return string
856
		 */
857
		public function get_url() {
858
859
			$url = '';
860
			// check if we are inside a plugin
861
			$file_dir = str_replace( "/includes","", wp_normalize_path( dirname( __FILE__ ) ) );
862
863
			// add check in-case user has changed wp-content dir name.
864
			$wp_content_folder_name = basename(WP_CONTENT_DIR);
865
			$dir_parts = explode("/$wp_content_folder_name/",$file_dir);
866
			$url_parts = explode("/$wp_content_folder_name/",plugins_url());
867
868
			if(!empty($url_parts[0]) && !empty($dir_parts[1])){
869
				$url = trailingslashit( $url_parts[0]."/$wp_content_folder_name/".$dir_parts[1] );
870
			}
871
872
			return $url;
873
		}
874
875
		/**
876
		 * Register the database settings with WordPress.
877
		 */
878
		public function register_settings() {
879
			register_setting( 'ayecode-ui-settings', 'ayecode-ui-settings' );
880
		}
881
882
		/**
883
		 * Add the WordPress settings menu item.
884
		 * @since 1.0.10 Calling function name direct will fail theme check so we don't.
885
		 */
886
		public function menu_item() {
887
			$menu_function = 'add' . '_' . 'options' . '_' . 'page'; // won't pass theme check if function name present in theme
888
			call_user_func( $menu_function, $this->name, $this->name, 'manage_options', 'ayecode-ui-settings', array(
889
				$this,
890
				'settings_page'
891
			) );
892
		}
893
894
		/**
895
		 * Get a list of themes and their default JS settings.
896
		 *
897
		 * @return array
898
		 */
899
		public function theme_js_settings(){
900
			return array(
901
				'ayetheme' => 'popper',
902
				'listimia' => 'required',
903
				'listimia_backend' => 'core-popper',
904
				'avada'    => 'required',
905
			);
906
		}
907
908
		/**
909
		 * Get the current Font Awesome output settings.
910
		 *
911
		 * @return array The array of settings.
912
		 */
913
		public function get_settings() {
914
915
			$db_settings = get_option( 'ayecode-ui-settings' );
916
			$js_default = 'core-popper';
917
			$js_default_backend = $js_default;
918
919
			// maybe set defaults (if no settings set)
920
			if(empty($db_settings)){
921
				$active_theme = strtolower( get_template() ); // active parent theme.
922
				$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

922
				/** @scrutinizer ignore-call */ 
923
    $theme_js_settings = self::theme_js_settings();
Loading history...
923
				if(isset($theme_js_settings[$active_theme])){
924
					$js_default = $theme_js_settings[$active_theme];
925
					$js_default_backend = isset($theme_js_settings[$active_theme."_backend"]) ? $theme_js_settings[$active_theme."_backend"] : $js_default;
926
				}
927
			}
928
929
			$defaults = array(
930
				'css'       => 'compatibility', // core, compatibility
931
				'js'        => $js_default, // js to load, core-popper, popper
932
				'html_font_size'        => '16', // js to load, core-popper, popper
933
				'css_backend'       => 'compatibility', // core, compatibility
934
				'js_backend'        => $js_default_backend, // js to load, core-popper, popper
935
				'disable_admin'     =>  '', // URL snippets to disable loading on admin
936
			);
937
938
			$settings = wp_parse_args( $db_settings, $defaults );
939
940
			/**
941
			 * Filter the Bootstrap settings.
942
			 *
943
			 * @todo if we add this filer people might use it and then it defeates the purpose of this class :/
944
			 */
945
			return $this->settings = apply_filters( 'ayecode-ui-settings', $settings, $db_settings, $defaults );
946
		}
947
948
949
		/**
950
		 * The settings page html output.
951
		 */
952
		public function settings_page() {
953
			if ( ! current_user_can( 'manage_options' ) ) {
954
				wp_die( __( 'You do not have sufficient permissions to access this page.', 'aui' ) );
955
			}
956
			?>
957
			<div class="wrap">
958
				<h1><?php echo $this->name; ?></h1>
959
				<p><?php _e("Here you can adjust settings if you are having compatibility issues.","aui");?></p>
960
				<form method="post" action="options.php">
961
					<?php
962
					settings_fields( 'ayecode-ui-settings' );
963
					do_settings_sections( 'ayecode-ui-settings' );
964
					?>
965
966
					<h2><?php _e( 'Frontend', 'aui' ); ?></h2>
967
					<table class="form-table wpbs-table-settings">
968
						<tr valign="top">
969
							<th scope="row"><label
970
									for="wpbs-css"><?php _e( 'Load CSS', 'aui' ); ?></label></th>
971
							<td>
972
								<select name="ayecode-ui-settings[css]" id="wpbs-css">
973
									<option	value="compatibility" <?php selected( $this->settings['css'], 'compatibility' ); ?>><?php _e( 'Compatibility Mode', 'aui' ); ?></option>
974
									<option value="core" <?php selected( $this->settings['css'], 'core' ); ?>><?php _e( 'Full Mode', 'aui' ); ?></option>
975
									<option	value="" <?php selected( $this->settings['css'], '' ); ?>><?php _e( 'Disabled', 'aui' ); ?></option>
976
								</select>
977
							</td>
978
						</tr>
979
980
						<tr valign="top">
981
							<th scope="row"><label
982
									for="wpbs-js"><?php _e( 'Load JS', 'aui' ); ?></label></th>
983
							<td>
984
								<select name="ayecode-ui-settings[js]" id="wpbs-js">
985
									<option	value="core-popper" <?php selected( $this->settings['js'], 'core-popper' ); ?>><?php _e( 'Core + Popper (default)', 'aui' ); ?></option>
986
									<option value="popper" <?php selected( $this->settings['js'], 'popper' ); ?>><?php _e( 'Popper', 'aui' ); ?></option>
987
									<option value="required" <?php selected( $this->settings['js'], 'required' ); ?>><?php _e( 'Required functions only', 'aui' ); ?></option>
988
									<option	value="" <?php selected( $this->settings['js'], '' ); ?>><?php _e( 'Disabled (not recommended)', 'aui' ); ?></option>
989
								</select>
990
							</td>
991
						</tr>
992
993
						<tr valign="top">
994
							<th scope="row"><label
995
									for="wpbs-font_size"><?php _e( 'HTML Font Size (px)', 'aui' ); ?></label></th>
996
							<td>
997
								<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" />
998
								<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>
999
							</td>
1000
						</tr>
1001
1002
					</table>
1003
1004
					<h2><?php _e( 'Backend', 'aui' ); ?> (wp-admin)</h2>
1005
					<table class="form-table wpbs-table-settings">
1006
						<tr valign="top">
1007
							<th scope="row"><label
1008
									for="wpbs-css-admin"><?php _e( 'Load CSS', 'aui' ); ?></label></th>
1009
							<td>
1010
								<select name="ayecode-ui-settings[css_backend]" id="wpbs-css-admin">
1011
									<option	value="compatibility" <?php selected( $this->settings['css_backend'], 'compatibility' ); ?>><?php _e( 'Compatibility Mode', 'aui' ); ?></option>
1012
									<option value="core" <?php selected( $this->settings['css_backend'], 'core' ); ?>><?php _e( 'Full Mode', 'aui' ); ?></option>
1013
									<option	value="" <?php selected( $this->settings['css_backend'], '' ); ?>><?php _e( 'Disabled', 'aui' ); ?></option>
1014
								</select>
1015
							</td>
1016
						</tr>
1017
1018
						<tr valign="top">
1019
							<th scope="row"><label
1020
									for="wpbs-js-admin"><?php _e( 'Load JS', 'aui' ); ?></label></th>
1021
							<td>
1022
								<select name="ayecode-ui-settings[js_backend]" id="wpbs-js-admin">
1023
									<option	value="core-popper" <?php selected( $this->settings['js_backend'], 'core-popper' ); ?>><?php _e( 'Core + Popper (default)', 'aui' ); ?></option>
1024
									<option value="popper" <?php selected( $this->settings['js_backend'], 'popper' ); ?>><?php _e( 'Popper', 'aui' ); ?></option>
1025
									<option value="required" <?php selected( $this->settings['js_backend'], 'required' ); ?>><?php _e( 'Required functions only', 'aui' ); ?></option>
1026
									<option	value="" <?php selected( $this->settings['js_backend'], '' ); ?>><?php _e( 'Disabled (not recommended)', 'aui' ); ?></option>
1027
								</select>
1028
							</td>
1029
						</tr>
1030
1031
						<tr valign="top">
1032
							<th scope="row"><label
1033
									for="wpbs-disable-admin"><?php _e( 'Disable load on URL', 'aui' ); ?></label></th>
1034
							<td>
1035
								<p><?php _e( 'If you have backend conflict you can enter a partial URL argument that will disable the loading of AUI on those pages. Add each argument on a new line.', 'aui' ); ?></p>
1036
								<textarea name="ayecode-ui-settings[disable_admin]" rows="10" cols="50" id="wpbs-disable-admin" class="large-text code" spellcheck="false" placeholder="myplugin.php &#10;action=go"><?php echo $this->settings['disable_admin'];?></textarea>
1037
1038
							</td>
1039
						</tr>
1040
1041
					</table>
1042
1043
					<?php
1044
					submit_button();
1045
					?>
1046
				</form>
1047
1048
				<div id="wpbs-version"><?php echo $this->version; ?></div>
1049
			</div>
1050
1051
			<?php
1052
		}
1053
1054
		public function customizer_settings($wp_customize){
1055
			$wp_customize->add_section('aui_settings', array(
1056
				'title'    => __('AyeCode UI','aui'),
1057
				'priority' => 120,
1058
			));
1059
1060
			//  =============================
1061
			//  = Color Picker              =
1062
			//  =============================
1063
			$wp_customize->add_setting('aui_options[color_primary]', array(
1064
				'default'           => AUI_PRIMARY_COLOR,
1065
				'sanitize_callback' => 'sanitize_hex_color',
1066
				'capability'        => 'edit_theme_options',
1067
				'type'              => 'option',
1068
				'transport'         => 'refresh',
1069
			));
1070
			$wp_customize->add_control( new WP_Customize_Color_Control($wp_customize, 'color_primary', array(
1071
				'label'    => __('Primary Color','aui'),
1072
				'section'  => 'aui_settings',
1073
				'settings' => 'aui_options[color_primary]',
1074
			)));
1075
1076
			$wp_customize->add_setting('aui_options[color_secondary]', array(
1077
				'default'           => '#6c757d',
1078
				'sanitize_callback' => 'sanitize_hex_color',
1079
				'capability'        => 'edit_theme_options',
1080
				'type'              => 'option',
1081
				'transport'         => 'refresh',
1082
			));
1083
			$wp_customize->add_control( new WP_Customize_Color_Control($wp_customize, 'color_secondary', array(
1084
				'label'    => __('Secondary Color','aui'),
1085
				'section'  => 'aui_settings',
1086
				'settings' => 'aui_options[color_secondary]',
1087
			)));
1088
		}
1089
1090
1091
		public static function custom_css($compatibility = true) {
1092
			$settings = get_option('aui_options');
1093
1094
			ob_start();
1095
1096
			$primary_color = !empty($settings['color_primary']) ? $settings['color_primary'] : AUI_PRIMARY_COLOR;
1097
			$secondary_color = !empty($settings['color_secondary']) ? $settings['color_secondary'] : AUI_SECONDARY_COLOR;
1098
				//AUI_PRIMARY_COLOR_ORIGINAL
1099
			?>
1100
			<style>
1101
				<?php
1102
					if(!is_admin() && $primary_color != AUI_PRIMARY_COLOR_ORIGINAL){
1103
						echo self::css_primary($primary_color,$compatibility);
1104
					}
1105
1106
					if(!is_admin() && $secondary_color != AUI_SECONDARY_COLOR_ORIGINAL){
1107
						echo self::css_secondary($settings['color_secondary'],$compatibility);
1108
					}
1109
                ?>
1110
			</style>
1111
			<?php
1112
1113
1114
			/*
1115
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1116
			 */
1117
			return str_replace( array(
1118
				'<style>',
1119
				'</style>'
1120
			), '', ob_get_clean());
1121
		}
1122
1123
		public static function css_primary($color_code,$compatibility){;
1124
			$color_code = sanitize_hex_color($color_code);
1125
			if(!$color_code){return '';}
1126
			/**
1127
			 * c = color, b = background color, o = border-color, f = fill
1128
			 */
1129
			$selectors = array(
1130
				'a' => array('c'),
1131
				'.btn-primary' => array('b','o'),
1132
				'.btn-primary.disabled' => array('b','o'),
1133
				'.btn-primary:disabled' => array('b','o'),
1134
				'.btn-outline-primary' => array('c','o'),
1135
				'.btn-outline-primary:hover' => array('b','o'),
1136
				'.btn-outline-primary:not(:disabled):not(.disabled).active' => array('b','o'),
1137
				'.btn-outline-primary:not(:disabled):not(.disabled):active' => array('b','o'),
1138
				'.show>.btn-outline-primary.dropdown-toggle' => array('b','o'),
1139
				'.btn-link' => array('c'),
1140
				'.dropdown-item.active' => array('b'),
1141
				'.custom-control-input:checked~.custom-control-label::before' => array('b','o'),
1142
				'.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before' => array('b','o'),
1143
//				'.custom-range::-webkit-slider-thumb' => array('b'), // these break the inline rules...
1144
//				'.custom-range::-moz-range-thumb' => array('b'),
1145
//				'.custom-range::-ms-thumb' => array('b'),
1146
				'.nav-pills .nav-link.active' => array('b'),
1147
				'.nav-pills .show>.nav-link' => array('b'),
1148
				'.page-link' => array('c'),
1149
				'.page-item.active .page-link' => array('b','o'),
1150
				'.badge-primary' => array('b'),
1151
				'.alert-primary' => array('b','o'),
1152
				'.progress-bar' => array('b'),
1153
				'.list-group-item.active' => array('b','o'),
1154
				'.bg-primary' => array('b','f'),
1155
				'.btn-link.btn-primary' => array('c'),
1156
				'.select2-container .select2-results__option--highlighted.select2-results__option[aria-selected=true]' => array('b'),
1157
			);
1158
1159
			$important_selectors = array(
1160
				'.bg-primary' => array('b','f'),
1161
				'.border-primary' => array('o'),
1162
				'.text-primary' => array('c'),
1163
			);
1164
1165
			$color = array();
1166
			$color_i = array();
1167
			$background = array();
1168
			$background_i = array();
1169
			$border = array();
1170
			$border_i = array();
1171
			$fill = array();
1172
			$fill_i = array();
1173
1174
			$output = '';
1175
1176
			// build rules into each type
1177
			foreach($selectors as $selector => $types){
1178
				$selector = $compatibility ? ".bsui ".$selector : $selector;
1179
				$types = array_combine($types,$types);
1180
				if(isset($types['c'])){$color[] = $selector;}
1181
				if(isset($types['b'])){$background[] = $selector;}
1182
				if(isset($types['o'])){$border[] = $selector;}
1183
				if(isset($types['f'])){$fill[] = $selector;}
1184
			}
1185
1186
			// build rules into each type
1187
			foreach($important_selectors as $selector => $types){
1188
				$selector = $compatibility ? ".bsui ".$selector : $selector;
1189
				$types = array_combine($types,$types);
1190
				if(isset($types['c'])){$color_i[] = $selector;}
1191
				if(isset($types['b'])){$background_i[] = $selector;}
1192
				if(isset($types['o'])){$border_i[] = $selector;}
1193
				if(isset($types['f'])){$fill_i[] = $selector;}
1194
			}
1195
1196
			// add any color rules
1197
			if(!empty($color)){
1198
				$output .= implode(",",$color) . "{color: $color_code;} ";
1199
			}
1200
			if(!empty($color_i)){
1201
				$output .= implode(",",$color_i) . "{color: $color_code !important;} ";
1202
			}
1203
1204
			// add any background color rules
1205
			if(!empty($background)){
1206
				$output .= implode(",",$background) . "{background-color: $color_code;} ";
1207
			}
1208
			if(!empty($background_i)){
1209
				$output .= implode(",",$background_i) . "{background-color: $color_code !important;} ";
1210
			}
1211
1212
			// add any border color rules
1213
			if(!empty($border)){
1214
				$output .= implode(",",$border) . "{border-color: $color_code;} ";
1215
			}
1216
			if(!empty($border_i)){
1217
				$output .= implode(",",$border_i) . "{border-color: $color_code !important;} ";
1218
			}
1219
1220
			// add any fill color rules
1221
			if(!empty($fill)){
1222
				$output .= implode(",",$fill) . "{fill: $color_code;} ";
1223
			}
1224
			if(!empty($fill_i)){
1225
				$output .= implode(",",$fill_i) . "{fill: $color_code !important;} ";
1226
			}
1227
1228
1229
			$prefix = $compatibility ? ".bsui " : "";
1230
1231
			// darken
1232
			$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

1232
			$darker_075 = self::css_hex_lighten_darken($color_code,/** @scrutinizer ignore-type */ "-0.075");
Loading history...
1233
			$darker_10 = self::css_hex_lighten_darken($color_code,"-0.10");
1234
			$darker_125 = self::css_hex_lighten_darken($color_code,"-0.125");
1235
1236
			// lighten
1237
			$lighten_25 = self::css_hex_lighten_darken($color_code,"0.25");
1238
1239
			// opacity see https://css-tricks.com/8-digit-hex-codes/
1240
			$op_25 = $color_code."40"; // 25% opacity
1241
1242
1243
			// button states
1244
			$output .= $prefix ." .btn-primary:hover{background-color: ".$darker_075.";    border-color: ".$darker_10.";} ";
1245
			$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;} ";
1246
			$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.";} ";
1247
			$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;} ";
1248
1249
1250
			// dropdown's
1251
			$output .= $prefix ." .dropdown-item.active, $prefix .dropdown-item:active{background-color: $color_code;} ";
1252
1253
1254
			// input states
1255
			$output .= $prefix ." .form-control:focus{border-color: ".$lighten_25.";box-shadow: 0 0 0 0.2rem $op_25;} ";
1256
1257
			// page link
1258
			$output .= $prefix ." .page-link:focus{box-shadow: 0 0 0 0.2rem $op_25;} ";
1259
1260
			return $output;
1261
		}
1262
1263
		public static function css_secondary($color_code,$compatibility){;
1264
			$color_code = sanitize_hex_color($color_code);
1265
			if(!$color_code){return '';}
1266
			/**
1267
			 * c = color, b = background color, o = border-color, f = fill
1268
			 */
1269
			$selectors = array(
1270
				'.btn-secondary' => array('b','o'),
1271
				'.btn-secondary.disabled' => array('b','o'),
1272
				'.btn-secondary:disabled' => array('b','o'),
1273
				'.btn-outline-secondary' => array('c','o'),
1274
				'.btn-outline-secondary:hover' => array('b','o'),
1275
				'.btn-outline-secondary.disabled' => array('c'),
1276
				'.btn-outline-secondary:disabled' => array('c'),
1277
				'.btn-outline-secondary:not(:disabled):not(.disabled):active' => array('b','o'),
1278
				'.btn-outline-secondary:not(:disabled):not(.disabled).active' => array('b','o'),
1279
				'.btn-outline-secondary.dropdown-toggle' => array('b','o'),
1280
				'.badge-secondary' => array('b'),
1281
				'.alert-secondary' => array('b','o'),
1282
				'.btn-link.btn-secondary' => array('c'),
1283
			);
1284
1285
			$important_selectors = array(
1286
				'.bg-secondary' => array('b','f'),
1287
				'.border-secondary' => array('o'),
1288
				'.text-secondary' => array('c'),
1289
			);
1290
1291
			$color = array();
1292
			$color_i = array();
1293
			$background = array();
1294
			$background_i = array();
1295
			$border = array();
1296
			$border_i = array();
1297
			$fill = array();
1298
			$fill_i = array();
1299
1300
			$output = '';
1301
1302
			// build rules into each type
1303
			foreach($selectors as $selector => $types){
1304
				$selector = $compatibility ? ".bsui ".$selector : $selector;
1305
				$types = array_combine($types,$types);
1306
				if(isset($types['c'])){$color[] = $selector;}
1307
				if(isset($types['b'])){$background[] = $selector;}
1308
				if(isset($types['o'])){$border[] = $selector;}
1309
				if(isset($types['f'])){$fill[] = $selector;}
1310
			}
1311
1312
			// build rules into each type
1313
			foreach($important_selectors as $selector => $types){
1314
				$selector = $compatibility ? ".bsui ".$selector : $selector;
1315
				$types = array_combine($types,$types);
1316
				if(isset($types['c'])){$color_i[] = $selector;}
1317
				if(isset($types['b'])){$background_i[] = $selector;}
1318
				if(isset($types['o'])){$border_i[] = $selector;}
1319
				if(isset($types['f'])){$fill_i[] = $selector;}
1320
			}
1321
1322
			// add any color rules
1323
			if(!empty($color)){
1324
				$output .= implode(",",$color) . "{color: $color_code;} ";
1325
			}
1326
			if(!empty($color_i)){
1327
				$output .= implode(",",$color_i) . "{color: $color_code !important;} ";
1328
			}
1329
1330
			// add any background color rules
1331
			if(!empty($background)){
1332
				$output .= implode(",",$background) . "{background-color: $color_code;} ";
1333
			}
1334
			if(!empty($background_i)){
1335
				$output .= implode(",",$background_i) . "{background-color: $color_code !important;} ";
1336
			}
1337
1338
			// add any border color rules
1339
			if(!empty($border)){
1340
				$output .= implode(",",$border) . "{border-color: $color_code;} ";
1341
			}
1342
			if(!empty($border_i)){
1343
				$output .= implode(",",$border_i) . "{border-color: $color_code !important;} ";
1344
			}
1345
1346
			// add any fill color rules
1347
			if(!empty($fill)){
1348
				$output .= implode(",",$fill) . "{fill: $color_code;} ";
1349
			}
1350
			if(!empty($fill_i)){
1351
				$output .= implode(",",$fill_i) . "{fill: $color_code !important;} ";
1352
			}
1353
1354
1355
			$prefix = $compatibility ? ".bsui " : "";
1356
1357
			// darken
1358
			$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

1358
			$darker_075 = self::css_hex_lighten_darken($color_code,/** @scrutinizer ignore-type */ "-0.075");
Loading history...
1359
			$darker_10 = self::css_hex_lighten_darken($color_code,"-0.10");
1360
			$darker_125 = self::css_hex_lighten_darken($color_code,"-0.125");
1361
1362
			// lighten
1363
			$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...
1364
1365
			// opacity see https://css-tricks.com/8-digit-hex-codes/
1366
			$op_25 = $color_code."40"; // 25% opacity
1367
1368
1369
			// button states
1370
			$output .= $prefix ." .btn-secondary:hover{background-color: ".$darker_075.";    border-color: ".$darker_10.";} ";
1371
			$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;} ";
1372
			$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.";} ";
1373
			$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;} ";
1374
1375
1376
			return $output;
1377
		}
1378
1379
		/**
1380
		 * Increases or decreases the brightness of a color by a percentage of the current brightness.
1381
		 *
1382
		 * @param   string  $hexCode        Supported formats: `#FFF`, `#FFFFFF`, `FFF`, `FFFFFF`
1383
		 * @param   float   $adjustPercent  A number between -1 and 1. E.g. 0.3 = 30% lighter; -0.4 = 40% darker.
1384
		 *
1385
		 * @return  string
1386
		 */
1387
		public static function css_hex_lighten_darken($hexCode, $adjustPercent) {
1388
			$hexCode = ltrim($hexCode, '#');
1389
1390
			if (strlen($hexCode) == 3) {
1391
				$hexCode = $hexCode[0] . $hexCode[0] . $hexCode[1] . $hexCode[1] . $hexCode[2] . $hexCode[2];
1392
			}
1393
1394
			$hexCode = array_map('hexdec', str_split($hexCode, 2));
1395
1396
			foreach ($hexCode as & $color) {
1397
				$adjustableLimit = $adjustPercent < 0 ? $color : 255 - $color;
1398
				$adjustAmount = ceil($adjustableLimit * $adjustPercent);
1399
1400
				$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

1400
				$color = str_pad(dechex(/** @scrutinizer ignore-type */ $color + $adjustAmount), 2, '0', STR_PAD_LEFT);
Loading history...
1401
			}
1402
1403
			return '#' . implode($hexCode);
1404
		}
1405
1406
		/**
1407
		 * Check if we should display examples.
1408
		 */
1409
		public function maybe_show_examples(){
1410
			if(current_user_can('manage_options') && isset($_REQUEST['preview-aui'])){
1411
				echo "<head>";
1412
				wp_head();
1413
				echo "</head>";
1414
				echo "<body>";
1415
				echo $this->get_examples();
1416
				echo "</body>";
1417
				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...
1418
			}
1419
		}
1420
1421
		/**
1422
		 * Get developer examples.
1423
		 *
1424
		 * @return string
1425
		 */
1426
		public function get_examples(){
1427
			$output = '';
1428
1429
1430
			// open form
1431
			$output .= "<form class='p-5 m-5 border rounded'>";
1432
1433
			// input example
1434
			$output .= aui()->input(array(
1435
				'type'  =>  'text',
1436
				'id'    =>  'text-example',
1437
				'name'    =>  'text-example',
1438
				'placeholder'   => 'text placeholder',
1439
				'title'   => 'Text input example',
1440
				'value' =>  '',
1441
				'required'  => false,
1442
				'help_text' => 'help text',
1443
				'label' => 'Text input example label'
1444
			));
1445
1446
			// input example
1447
			$output .= aui()->input(array(
1448
				'type'  =>  'url',
1449
				'id'    =>  'text-example2',
1450
				'name'    =>  'text-example',
1451
				'placeholder'   => 'url placeholder',
1452
				'title'   => 'Text input example',
1453
				'value' =>  '',
1454
				'required'  => false,
1455
				'help_text' => 'help text',
1456
				'label' => 'Text input example label'
1457
			));
1458
1459
			// checkbox example
1460
			$output .= aui()->input(array(
1461
				'type'  =>  'checkbox',
1462
				'id'    =>  'checkbox-example',
1463
				'name'    =>  'checkbox-example',
1464
				'placeholder'   => 'checkbox-example',
1465
				'title'   => 'Checkbox example',
1466
				'value' =>  '1',
1467
				'checked'   => true,
1468
				'required'  => false,
1469
				'help_text' => 'help text',
1470
				'label' => 'Checkbox checked'
1471
			));
1472
1473
			// checkbox example
1474
			$output .= aui()->input(array(
1475
				'type'  =>  'checkbox',
1476
				'id'    =>  'checkbox-example2',
1477
				'name'    =>  'checkbox-example2',
1478
				'placeholder'   => 'checkbox-example',
1479
				'title'   => 'Checkbox example',
1480
				'value' =>  '1',
1481
				'checked'   => false,
1482
				'required'  => false,
1483
				'help_text' => 'help text',
1484
				'label' => 'Checkbox un-checked'
1485
			));
1486
1487
			// switch example
1488
			$output .= aui()->input(array(
1489
				'type'  =>  'checkbox',
1490
				'id'    =>  'switch-example',
1491
				'name'    =>  'switch-example',
1492
				'placeholder'   => 'checkbox-example',
1493
				'title'   => 'Switch example',
1494
				'value' =>  '1',
1495
				'checked'   => true,
1496
				'switch'    => true,
1497
				'required'  => false,
1498
				'help_text' => 'help text',
1499
				'label' => 'Switch on'
1500
			));
1501
1502
			// switch example
1503
			$output .= aui()->input(array(
1504
				'type'  =>  'checkbox',
1505
				'id'    =>  'switch-example2',
1506
				'name'    =>  'switch-example2',
1507
				'placeholder'   => 'checkbox-example',
1508
				'title'   => 'Switch example',
1509
				'value' =>  '1',
1510
				'checked'   => false,
1511
				'switch'    => true,
1512
				'required'  => false,
1513
				'help_text' => 'help text',
1514
				'label' => 'Switch off'
1515
			));
1516
1517
			// close form
1518
			$output .= "</form>";
1519
1520
			return $output;
1521
		}
1522
1523
	}
1524
1525
	/**
1526
	 * Run the class if found.
1527
	 */
1528
	AyeCode_UI_Settings::instance();
1529
}