Passed
Push — master ( 630150...78277f )
by Brian
05:00
created

AyeCode_UI_Settings::is_aui_screen()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 22
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 3
nop 0
dl 0
loc 22
rs 9.9
c 0
b 0
f 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 = '0.1.43';
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.5.3";
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
				$priority = $this->is_bs3_compat() ? 100 : 1;
156
				add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ), $priority );
157
			}
158
			if ( $this->settings['js_backend'] && $this->load_admin_scripts() ) {
159
				add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), 1 );
160
			}
161
162
			// Maybe set the HTML font size
163
			if ( $this->settings['html_font_size'] ) {
164
				add_action( 'wp_footer', array( $this, 'html_font_size' ), 10 );
165
			}
166
167
168
		}
169
170
		/**
171
		 * Check if we should load the admin scripts or not.
172
		 *
173
		 * @return bool
174
		 */
175
		public function load_admin_scripts(){
176
			$result = true;
177
178
			// check if specifically disabled
179
			if(!empty($this->settings['disable_admin'])){
180
				$url_parts = explode("\n",$this->settings['disable_admin']);
181
				foreach($url_parts as $part){
182
					if( strpos($_SERVER['REQUEST_URI'], trim($part)) !== false ){
183
						return false; // return early, no point checking further
184
					}
185
				}
186
			}
187
188
			return $result;
189
		}
190
191
		/**
192
		 * Add a html font size to the footer.
193
		 */
194
		public function html_font_size(){
195
			$this->settings = $this->get_settings();
196
			echo "<style>html{font-size:".absint($this->settings['html_font_size'])."px;}</style>";
197
		}
198
199
		/**
200
		 * Check if the current admin screen should load scripts.
201
		 * 
202
		 * @return bool
203
		 */
204
		public function is_aui_screen(){
205
			$load = false;
206
			// check if we should load or not
207
			if ( is_admin() ) {
208
				// Only enable on set pages
209
				$aui_screens = array(
210
					'page',
211
					'post',
212
					'settings_page_ayecode-ui-settings'
213
				);
214
				$screen_ids = apply_filters( 'aui_screen_ids', $aui_screens );
215
216
				$screen = get_current_screen();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $screen is correct as get_current_screen() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

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

997
				/** @scrutinizer ignore-call */ 
998
    $theme_js_settings = self::theme_js_settings();
Loading history...
998
				if(isset($theme_js_settings[$active_theme])){
999
					$js_default = $theme_js_settings[$active_theme];
1000
					$js_default_backend = isset($theme_js_settings[$active_theme."_backend"]) ? $theme_js_settings[$active_theme."_backend"] : $js_default;
1001
				}
1002
			}
1003
1004
			$defaults = array(
1005
				'css'       => 'compatibility', // core, compatibility
1006
				'js'        => $js_default, // js to load, core-popper, popper
1007
				'html_font_size'        => '16', // js to load, core-popper, popper
1008
				'css_backend'       => 'compatibility', // core, compatibility
1009
				'js_backend'        => $js_default_backend, // js to load, core-popper, popper
1010
				'disable_admin'     =>  '', // URL snippets to disable loading on admin
1011
			);
1012
1013
			$settings = wp_parse_args( $db_settings, $defaults );
1014
1015
			/**
1016
			 * Filter the Bootstrap settings.
1017
			 *
1018
			 * @todo if we add this filer people might use it and then it defeates the purpose of this class :/
1019
			 */
1020
			return $this->settings = apply_filters( 'ayecode-ui-settings', $settings, $db_settings, $defaults );
1021
		}
1022
1023
1024
		/**
1025
		 * The settings page html output.
1026
		 */
1027
		public function settings_page() {
1028
			if ( ! current_user_can( 'manage_options' ) ) {
1029
				wp_die( __( 'You do not have sufficient permissions to access this page.', 'aui' ) );
1030
			}
1031
			?>
1032
			<div class="wrap">
1033
				<h1><?php echo $this->name; ?></h1>
1034
				<p><?php _e("Here you can adjust settings if you are having compatibility issues.","aui");?></p>
1035
				<form method="post" action="options.php">
1036
					<?php
1037
					settings_fields( 'ayecode-ui-settings' );
1038
					do_settings_sections( 'ayecode-ui-settings' );
1039
					?>
1040
1041
					<h2><?php _e( 'Frontend', 'aui' ); ?></h2>
1042
					<table class="form-table wpbs-table-settings">
1043
						<tr valign="top">
1044
							<th scope="row"><label
1045
									for="wpbs-css"><?php _e( 'Load CSS', 'aui' ); ?></label></th>
1046
							<td>
1047
								<select name="ayecode-ui-settings[css]" id="wpbs-css">
1048
									<option	value="compatibility" <?php selected( $this->settings['css'], 'compatibility' ); ?>><?php _e( 'Compatibility Mode (default)', 'aui' ); ?></option>
1049
									<option value="core" <?php selected( $this->settings['css'], 'core' ); ?>><?php _e( 'Full Mode', 'aui' ); ?></option>
1050
									<option	value="" <?php selected( $this->settings['css'], '' ); ?>><?php _e( 'Disabled', 'aui' ); ?></option>
1051
								</select>
1052
							</td>
1053
						</tr>
1054
1055
						<tr valign="top">
1056
							<th scope="row"><label
1057
									for="wpbs-js"><?php _e( 'Load JS', 'aui' ); ?></label></th>
1058
							<td>
1059
								<select name="ayecode-ui-settings[js]" id="wpbs-js">
1060
									<option	value="core-popper" <?php selected( $this->settings['js'], 'core-popper' ); ?>><?php _e( 'Core + Popper (default)', 'aui' ); ?></option>
1061
									<option value="popper" <?php selected( $this->settings['js'], 'popper' ); ?>><?php _e( 'Popper', 'aui' ); ?></option>
1062
									<option value="required" <?php selected( $this->settings['js'], 'required' ); ?>><?php _e( 'Required functions only', 'aui' ); ?></option>
1063
									<option	value="" <?php selected( $this->settings['js'], '' ); ?>><?php _e( 'Disabled (not recommended)', 'aui' ); ?></option>
1064
								</select>
1065
							</td>
1066
						</tr>
1067
1068
						<tr valign="top">
1069
							<th scope="row"><label
1070
									for="wpbs-font_size"><?php _e( 'HTML Font Size (px)', 'aui' ); ?></label></th>
1071
							<td>
1072
								<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" />
1073
								<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>
1074
							</td>
1075
						</tr>
1076
1077
					</table>
1078
1079
					<h2><?php _e( 'Backend', 'aui' ); ?> (wp-admin)</h2>
1080
					<table class="form-table wpbs-table-settings">
1081
						<tr valign="top">
1082
							<th scope="row"><label
1083
									for="wpbs-css-admin"><?php _e( 'Load CSS', 'aui' ); ?></label></th>
1084
							<td>
1085
								<select name="ayecode-ui-settings[css_backend]" id="wpbs-css-admin">
1086
									<option	value="compatibility" <?php selected( $this->settings['css_backend'], 'compatibility' ); ?>><?php _e( 'Compatibility Mode (default)', 'aui' ); ?></option>
1087
									<option value="core" <?php selected( $this->settings['css_backend'], 'core' ); ?>><?php _e( 'Full Mode (will cause style issues)', 'aui' ); ?></option>
1088
									<option	value="" <?php selected( $this->settings['css_backend'], '' ); ?>><?php _e( 'Disabled', 'aui' ); ?></option>
1089
								</select>
1090
							</td>
1091
						</tr>
1092
1093
						<tr valign="top">
1094
							<th scope="row"><label
1095
									for="wpbs-js-admin"><?php _e( 'Load JS', 'aui' ); ?></label></th>
1096
							<td>
1097
								<select name="ayecode-ui-settings[js_backend]" id="wpbs-js-admin">
1098
									<option	value="core-popper" <?php selected( $this->settings['js_backend'], 'core-popper' ); ?>><?php _e( 'Core + Popper (default)', 'aui' ); ?></option>
1099
									<option value="popper" <?php selected( $this->settings['js_backend'], 'popper' ); ?>><?php _e( 'Popper', 'aui' ); ?></option>
1100
									<option value="required" <?php selected( $this->settings['js_backend'], 'required' ); ?>><?php _e( 'Required functions only', 'aui' ); ?></option>
1101
									<option	value="" <?php selected( $this->settings['js_backend'], '' ); ?>><?php _e( 'Disabled (not recommended)', 'aui' ); ?></option>
1102
								</select>
1103
							</td>
1104
						</tr>
1105
1106
						<tr valign="top">
1107
							<th scope="row"><label
1108
									for="wpbs-disable-admin"><?php _e( 'Disable load on URL', 'aui' ); ?></label></th>
1109
							<td>
1110
								<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>
1111
								<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>
1112
1113
							</td>
1114
						</tr>
1115
1116
					</table>
1117
1118
					<?php
1119
					submit_button();
1120
					?>
1121
				</form>
1122
1123
				<div id="wpbs-version"><?php echo $this->version; ?></div>
1124
			</div>
1125
1126
			<?php
1127
		}
1128
1129
		public function customizer_settings($wp_customize){
1130
			$wp_customize->add_section('aui_settings', array(
1131
				'title'    => __('AyeCode UI','aui'),
1132
				'priority' => 120,
1133
			));
1134
1135
			//  =============================
1136
			//  = Color Picker              =
1137
			//  =============================
1138
			$wp_customize->add_setting('aui_options[color_primary]', array(
1139
				'default'           => AUI_PRIMARY_COLOR,
1140
				'sanitize_callback' => 'sanitize_hex_color',
1141
				'capability'        => 'edit_theme_options',
1142
				'type'              => 'option',
1143
				'transport'         => 'refresh',
1144
			));
1145
			$wp_customize->add_control( new WP_Customize_Color_Control($wp_customize, 'color_primary', array(
1146
				'label'    => __('Primary Color','aui'),
1147
				'section'  => 'aui_settings',
1148
				'settings' => 'aui_options[color_primary]',
1149
			)));
1150
1151
			$wp_customize->add_setting('aui_options[color_secondary]', array(
1152
				'default'           => '#6c757d',
1153
				'sanitize_callback' => 'sanitize_hex_color',
1154
				'capability'        => 'edit_theme_options',
1155
				'type'              => 'option',
1156
				'transport'         => 'refresh',
1157
			));
1158
			$wp_customize->add_control( new WP_Customize_Color_Control($wp_customize, 'color_secondary', array(
1159
				'label'    => __('Secondary Color','aui'),
1160
				'section'  => 'aui_settings',
1161
				'settings' => 'aui_options[color_secondary]',
1162
			)));
1163
		}
1164
1165
		/**
1166
		 * CSS to help with conflict issues with other plugins and themes using bootstrap v3.
1167
		 *
1168
		 * @return mixed
1169
		 */
1170
		public static function bs3_compat_css() {
1171
			ob_start();
1172
			?>
1173
			<style>
1174
			/* Bootstrap 3 compatibility */
1175
			body.modal-open .modal-backdrop.show:not(.in) {opacity:0.5;}
1176
			body.modal-open .modal.show:not(.in)  {opacity:1;z-index: 99999}
1177
			body.modal-open .modal.show:not(.in) .modal-content  {box-shadow: none;}
1178
			body.modal-open .modal.show:not(.in)  .modal-dialog {transform: initial;}
1179
1180
			body.modal-open .modal.bsui .modal-dialog{left: auto;}
1181
1182
			.collapse.show:not(.in){display: inherit;}
1183
			.fade.show{opacity: 1;}
1184
1185
			<?php if( defined( 'SVQ_THEME_VERSION' ) ){ ?>
1186
			/* KLEO theme specific */
1187
			.kleo-main-header .navbar-collapse.collapse.show:not(.in){display: inherit !important;}
1188
			<?php } ?>
1189
1190
			<?php if( defined( 'FUSION_BUILDER_VERSION' ) ){ ?>
1191
			/* With Avada builder */
1192
			body.modal-open .modal.in  {opacity:1;z-index: 99999}
1193
			body.modal-open .modal.bsui.in .modal-content  {box-shadow: none;}
1194
			.bsui .collapse.in{display: inherit;}
1195
			<?php } ?>
1196
			</style>
1197
			<?php
1198
			return str_replace( array(
1199
				'<style>',
1200
				'</style>'
1201
			), '', ob_get_clean());
1202
		}
1203
1204
1205
		public static function custom_css($compatibility = true) {
1206
			$settings = get_option('aui_options');
1207
1208
			ob_start();
1209
1210
			$primary_color = !empty($settings['color_primary']) ? $settings['color_primary'] : AUI_PRIMARY_COLOR;
1211
			$secondary_color = !empty($settings['color_secondary']) ? $settings['color_secondary'] : AUI_SECONDARY_COLOR;
1212
				//AUI_PRIMARY_COLOR_ORIGINAL
1213
			?>
1214
			<style>
1215
				<?php
1216
1217
					// BS v3 compat
1218
					if( self::is_bs3_compat() ){
1219
					    echo self::bs3_compat_css();
1220
					}
1221
1222
					if(!is_admin() && $primary_color != AUI_PRIMARY_COLOR_ORIGINAL){
1223
						echo self::css_primary($primary_color,$compatibility);
1224
					}
1225
1226
					if(!is_admin() && $secondary_color != AUI_SECONDARY_COLOR_ORIGINAL){
1227
						echo self::css_secondary($settings['color_secondary'],$compatibility);
1228
					}
1229
1230
					// Set admin bar z-index lower when modal is open.
1231
					echo ' body.modal-open #wpadminbar{z-index:999}';
1232
                ?>
1233
			</style>
1234
			<?php
1235
1236
1237
			/*
1238
			 * We only add the <script> tags for code highlighting, so we strip them from the output.
1239
			 */
1240
			return str_replace( array(
1241
				'<style>',
1242
				'</style>'
1243
			), '', ob_get_clean());
1244
		}
1245
1246
		/**
1247
		 * Check if we should add booststrap 3 compatibility changes.
1248
		 *
1249
		 * @return bool
1250
		 */
1251
		public static function is_bs3_compat(){
1252
			return defined('AYECODE_UI_BS3_COMPAT') || defined('SVQ_THEME_VERSION') || defined('FUSION_BUILDER_VERSION');
1253
		}
1254
1255
		public static function css_primary($color_code,$compatibility){;
1256
			$color_code = sanitize_hex_color($color_code);
1257
			if(!$color_code){return '';}
1258
			/**
1259
			 * c = color, b = background color, o = border-color, f = fill
1260
			 */
1261
			$selectors = array(
1262
				'a' => array('c'),
1263
				'.btn-primary' => array('b','o'),
1264
				'.btn-primary.disabled' => array('b','o'),
1265
				'.btn-primary:disabled' => array('b','o'),
1266
				'.btn-outline-primary' => array('c','o'),
1267
				'.btn-outline-primary:hover' => array('b','o'),
1268
				'.btn-outline-primary:not(:disabled):not(.disabled).active' => array('b','o'),
1269
				'.btn-outline-primary:not(:disabled):not(.disabled):active' => array('b','o'),
1270
				'.show>.btn-outline-primary.dropdown-toggle' => array('b','o'),
1271
				'.btn-link' => array('c'),
1272
				'.dropdown-item.active' => array('b'),
1273
				'.custom-control-input:checked~.custom-control-label::before' => array('b','o'),
1274
				'.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before' => array('b','o'),
1275
//				'.custom-range::-webkit-slider-thumb' => array('b'), // these break the inline rules...
1276
//				'.custom-range::-moz-range-thumb' => array('b'),
1277
//				'.custom-range::-ms-thumb' => array('b'),
1278
				'.nav-pills .nav-link.active' => array('b'),
1279
				'.nav-pills .show>.nav-link' => array('b'),
1280
				'.page-link' => array('c'),
1281
				'.page-item.active .page-link' => array('b','o'),
1282
				'.badge-primary' => array('b'),
1283
				'.alert-primary' => array('b','o'),
1284
				'.progress-bar' => array('b'),
1285
				'.list-group-item.active' => array('b','o'),
1286
				'.bg-primary' => array('b','f'),
1287
				'.btn-link.btn-primary' => array('c'),
1288
				'.select2-container .select2-results__option--highlighted.select2-results__option[aria-selected=true]' => array('b'),
1289
			);
1290
1291
			$important_selectors = array(
1292
				'.bg-primary' => array('b','f'),
1293
				'.border-primary' => array('o'),
1294
				'.text-primary' => array('c'),
1295
			);
1296
1297
			$color = array();
1298
			$color_i = array();
1299
			$background = array();
1300
			$background_i = array();
1301
			$border = array();
1302
			$border_i = array();
1303
			$fill = array();
1304
			$fill_i = array();
1305
1306
			$output = '';
1307
1308
			// build rules into each type
1309
			foreach($selectors as $selector => $types){
1310
				$selector = $compatibility ? ".bsui ".$selector : $selector;
1311
				$types = array_combine($types,$types);
1312
				if(isset($types['c'])){$color[] = $selector;}
1313
				if(isset($types['b'])){$background[] = $selector;}
1314
				if(isset($types['o'])){$border[] = $selector;}
1315
				if(isset($types['f'])){$fill[] = $selector;}
1316
			}
1317
1318
			// build rules into each type
1319
			foreach($important_selectors as $selector => $types){
1320
				$selector = $compatibility ? ".bsui ".$selector : $selector;
1321
				$types = array_combine($types,$types);
1322
				if(isset($types['c'])){$color_i[] = $selector;}
1323
				if(isset($types['b'])){$background_i[] = $selector;}
1324
				if(isset($types['o'])){$border_i[] = $selector;}
1325
				if(isset($types['f'])){$fill_i[] = $selector;}
1326
			}
1327
1328
			// add any color rules
1329
			if(!empty($color)){
1330
				$output .= implode(",",$color) . "{color: $color_code;} ";
1331
			}
1332
			if(!empty($color_i)){
1333
				$output .= implode(",",$color_i) . "{color: $color_code !important;} ";
1334
			}
1335
1336
			// add any background color rules
1337
			if(!empty($background)){
1338
				$output .= implode(",",$background) . "{background-color: $color_code;} ";
1339
			}
1340
			if(!empty($background_i)){
1341
				$output .= implode(",",$background_i) . "{background-color: $color_code !important;} ";
1342
			}
1343
1344
			// add any border color rules
1345
			if(!empty($border)){
1346
				$output .= implode(",",$border) . "{border-color: $color_code;} ";
1347
			}
1348
			if(!empty($border_i)){
1349
				$output .= implode(",",$border_i) . "{border-color: $color_code !important;} ";
1350
			}
1351
1352
			// add any fill color rules
1353
			if(!empty($fill)){
1354
				$output .= implode(",",$fill) . "{fill: $color_code;} ";
1355
			}
1356
			if(!empty($fill_i)){
1357
				$output .= implode(",",$fill_i) . "{fill: $color_code !important;} ";
1358
			}
1359
1360
1361
			$prefix = $compatibility ? ".bsui " : "";
1362
1363
			// darken
1364
			$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

1364
			$darker_075 = self::css_hex_lighten_darken($color_code,/** @scrutinizer ignore-type */ "-0.075");
Loading history...
1365
			$darker_10 = self::css_hex_lighten_darken($color_code,"-0.10");
1366
			$darker_125 = self::css_hex_lighten_darken($color_code,"-0.125");
1367
1368
			// lighten
1369
			$lighten_25 = self::css_hex_lighten_darken($color_code,"0.25");
1370
1371
			// opacity see https://css-tricks.com/8-digit-hex-codes/
1372
			$op_25 = $color_code."40"; // 25% opacity
1373
1374
1375
			// button states
1376
			$output .= $prefix ." .btn-primary:hover{background-color: ".$darker_075.";    border-color: ".$darker_10.";} ";
1377
			$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;} ";
1378
			$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.";} ";
1379
			$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;} ";
1380
1381
1382
			// dropdown's
1383
			$output .= $prefix ." .dropdown-item.active, $prefix .dropdown-item:active{background-color: $color_code;} ";
1384
1385
1386
			// input states
1387
			$output .= $prefix ." .form-control:focus{border-color: ".$lighten_25.";box-shadow: 0 0 0 0.2rem $op_25;} ";
1388
1389
			// page link
1390
			$output .= $prefix ." .page-link:focus{box-shadow: 0 0 0 0.2rem $op_25;} ";
1391
1392
			return $output;
1393
		}
1394
1395
		public static function css_secondary($color_code,$compatibility){;
1396
			$color_code = sanitize_hex_color($color_code);
1397
			if(!$color_code){return '';}
1398
			/**
1399
			 * c = color, b = background color, o = border-color, f = fill
1400
			 */
1401
			$selectors = array(
1402
				'.btn-secondary' => array('b','o'),
1403
				'.btn-secondary.disabled' => array('b','o'),
1404
				'.btn-secondary:disabled' => array('b','o'),
1405
				'.btn-outline-secondary' => array('c','o'),
1406
				'.btn-outline-secondary:hover' => array('b','o'),
1407
				'.btn-outline-secondary.disabled' => array('c'),
1408
				'.btn-outline-secondary:disabled' => array('c'),
1409
				'.btn-outline-secondary:not(:disabled):not(.disabled):active' => array('b','o'),
1410
				'.btn-outline-secondary:not(:disabled):not(.disabled).active' => array('b','o'),
1411
				'.btn-outline-secondary.dropdown-toggle' => array('b','o'),
1412
				'.badge-secondary' => array('b'),
1413
				'.alert-secondary' => array('b','o'),
1414
				'.btn-link.btn-secondary' => array('c'),
1415
			);
1416
1417
			$important_selectors = array(
1418
				'.bg-secondary' => array('b','f'),
1419
				'.border-secondary' => array('o'),
1420
				'.text-secondary' => array('c'),
1421
			);
1422
1423
			$color = array();
1424
			$color_i = array();
1425
			$background = array();
1426
			$background_i = array();
1427
			$border = array();
1428
			$border_i = array();
1429
			$fill = array();
1430
			$fill_i = array();
1431
1432
			$output = '';
1433
1434
			// build rules into each type
1435
			foreach($selectors as $selector => $types){
1436
				$selector = $compatibility ? ".bsui ".$selector : $selector;
1437
				$types = array_combine($types,$types);
1438
				if(isset($types['c'])){$color[] = $selector;}
1439
				if(isset($types['b'])){$background[] = $selector;}
1440
				if(isset($types['o'])){$border[] = $selector;}
1441
				if(isset($types['f'])){$fill[] = $selector;}
1442
			}
1443
1444
			// build rules into each type
1445
			foreach($important_selectors as $selector => $types){
1446
				$selector = $compatibility ? ".bsui ".$selector : $selector;
1447
				$types = array_combine($types,$types);
1448
				if(isset($types['c'])){$color_i[] = $selector;}
1449
				if(isset($types['b'])){$background_i[] = $selector;}
1450
				if(isset($types['o'])){$border_i[] = $selector;}
1451
				if(isset($types['f'])){$fill_i[] = $selector;}
1452
			}
1453
1454
			// add any color rules
1455
			if(!empty($color)){
1456
				$output .= implode(",",$color) . "{color: $color_code;} ";
1457
			}
1458
			if(!empty($color_i)){
1459
				$output .= implode(",",$color_i) . "{color: $color_code !important;} ";
1460
			}
1461
1462
			// add any background color rules
1463
			if(!empty($background)){
1464
				$output .= implode(",",$background) . "{background-color: $color_code;} ";
1465
			}
1466
			if(!empty($background_i)){
1467
				$output .= implode(",",$background_i) . "{background-color: $color_code !important;} ";
1468
			}
1469
1470
			// add any border color rules
1471
			if(!empty($border)){
1472
				$output .= implode(",",$border) . "{border-color: $color_code;} ";
1473
			}
1474
			if(!empty($border_i)){
1475
				$output .= implode(",",$border_i) . "{border-color: $color_code !important;} ";
1476
			}
1477
1478
			// add any fill color rules
1479
			if(!empty($fill)){
1480
				$output .= implode(",",$fill) . "{fill: $color_code;} ";
1481
			}
1482
			if(!empty($fill_i)){
1483
				$output .= implode(",",$fill_i) . "{fill: $color_code !important;} ";
1484
			}
1485
1486
1487
			$prefix = $compatibility ? ".bsui " : "";
1488
1489
			// darken
1490
			$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

1490
			$darker_075 = self::css_hex_lighten_darken($color_code,/** @scrutinizer ignore-type */ "-0.075");
Loading history...
1491
			$darker_10 = self::css_hex_lighten_darken($color_code,"-0.10");
1492
			$darker_125 = self::css_hex_lighten_darken($color_code,"-0.125");
1493
1494
			// lighten
1495
			$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...
1496
1497
			// opacity see https://css-tricks.com/8-digit-hex-codes/
1498
			$op_25 = $color_code."40"; // 25% opacity
1499
1500
1501
			// button states
1502
			$output .= $prefix ." .btn-secondary:hover{background-color: ".$darker_075.";    border-color: ".$darker_10.";} ";
1503
			$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;} ";
1504
			$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.";} ";
1505
			$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;} ";
1506
1507
1508
			return $output;
1509
		}
1510
1511
		/**
1512
		 * Increases or decreases the brightness of a color by a percentage of the current brightness.
1513
		 *
1514
		 * @param   string  $hexCode        Supported formats: `#FFF`, `#FFFFFF`, `FFF`, `FFFFFF`
1515
		 * @param   float   $adjustPercent  A number between -1 and 1. E.g. 0.3 = 30% lighter; -0.4 = 40% darker.
1516
		 *
1517
		 * @return  string
1518
		 */
1519
		public static function css_hex_lighten_darken($hexCode, $adjustPercent) {
1520
			$hexCode = ltrim($hexCode, '#');
1521
1522
			if (strlen($hexCode) == 3) {
1523
				$hexCode = $hexCode[0] . $hexCode[0] . $hexCode[1] . $hexCode[1] . $hexCode[2] . $hexCode[2];
1524
			}
1525
1526
			$hexCode = array_map('hexdec', str_split($hexCode, 2));
0 ignored issues
show
Bug introduced by
It seems like str_split($hexCode, 2) can also be of type true; however, parameter $array of array_map() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

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

1526
			$hexCode = array_map('hexdec', /** @scrutinizer ignore-type */ str_split($hexCode, 2));
Loading history...
1527
1528
			foreach ($hexCode as & $color) {
1529
				$adjustableLimit = $adjustPercent < 0 ? $color : 255 - $color;
1530
				$adjustAmount = ceil($adjustableLimit * $adjustPercent);
1531
1532
				$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 $num 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

1532
				$color = str_pad(dechex(/** @scrutinizer ignore-type */ $color + $adjustAmount), 2, '0', STR_PAD_LEFT);
Loading history...
1533
			}
1534
1535
			return '#' . implode($hexCode);
1536
		}
1537
1538
		/**
1539
		 * Check if we should display examples.
1540
		 */
1541
		public function maybe_show_examples(){
1542
			if(current_user_can('manage_options') && isset($_REQUEST['preview-aui'])){
1543
				echo "<head>";
1544
				wp_head();
1545
				echo "</head>";
1546
				echo "<body>";
1547
				echo $this->get_examples();
1548
				echo "</body>";
1549
				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...
1550
			}
1551
		}
1552
1553
		/**
1554
		 * Get developer examples.
1555
		 *
1556
		 * @return string
1557
		 */
1558
		public function get_examples(){
1559
			$output = '';
1560
1561
1562
			// open form
1563
			$output .= "<form class='p-5 m-5 border rounded'>";
1564
1565
			// input example
1566
			$output .= aui()->input(array(
1567
				'type'  =>  'text',
1568
				'id'    =>  'text-example',
1569
				'name'    =>  'text-example',
1570
				'placeholder'   => 'text placeholder',
1571
				'title'   => 'Text input example',
1572
				'value' =>  '',
1573
				'required'  => false,
1574
				'help_text' => 'help text',
1575
				'label' => 'Text input example label'
1576
			));
1577
1578
			// input example
1579
			$output .= aui()->input(array(
1580
				'type'  =>  'url',
1581
				'id'    =>  'text-example2',
1582
				'name'    =>  'text-example',
1583
				'placeholder'   => 'url placeholder',
1584
				'title'   => 'Text input example',
1585
				'value' =>  '',
1586
				'required'  => false,
1587
				'help_text' => 'help text',
1588
				'label' => 'Text input example label'
1589
			));
1590
1591
			// checkbox example
1592
			$output .= aui()->input(array(
1593
				'type'  =>  'checkbox',
1594
				'id'    =>  'checkbox-example',
1595
				'name'    =>  'checkbox-example',
1596
				'placeholder'   => 'checkbox-example',
1597
				'title'   => 'Checkbox example',
1598
				'value' =>  '1',
1599
				'checked'   => true,
1600
				'required'  => false,
1601
				'help_text' => 'help text',
1602
				'label' => 'Checkbox checked'
1603
			));
1604
1605
			// checkbox example
1606
			$output .= aui()->input(array(
1607
				'type'  =>  'checkbox',
1608
				'id'    =>  'checkbox-example2',
1609
				'name'    =>  'checkbox-example2',
1610
				'placeholder'   => 'checkbox-example',
1611
				'title'   => 'Checkbox example',
1612
				'value' =>  '1',
1613
				'checked'   => false,
1614
				'required'  => false,
1615
				'help_text' => 'help text',
1616
				'label' => 'Checkbox un-checked'
1617
			));
1618
1619
			// switch example
1620
			$output .= aui()->input(array(
1621
				'type'  =>  'checkbox',
1622
				'id'    =>  'switch-example',
1623
				'name'    =>  'switch-example',
1624
				'placeholder'   => 'checkbox-example',
1625
				'title'   => 'Switch example',
1626
				'value' =>  '1',
1627
				'checked'   => true,
1628
				'switch'    => true,
1629
				'required'  => false,
1630
				'help_text' => 'help text',
1631
				'label' => 'Switch on'
1632
			));
1633
1634
			// switch example
1635
			$output .= aui()->input(array(
1636
				'type'  =>  'checkbox',
1637
				'id'    =>  'switch-example2',
1638
				'name'    =>  'switch-example2',
1639
				'placeholder'   => 'checkbox-example',
1640
				'title'   => 'Switch example',
1641
				'value' =>  '1',
1642
				'checked'   => false,
1643
				'switch'    => true,
1644
				'required'  => false,
1645
				'help_text' => 'help text',
1646
				'label' => 'Switch off'
1647
			));
1648
1649
			// close form
1650
			$output .= "</form>";
1651
1652
			return $output;
1653
		}
1654
1655
	}
1656
1657
	/**
1658
	 * Run the class if found.
1659
	 */
1660
	AyeCode_UI_Settings::instance();
1661
}