github.com/apremalal/vamps-core@v1.0.1-0.20161221121535-d430b56ec174/server/webapps/app/base/plugins/jarviswidgets/jarvis.js (about)

     1  /*                  ______________________________________
     2             ________|                                      |_______
     3             \       |           SmartAdmin WebApp          |      /
     4              \      |      Copyright © 2015 MyOrange       |     /
     5              /      |______________________________________|     \
     6             /__________)                                (_________\
     7  
     8   * The above copyright notice and this permission notice shall be
     9   * included in all copies or substantial portions of the Software.
    10   * =======================================================================
    11   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    12   * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    13   * MERCHANTABILITY, IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
    14   * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
    15   * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
    16   * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
    17   * =======================================================================
    18   * original filename  : app.js
    19   * filesize           : 62,499~ bytes
    20   * author             : Sunny (@bootstraphunt)
    21   * email              : info@myorange.ca
    22   * legal notice       : This script is part of a theme sold by
    23   *                      https://wrapbootstrap.com/?ref=myorange 
    24   *    
    25   * =======================================================================
    26   * INDEX (Note: line numbers for index items may not be up to date):
    27   * 
    28   * 1. APP CONFIGURATION..................................[ app.config.js ]
    29   * 2. APP DOM REFERENCES.................................[ app.config.js ]
    30   * 3. DETECT MOBILE DEVICES...................................[line: 149 ]
    31   * 4. CUSTOM MENU PLUGIN......................................[line: 688 ]
    32   * 5. ELEMENT EXIST OR NOT....................................[line: 778 ]
    33   * 6. INITIALIZE FORMS........................................[line: 788 ]
    34   * 		6a. BOOTSTRAP SLIDER PLUGIN...........................[line: 794 ]
    35   * 		6b. SELECT2 PLUGIN....................................[line: 803 ]
    36   * 		6c. MASKING...........................................[line: 824 ]
    37   * 		6d. AUTOCOMPLETE......................................[line: 843 ]
    38   * 		6f. JQUERY UI DATE....................................[line: 862 ]
    39   * 		6g. AJAX BUTTON LOADING TEXT..........................[line: 884 ]
    40   * 7. INITIALIZE CHARTS.......................................[line: 902 ]
    41   * 		7a. SPARKLINES........................................[line: 907 ]
    42   * 		7b. LINE CHART........................................[line: 1026]
    43   * 		7c. PIE CHART.........................................[line: 1077]
    44   * 		7d. BOX PLOT..........................................[line: 1100]
    45   * 		7e. BULLET............................................[line: 1145]
    46   * 		7f. DISCRETE..........................................[line: 1169]
    47   * 		7g. TRISTATE..........................................[line: 1195]
    48   * 		7h. COMPOSITE: BAR....................................[line: 1223]
    49   * 		7i. COMPOSITE: LINE...................................[line: 1259]
    50   * 		7j. EASY PIE CHARTS...................................[line: 1339]
    51   * 8. INITIALIZE JARVIS WIDGETS...............................[line: 1379]
    52   * 		8a. SETUP DESKTOP WIDGET..............................[line: 1466]
    53   * 		8b. GOOGLE MAPS.......................................[line: 1478]
    54   * 		8c. LOAD SCRIPTS......................................[line: 1500]
    55   * 		8d. APP AJAX REQUEST SETUP............................[line: 1538]
    56   * 9. CHECK TO SEE IF URL EXISTS..............................[line: 1614]
    57   * 10.LOAD AJAX PAGES.........................................[line: 1669]
    58   * 11.UPDATE BREADCRUMB.......................................[line: 1775]
    59   * 12.PAGE SETUP..............................................[line: 1798]
    60   * 13.POP OVER THEORY.........................................[line: 1852]
    61   * 14.DELETE MODEL DATA ON HIDDEN.............................[line: 1991]
    62   * 15.HELPFUL FUNCTIONS.......................................[line: 2027]
    63   * 
    64   * =======================================================================
    65   *       IMPORTANT: ALL CONFIG VARS IS NOW MOVED TO APP.CONFIG.JS
    66   * =======================================================================
    67   * 
    68   * 
    69   * GLOBAL: interval array (to be used with jarviswidget in ajax and 
    70   * angular mode) to clear auto fetch interval
    71   */
    72  	$.intervalArr = [];
    73  /*
    74   * Calculate nav height
    75   */
    76  var calc_navbar_height = function() {
    77  		var height = null;
    78  	
    79  		if ($('#header').length)
    80  			height = $('#header').height();
    81  	
    82  		if (height === null)
    83  			height = $('<div id="header"></div>').height();
    84  	
    85  		if (height === null)
    86  			return 49;
    87  		// default
    88  		return height;
    89  	},
    90  	
    91  	navbar_height = calc_navbar_height, 
    92  /*
    93   * APP DOM REFERENCES
    94   * Description: Obj DOM reference, please try to avoid changing these
    95   */	
    96  	shortcut_dropdown = $('#shortcut'),
    97  	
    98  	bread_crumb = $('#ribbon ol.breadcrumb'),
    99  /*
   100   * Top menu on/off
   101   */
   102  	topmenu = false,
   103  /*
   104   * desktop or mobile
   105   */
   106  	thisDevice = null,
   107  /*
   108   * DETECT MOBILE DEVICES
   109   * Description: Detects mobile device - if any of the listed device is 
   110   * detected a class is inserted to $.root_ and the variable thisDevice 
   111   * is decleard. (so far this is covering most hand held devices)
   112   */	
   113  	ismobile = (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase())),
   114  /*
   115   * JS ARRAY SCRIPT STORAGE
   116   * Description: used with loadScript to store script path and file name
   117   * so it will not load twice
   118   */	
   119  	jsArray = {},
   120  /*
   121   * App Initialize
   122   * Description: Initializes the app with intApp();
   123   */	
   124  	initApp = (function(app) {
   125  		
   126  		/*
   127  		 * ADD DEVICE TYPE
   128  		 * Detect if mobile or desktop
   129  		 */		
   130  		app.addDeviceType = function() {
   131  
   132  			if (!ismobile) {
   133  				// Desktop
   134  				$.root_.addClass("desktop-detected");
   135  				thisDevice = "desktop";
   136  				return false;
   137  			} else {
   138  				// Mobile
   139  				$.root_.addClass("mobile-detected");
   140  				thisDevice = "mobile";
   141  
   142  				if (fastClick) {
   143  					// Removes the tap delay in idevices
   144  					// dependency: js/plugin/fastclick/fastclick.js
   145  					$.root_.addClass("needsclick");
   146  					FastClick.attach(document.body);
   147  					return false;
   148  				}
   149  
   150  			}
   151  
   152  		};
   153  		/* ~ END: ADD DEVICE TYPE */
   154  		
   155  		/*
   156  		 * CHECK FOR MENU POSITION
   157  		 * Scans localstroage for menu position (vertical or horizontal)
   158  		 */
   159  		app.menuPos = function() {
   160  			
   161  		 	if ($.root_.hasClass("menu-on-top") || localStorage.getItem('sm-setmenu')=='top' ) { 
   162  		 		topmenu = true;
   163  		 		$.root_.addClass("menu-on-top");
   164  		 	}
   165  		};
   166  		/* ~ END: CHECK MOBILE DEVICE */
   167  
   168  		/*
   169  		 * SMART ACTIONS
   170  		 */
   171  		app.SmartActions = function(){
   172  				
   173  			var smartActions = {
   174  			    
   175  			    // LOGOUT MSG 
   176  			    userLogout: function($this){
   177  			
   178  					// ask verification
   179  					$.SmartMessageBox({
   180  						title : "<i class='fa fa-sign-out txt-color-orangeDark'></i> Logout <span class='txt-color-orangeDark'><strong>" + $('#show-shortcut').text() + "</strong></span> ?",
   181  						content : $this.data('logout-msg') || "You can improve your security further after logging out by closing this opened browser",
   182  						buttons : '[No][Yes]'
   183  			
   184  					}, function(ButtonPressed) {
   185  						if (ButtonPressed == "Yes") {
   186  							$.root_.addClass('animated fadeOutUp');
   187  							setTimeout(logout, 1000);
   188  						}
   189  					});
   190  					function logout() {
   191  						window.location = $this.attr('href');
   192  					}
   193  			
   194  				},
   195  		
   196  				// RESET WIDGETS
   197  			    resetWidgets: function($this){
   198  					
   199  					$.SmartMessageBox({
   200  						title : "<i class='fa fa-refresh' style='color:green'></i> Clear Local Storage",
   201  						content : $this.data('reset-msg') || "Would you like to RESET all your saved widgets and clear LocalStorage?1",
   202  						buttons : '[No][Yes]'
   203  					}, function(ButtonPressed) {
   204  						if (ButtonPressed == "Yes" && localStorage) {
   205  							localStorage.clear();
   206  							location.reload();
   207  						}
   208  			
   209  					});
   210  			    },
   211  			    
   212  			    // LAUNCH FULLSCREEN 
   213  			    launchFullscreen: function(element){
   214  			
   215  					if (!$.root_.hasClass("full-screen")) {
   216  				
   217  						$.root_.addClass("full-screen");
   218  				
   219  						if (element.requestFullscreen) {
   220  							element.requestFullscreen();
   221  						} else if (element.mozRequestFullScreen) {
   222  							element.mozRequestFullScreen();
   223  						} else if (element.webkitRequestFullscreen) {
   224  							element.webkitRequestFullscreen();
   225  						} else if (element.msRequestFullscreen) {
   226  							element.msRequestFullscreen();
   227  						}
   228  				
   229  					} else {
   230  						
   231  						$.root_.removeClass("full-screen");
   232  						
   233  						if (document.exitFullscreen) {
   234  							document.exitFullscreen();
   235  						} else if (document.mozCancelFullScreen) {
   236  							document.mozCancelFullScreen();
   237  						} else if (document.webkitExitFullscreen) {
   238  							document.webkitExitFullscreen();
   239  						}
   240  				
   241  					}
   242  			
   243  			   },
   244  			
   245  			   // MINIFY MENU
   246  			    minifyMenu: function($this){
   247  			    	if (!$.root_.hasClass("menu-on-top")){
   248  						$.root_.toggleClass("minified");
   249  						$.root_.removeClass("hidden-menu");
   250  						$('html').removeClass("hidden-menu-mobile-lock");
   251  						$this.effect("highlight", {}, 500);
   252  					}
   253  			    },
   254  			    
   255  			    // TOGGLE MENU 
   256  			    toggleMenu: function(){
   257  			    	if (!$.root_.hasClass("menu-on-top")){
   258  						$('html').toggleClass("hidden-menu-mobile-lock");
   259  						$.root_.toggleClass("hidden-menu");
   260  						$.root_.removeClass("minified");
   261  			    	//} else if ( $.root_.hasClass("menu-on-top") && $.root_.hasClass("mobile-view-activated") ) {
   262  			    	// suggested fix from Christian Jäger	
   263  			    	} else if ( $.root_.hasClass("menu-on-top") && $(window).width() < 979 ) {	
   264  			    		$('html').toggleClass("hidden-menu-mobile-lock");
   265  						$.root_.toggleClass("hidden-menu");
   266  						$.root_.removeClass("minified");
   267  			    	}
   268  			    },     
   269  			
   270  			    // TOGGLE SHORTCUT 
   271  			    toggleShortcut: function(){
   272  			    	
   273  					if (shortcut_dropdown.is(":visible")) {
   274  						shortcut_buttons_hide();
   275  					} else {
   276  						shortcut_buttons_show();
   277  					}
   278  		
   279  					// SHORT CUT (buttons that appear when clicked on user name)
   280  					shortcut_dropdown.find('a').click(function(e) {
   281  						e.preventDefault();
   282  						window.location = $(this).attr('href');
   283  						setTimeout(shortcut_buttons_hide, 300);
   284  				
   285  					});
   286  				
   287  					// SHORTCUT buttons goes away if mouse is clicked outside of the area
   288  					$(document).mouseup(function(e) {
   289  						if (!shortcut_dropdown.is(e.target) && shortcut_dropdown.has(e.target).length === 0) {
   290  							shortcut_buttons_hide();
   291  						}
   292  					});
   293  					
   294  					// SHORTCUT ANIMATE HIDE
   295  					function shortcut_buttons_hide() {
   296  						shortcut_dropdown.animate({
   297  							height : "hide"
   298  						}, 300, "easeOutCirc");
   299  						$.root_.removeClass('shortcut-on');
   300  				
   301  					}
   302  				
   303  					// SHORTCUT ANIMATE SHOW
   304  					function shortcut_buttons_show() {
   305  						shortcut_dropdown.animate({
   306  							height : "show"
   307  						}, 200, "easeOutCirc");
   308  						$.root_.addClass('shortcut-on');
   309  					}
   310  			
   311  			    }  
   312  			   
   313  			};
   314  				
   315  			$.root_.on('click', '[data-action="userLogout"]', function(e) {
   316  				var $this = $(this);
   317  				smartActions.userLogout($this);
   318  				e.preventDefault();
   319  				
   320  				//clear memory reference
   321  				$this = null;
   322  				
   323  			}); 
   324  
   325  			/*
   326  			 * BUTTON ACTIONS 
   327  			 */		
   328  			$.root_.on('click', '[data-action="resetWidgets"]', function(e) {	
   329  				var $this = $(this);
   330  				smartActions.resetWidgets($this);
   331  				e.preventDefault();
   332  				
   333  				//clear memory reference
   334  				$this = null;
   335  			});
   336  			
   337  			$.root_.on('click', '[data-action="launchFullscreen"]', function(e) {	
   338  				smartActions.launchFullscreen(document.documentElement);
   339  				e.preventDefault();
   340  			}); 
   341  			
   342  			$.root_.on('click', '[data-action="minifyMenu"]', function(e) {
   343  				var $this = $(this);
   344  				smartActions.minifyMenu($this);
   345  				e.preventDefault();
   346  				
   347  				//clear memory reference
   348  				$this = null;
   349  			}); 
   350  			
   351  			$.root_.on('click', '[data-action="toggleMenu"]', function(e) {	
   352  				smartActions.toggleMenu();
   353  				e.preventDefault();
   354  			});  
   355  		
   356  			$.root_.on('click', '[data-action="toggleShortcut"]', function(e) {	
   357  				smartActions.toggleShortcut();
   358  				e.preventDefault();
   359  			}); 
   360  					
   361  		};
   362  		/* ~ END: SMART ACTIONS */
   363  		
   364  		/*
   365  		 * ACTIVATE NAVIGATION
   366  		 * Description: Activation will fail if top navigation is on
   367  		 */
   368  		app.leftNav = function(){
   369  			
   370  			// INITIALIZE LEFT NAV
   371  			if (!topmenu) {
   372  				if (!null) {
   373  					$('nav ul').jarvismenu({
   374  						accordion : menu_accordion || true,
   375  						speed : menu_speed || true,
   376  						closedSign : '<em class="fa fa-plus-square-o"></em>',
   377  						openedSign : '<em class="fa fa-minus-square-o"></em>'
   378  					});
   379  				} else {
   380  					alert("Error - menu anchor does not exist");
   381  				}
   382  			}
   383  			
   384  		};
   385  		/* ~ END: ACTIVATE NAVIGATION */
   386  		
   387  		/*
   388  		 * MISCELANEOUS DOM READY FUNCTIONS
   389  		 * Description: fire with jQuery(document).ready...
   390  		 */
   391  		app.domReadyMisc = function() {
   392  			
   393  			/*
   394  			 * FIRE TOOLTIPS
   395  			 */
   396  			if ($("[rel=tooltip]").length) {
   397  				$("[rel=tooltip]").tooltip();
   398  			}
   399  		
   400  			// SHOW & HIDE MOBILE SEARCH FIELD
   401  			$('#search-mobile').click(function() {
   402  				$.root_.addClass('search-mobile');
   403  			});
   404  		
   405  			$('#cancel-search-js').click(function() {
   406  				$.root_.removeClass('search-mobile');
   407  			});
   408  		
   409  			// ACTIVITY
   410  			// ajax drop
   411  			$('#activity').click(function(e) {
   412  				var $this = $(this);
   413  		
   414  				if ($this.find('.badge').hasClass('bg-color-red')) {
   415  					$this.find('.badge').removeClassPrefix('bg-color-');
   416  					$this.find('.badge').text("0");
   417  				}
   418  		
   419  				if (!$this.next('.ajax-dropdown').is(':visible')) {
   420  					$this.next('.ajax-dropdown').fadeIn(150);
   421  					$this.addClass('active');
   422  				} else {
   423  					$this.next('.ajax-dropdown').fadeOut(150);
   424  					$this.removeClass('active');
   425  				}
   426  		
   427  				var theUrlVal = $this.next('.ajax-dropdown').find('.btn-group > .active > input').attr('id');
   428  				
   429  				//clear memory reference
   430  				$this = null;
   431  				theUrlVal = null;
   432  						
   433  				e.preventDefault();
   434  			});
   435  		
   436  			$('input[name="activity"]').change(function() {
   437  				var $this = $(this);
   438  		
   439  				url = $this.attr('id');
   440  				container = $('.ajax-notifications');
   441  				
   442  				loadURL(url, container);
   443  				
   444  				//clear memory reference
   445  				$this = null;		
   446  			});
   447  		
   448  			// close dropdown if mouse is not inside the area of .ajax-dropdown
   449  			$(document).mouseup(function(e) {
   450  				if (!$('.ajax-dropdown').is(e.target) && $('.ajax-dropdown').has(e.target).length === 0) {
   451  					$('.ajax-dropdown').fadeOut(150);
   452  					$('.ajax-dropdown').prev().removeClass("active");
   453  				}
   454  			});
   455  			
   456  			// loading animation (demo purpose only)
   457  			$('button[data-btn-loading]').on('click', function() {
   458  				var btn = $(this);
   459  				btn.button('loading');
   460  				setTimeout(function() {
   461  					btn.button('reset');
   462  				}, 3000);
   463  			});
   464  		
   465  			// NOTIFICATION IS PRESENT
   466  			// Change color of lable once notification button is clicked
   467  
   468  			$this = $('#activity > .badge');
   469  	
   470  			if (parseInt($this.text()) > 0) {
   471  				$this.addClass("bg-color-red bounceIn animated");
   472  				
   473  				//clear memory reference
   474  				$this = null;
   475  			}
   476  
   477  			
   478  		};
   479  		/* ~ END: MISCELANEOUS DOM */
   480  	
   481  		/*
   482  		 * MISCELANEOUS DOM READY FUNCTIONS
   483  		 * Description: fire with jQuery(document).ready...
   484  		 */
   485  		app.mobileCheckActivation = function(){
   486  			
   487  			if ($(window).width() < 979) {
   488  				$.root_.addClass('mobile-view-activated');
   489  				$.root_.removeClass('minified');
   490  			} else if ($.root_.hasClass('mobile-view-activated')) {
   491  				$.root_.removeClass('mobile-view-activated');
   492  			}
   493  
   494  			if (debugState){
   495  				console.log("mobileCheckActivation");
   496  			}
   497  			
   498  		} 
   499  		/* ~ END: MISCELANEOUS DOM */
   500  
   501  		return app;
   502  		
   503  	})({});
   504  
   505  	initApp.addDeviceType();
   506  	initApp.menuPos();
   507  /*
   508   * DOCUMENT LOADED EVENT
   509   * Description: Fire when DOM is ready
   510   */
   511  	jQuery(document).ready(function() {
   512  		
   513  		initApp.SmartActions();
   514  		initApp.leftNav();
   515  		initApp.domReadyMisc();
   516  	
   517  	});
   518  /*
   519   * RESIZER WITH THROTTLE
   520   * Source: http://benalman.com/code/projects/jquery-resize/examples/resize/
   521   */
   522  	(function ($, window, undefined) {
   523  	
   524  	    var elems = $([]),
   525  	        jq_resize = $.resize = $.extend($.resize, {}),
   526  	        timeout_id, str_setTimeout = 'setTimeout',
   527  	        str_resize = 'resize',
   528  	        str_data = str_resize + '-special-event',
   529  	        str_delay = 'delay',
   530  	        str_throttle = 'throttleWindow';
   531  	
   532  	    jq_resize[str_delay] = throttle_delay;
   533  	
   534  	    jq_resize[str_throttle] = true;
   535  	
   536  	    $.event.special[str_resize] = {
   537  	
   538  	        setup: function () {
   539  	            if (!jq_resize[str_throttle] && this[str_setTimeout]) {
   540  	                return false;
   541  	            }
   542  	
   543  	            var elem = $(this);
   544  	            elems = elems.add(elem);
   545  	            try {
   546  	                $.data(this, str_data, {
   547  	                    w: elem.width(),
   548  	                    h: elem.height()
   549  	                });
   550  	            } catch (e) {
   551  	                $.data(this, str_data, {
   552  	                    w: elem.width, // elem.width();
   553  	                    h: elem.height // elem.height();
   554  	                });
   555  	            }
   556  	
   557  	            if (elems.length === 1) {
   558  	                loopy();
   559  	            }
   560  	        },
   561  	        teardown: function () {
   562  	            if (!jq_resize[str_throttle] && this[str_setTimeout]) {
   563  	                return false;
   564  	            }
   565  	
   566  	            var elem = $(this);
   567  	            elems = elems.not(elem);
   568  	            elem.removeData(str_data);
   569  	            if (!elems.length) {
   570  	                clearTimeout(timeout_id);
   571  	            }
   572  	        },
   573  	
   574  	        add: function (handleObj) {
   575  	            if (!jq_resize[str_throttle] && this[str_setTimeout]) {
   576  	                return false;
   577  	            }
   578  	            var old_handler;
   579  	
   580  	            function new_handler(e, w, h) {
   581  	                var elem = $(this),
   582  	                    data = $.data(this, str_data);
   583  	                //data.w = w !== undefined ? w : elem.width();
   584  	                //data.h = h !== undefined ? h : elem.height();
   585                      //
   586  	                //old_handler.apply(this, arguments);
   587  	            }
   588  	            if ($.isFunction(handleObj)) {
   589  	                old_handler = handleObj;
   590  	                return new_handler;
   591  	            } else {
   592  	                old_handler = handleObj.handler;
   593  	                handleObj.handler = new_handler;
   594  	            }
   595  	        }
   596  	    };
   597  	
   598  	    function loopy() {
   599  	        timeout_id = window[str_setTimeout](function () {
   600  	            elems.each(function () {
   601  	                var width;
   602  	                var height;
   603  	
   604  	                var elem = $(this),
   605  	                    data = $.data(this, str_data); //width = elem.width(), height = elem.height();
   606  	
   607  	                // Highcharts fix
   608  	                try {
   609  	                    width = elem.width();
   610  	                } catch (e) {
   611  	                    width = elem.width;
   612  	                }
   613  	
   614  	                try {
   615  	                    height = elem.height();
   616  	                } catch (e) {
   617  	                    height = elem.height;
   618  	                }
   619  	                //fixed bug
   620  	
   621  	
   622  	                if (width !== data.w || height !== data.h) {
   623  	                    elem.trigger(str_resize, [data.w = width, data.h = height]);
   624  	                }
   625  	
   626  	            });
   627  	            loopy();
   628  	
   629  	        }, jq_resize[str_delay]);
   630  	
   631  	    }
   632  	
   633  	})(jQuery, this);
   634  /*
   635  * ADD CLASS WHEN BELOW CERTAIN WIDTH (MOBILE MENU)
   636  * Description: tracks the page min-width of #CONTENT and NAV when navigation is resized.
   637  * This is to counter bugs for minimum page width on many desktop and mobile devices.
   638  * Note: This script utilizes JSthrottle script so don't worry about memory/CPU usage
   639  */
   640  	$('#main').resize(function() {
   641  		
   642  		initApp.mobileCheckActivation();
   643  		
   644  	});
   645  
   646  /* ~ END: NAV OR #LEFT-BAR RESIZE DETECT */
   647  
   648  /*
   649   * DETECT IE VERSION
   650   * Description: A short snippet for detecting versions of IE in JavaScript
   651   * without resorting to user-agent sniffing
   652   * RETURNS:
   653   * If you're not in IE (or IE version is less than 5) then:
   654   * //ie === undefined
   655   *
   656   * If you're in IE (>=5) then you can determine which version:
   657   * // ie === 7; // IE7
   658   *
   659   * Thus, to detect IE:
   660   * // if (ie) {}
   661   *
   662   * And to detect the version:
   663   * ie === 6 // IE6
   664   * ie > 7 // IE8, IE9 ...
   665   * ie < 9 // Anything less than IE9
   666   */
   667  // TODO: delete this function later on - no longer needed (?)
   668  	var ie = ( function() {
   669  	
   670  		var undef, v = 3, div = document.createElement('div'), all = div.getElementsByTagName('i');
   671  	
   672  		while (div.innerHTML = '<!--[if gt IE ' + (++v) + ']><i></i><![endif]-->', all[0]);
   673  	
   674  		return v > 4 ? v : undef;
   675  	
   676  	}()); 
   677  /* ~ END: DETECT IE VERSION */
   678  
   679  /*
   680   * CUSTOM MENU PLUGIN
   681   */
   682  	$.fn.extend({
   683  	
   684  		//pass the options variable to the function
   685  		jarvismenu : function(options) {
   686  	
   687  			var defaults = {
   688  				accordion : 'true',
   689  				speed : 200,
   690  				closedSign : '[+]',
   691  				openedSign : '[-]'
   692  			},
   693  	
   694  			// Extend our default options with those provided.
   695  				opts = $.extend(defaults, options),
   696  			//Assign current element to variable, in this case is UL element
   697  				$this = $(this);
   698  	
   699  			//add a mark [+] to a multilevel menu
   700  			$this.find("li").each(function() {
   701  				if ($(this).find("ul").size() !== 0) {
   702  					//add the multilevel sign next to the link
   703  					$(this).find("a:first").append("<b class='collapse-sign'>" + opts.closedSign + "</b>");
   704  	
   705  					//avoid jumping to the top of the page when the href is an #
   706  					if ($(this).find("a:first").attr('href') == "#") {
   707  						$(this).find("a:first").click(function() {
   708  							return false;
   709  						});
   710  					}
   711  				}
   712  			});
   713  	
   714  			//open active level
   715  			$this.find("li.active").each(function() {
   716  				$(this).parents("ul").slideDown(opts.speed);
   717  				$(this).parents("ul").parent("li").find("b:first").html(opts.openedSign);
   718  				$(this).parents("ul").parent("li").addClass("open");
   719  			});
   720  	
   721  			$this.find("li a").click(function() {
   722  	
   723  				if ($(this).parent().find("ul").size() !== 0) {
   724  	
   725  					if (opts.accordion) {
   726  						//Do nothing when the list is open
   727  						if (!$(this).parent().find("ul").is(':visible')) {
   728  							parents = $(this).parent().parents("ul");
   729  							visible = $this.find("ul:visible");
   730  							visible.each(function(visibleIndex) {
   731  								var close = true;
   732  								parents.each(function(parentIndex) {
   733  									if (parents[parentIndex] == visible[visibleIndex]) {
   734  										close = false;
   735  										return false;
   736  									}
   737  								});
   738  								if (close) {
   739  									if ($(this).parent().find("ul") != visible[visibleIndex]) {
   740  										$(visible[visibleIndex]).slideUp(opts.speed, function() {
   741  											$(this).parent("li").find("b:first").html(opts.closedSign);
   742  											$(this).parent("li").removeClass("open");
   743  										});
   744  	
   745  									}
   746  								}
   747  							});
   748  						}
   749  					}// end if
   750  					if ($(this).parent().find("ul:first").is(":visible") && !$(this).parent().find("ul:first").hasClass("active")) {
   751  						$(this).parent().find("ul:first").slideUp(opts.speed, function() {
   752  							$(this).parent("li").removeClass("open");
   753  							$(this).parent("li").find("b:first").delay(opts.speed).html(opts.closedSign);
   754  						});
   755  	
   756  					} else {
   757  						$(this).parent().find("ul:first").slideDown(opts.speed, function() {
   758  							/*$(this).effect("highlight", {color : '#616161'}, 500); - disabled due to CPU clocking on phones*/
   759  							$(this).parent("li").addClass("open");
   760  							$(this).parent("li").find("b:first").delay(opts.speed).html(opts.openedSign);
   761  						});
   762  					} // end else
   763  				} // end if
   764  			});
   765  		} // end function
   766  	});
   767  /* ~ END: CUSTOM MENU PLUGIN */
   768  
   769  /*
   770   * ELEMENT EXIST OR NOT
   771   * Description: returns true or false
   772   * Usage: $('#myDiv').doesExist();
   773   */
   774  	jQuery.fn.doesExist = function() {
   775  		return jQuery(this).length > 0;
   776  	};
   777  /* ~ END: ELEMENT EXIST OR NOT */
   778  
   779  /*
   780   * INITIALIZE FORMS
   781   * Description: Select2, Masking, Datepicker, Autocomplete
   782   */	
   783  	function runAllForms() {
   784  	
   785  		/*
   786  		 * BOOTSTRAP SLIDER PLUGIN
   787  		 * Usage:
   788  		 * Dependency: js/plugin/bootstrap-slider
   789  		 */
   790  		if ($.fn.slider) {
   791  			$('.slider').slider();
   792  		}
   793  	
   794  		/*
   795  		 * SELECT2 PLUGIN
   796  		 * Usage:
   797  		 * Dependency: js/plugin/select2/
   798  		 */
   799  		if ($.fn.select2) {
   800  			$('select.select2').each(function() {
   801  				var $this = $(this),
   802  					width = $this.attr('data-select-width') || '100%';
   803  				//, _showSearchInput = $this.attr('data-select-search') === 'true';
   804  				$this.select2({
   805  					//showSearchInput : _showSearchInput,
   806  					allowClear : true,
   807  					width : width
   808  				});
   809  
   810  				//clear memory reference
   811  				$this = null;
   812  			});
   813  		}
   814  	
   815  		/*
   816  		 * MASKING
   817  		 * Dependency: js/plugin/masked-input/
   818  		 */
   819  		if ($.fn.mask) {
   820  			$('[data-mask]').each(function() {
   821  	
   822  				var $this = $(this),
   823  					mask = $this.attr('data-mask') || 'error...', mask_placeholder = $this.attr('data-mask-placeholder') || 'X';
   824  	
   825  				$this.mask(mask, {
   826  					placeholder : mask_placeholder
   827  				});
   828  				
   829  				//clear memory reference
   830  				$this = null;
   831  			});
   832  		}
   833  	
   834  		/*
   835  		 * AUTOCOMPLETE
   836  		 * Dependency: js/jqui
   837  		 */
   838  		if ($.fn.autocomplete) {
   839  			$('[data-autocomplete]').each(function() {
   840  	
   841  				var $this = $(this),
   842  					availableTags = $this.data('autocomplete') || ["The", "Quick", "Brown", "Fox", "Jumps", "Over", "Three", "Lazy", "Dogs"];
   843  	
   844  				$this.autocomplete({
   845  					source : availableTags
   846  				});
   847  				
   848  				//clear memory reference
   849  				$this = null;
   850  			});
   851  		}
   852  	
   853  		/*
   854  		 * JQUERY UI DATE
   855  		 * Dependency: js/libs/jquery-ui-1.10.3.min.js
   856  		 * Usage: <input class="datepicker" />
   857  		 */
   858  		if ($.fn.datepicker) {
   859  			$('.datepicker').each(function() {
   860  	
   861  				var $this = $(this),
   862  					dataDateFormat = $this.attr('data-dateformat') || 'dd.mm.yy';
   863  	
   864  				$this.datepicker({
   865  					dateFormat : dataDateFormat,
   866  					prevText : '<i class="fa fa-chevron-left"></i>',
   867  					nextText : '<i class="fa fa-chevron-right"></i>',
   868  				});
   869  				
   870  				//clear memory reference
   871  				$this = null;
   872  			});
   873  		}
   874  	
   875  		/*
   876  		 * AJAX BUTTON LOADING TEXT
   877  		 * Usage: <button type="button" data-loading-text="Loading..." class="btn btn-xs btn-default ajax-refresh"> .. </button>
   878  		 */
   879  		$('button[data-loading-text]').on('click', function() {
   880  			var btn = $(this);
   881  			btn.button('loading');
   882  			setTimeout(function() {
   883  				btn.button('reset');
   884  				//clear memory reference
   885  				btn = null;
   886  			}, 3000);
   887  
   888  		});
   889  	
   890  	}
   891  /* ~ END: INITIALIZE FORMS */
   892  
   893  /*
   894   * INITIALIZE CHARTS
   895   * Description: Sparklines, PieCharts
   896   */
   897  	function runAllCharts() {
   898  		/*
   899  		 * SPARKLINES
   900  		 * DEPENDENCY: js/plugins/sparkline/jquery.sparkline.min.js
   901  		 * See usage example below...
   902  		 */
   903  	
   904  		/* Usage:
   905  		 * 		<div class="sparkline-line txt-color-blue" data-fill-color="transparent" data-sparkline-height="26px">
   906  		 *			5,6,7,9,9,5,9,6,5,6,6,7,7,6,7,8,9,7
   907  		 *		</div>
   908  		 */
   909  	
   910  		if ($.fn.sparkline) {
   911  	
   912  			// variable declearations:
   913  	
   914  			var barColor,
   915  			    sparklineHeight,
   916  			    sparklineBarWidth,
   917  			    sparklineBarSpacing,
   918  			    sparklineNegBarColor,
   919  			    sparklineStackedColor,
   920  			    thisLineColor,
   921  			    thisLineWidth,
   922  			    thisFill,
   923  			    thisSpotColor,
   924  			    thisMinSpotColor,
   925  			    thisMaxSpotColor,
   926  			    thishighlightSpotColor,
   927  			    thisHighlightLineColor,
   928  			    thisSpotRadius,			        
   929  				pieColors,
   930  			    pieWidthHeight,
   931  			    pieBorderColor,
   932  			    pieOffset,
   933  			 	thisBoxWidth,
   934  			    thisBoxHeight,
   935  			    thisBoxRaw,
   936  			    thisBoxTarget,
   937  			    thisBoxMin,
   938  			    thisBoxMax,
   939  			    thisShowOutlier,
   940  			    thisIQR,
   941  			    thisBoxSpotRadius,
   942  			    thisBoxLineColor,
   943  			    thisBoxFillColor,
   944  			    thisBoxWhisColor,
   945  			    thisBoxOutlineColor,
   946  			    thisBoxOutlineFill,
   947  			    thisBoxMedianColor,
   948  			    thisBoxTargetColor,
   949  				thisBulletHeight,
   950  			    thisBulletWidth,
   951  			    thisBulletColor,
   952  			    thisBulletPerformanceColor,
   953  			    thisBulletRangeColors,
   954  				thisDiscreteHeight,
   955  			    thisDiscreteWidth,
   956  			    thisDiscreteLineColor,
   957  			    thisDiscreteLineHeight,
   958  			    thisDiscreteThrushold,
   959  			    thisDiscreteThrusholdColor,
   960  				thisTristateHeight,
   961  			    thisTristatePosBarColor,
   962  			    thisTristateNegBarColor,
   963  			    thisTristateZeroBarColor,
   964  			    thisTristateBarWidth,
   965  			    thisTristateBarSpacing,
   966  			    thisZeroAxis,
   967  			    thisBarColor,
   968  			    sparklineWidth,
   969  			    sparklineValue,
   970  			    sparklineValueSpots1,
   971  			    sparklineValueSpots2,
   972  			    thisLineWidth1,
   973  			    thisLineWidth2,
   974  			    thisLineColor1,
   975  			    thisLineColor2,
   976  			    thisSpotRadius1,
   977  			    thisSpotRadius2,
   978  			    thisMinSpotColor1,
   979  			    thisMaxSpotColor1,
   980  			    thisMinSpotColor2,
   981  			    thisMaxSpotColor2,
   982  			    thishighlightSpotColor1,
   983  			    thisHighlightLineColor1,
   984  			    thishighlightSpotColor2,
   985  			    thisFillColor1,
   986  			    thisFillColor2;
   987  					    				    	
   988  			$('.sparkline:not(:has(>canvas))').each(function() {
   989  				var $this = $(this),
   990  					sparklineType = $this.data('sparkline-type') || 'bar';
   991  	
   992  				// BAR CHART
   993  				if (sparklineType == 'bar') {
   994  	
   995  						barColor = $this.data('sparkline-bar-color') || $this.css('color') || '#0000f0';
   996  					    sparklineHeight = $this.data('sparkline-height') || '26px';
   997  					    sparklineBarWidth = $this.data('sparkline-barwidth') || 5;
   998  					    sparklineBarSpacing = $this.data('sparkline-barspacing') || 2;
   999  					    sparklineNegBarColor = $this.data('sparkline-negbar-color') || '#A90329';
  1000  					    sparklineStackedColor = $this.data('sparkline-barstacked-color') || ["#A90329", "#0099c6", "#98AA56", "#da532c", "#4490B1", "#6E9461", "#990099", "#B4CAD3"];
  1001  					        
  1002  					$this.sparkline('html', {
  1003  						barColor : barColor,
  1004  						type : sparklineType,
  1005  						height : sparklineHeight,
  1006  						barWidth : sparklineBarWidth,
  1007  						barSpacing : sparklineBarSpacing,
  1008  						stackedBarColor : sparklineStackedColor,
  1009  						negBarColor : sparklineNegBarColor,
  1010  						zeroAxis : 'false'
  1011  					});
  1012  					
  1013  					$this = null;
  1014  	
  1015  				}
  1016  	
  1017  				// LINE CHART
  1018  				if (sparklineType == 'line') {
  1019  	
  1020  						sparklineHeight = $this.data('sparkline-height') || '20px';
  1021  					    sparklineWidth = $this.data('sparkline-width') || '90px';
  1022  					    thisLineColor = $this.data('sparkline-line-color') || $this.css('color') || '#0000f0';
  1023  					    thisLineWidth = $this.data('sparkline-line-width') || 1;
  1024  					    thisFill = $this.data('fill-color') || '#c0d0f0';
  1025  					    thisSpotColor = $this.data('sparkline-spot-color') || '#f08000';
  1026  					    thisMinSpotColor = $this.data('sparkline-minspot-color') || '#ed1c24';
  1027  					    thisMaxSpotColor = $this.data('sparkline-maxspot-color') || '#f08000';
  1028  					    thishighlightSpotColor = $this.data('sparkline-highlightspot-color') || '#50f050';
  1029  					    thisHighlightLineColor = $this.data('sparkline-highlightline-color') || 'f02020';
  1030  					    thisSpotRadius = $this.data('sparkline-spotradius') || 1.5;
  1031  						thisChartMinYRange = $this.data('sparkline-min-y') || 'undefined'; 
  1032  						thisChartMaxYRange = $this.data('sparkline-max-y') || 'undefined'; 
  1033  						thisChartMinXRange = $this.data('sparkline-min-x') || 'undefined'; 
  1034  						thisChartMaxXRange = $this.data('sparkline-max-x') || 'undefined'; 
  1035  						thisMinNormValue = $this.data('min-val') || 'undefined'; 
  1036  						thisMaxNormValue = $this.data('max-val') || 'undefined'; 
  1037  						thisNormColor =  $this.data('norm-color') || '#c0c0c0';
  1038  						thisDrawNormalOnTop = $this.data('draw-normal') || false;
  1039  					    
  1040  					$this.sparkline('html', {
  1041  						type : 'line',
  1042  						width : sparklineWidth,
  1043  						height : sparklineHeight,
  1044  						lineWidth : thisLineWidth,
  1045  						lineColor : thisLineColor,
  1046  						fillColor : thisFill,
  1047  						spotColor : thisSpotColor,
  1048  						minSpotColor : thisMinSpotColor,
  1049  						maxSpotColor : thisMaxSpotColor,
  1050  						highlightSpotColor : thishighlightSpotColor,
  1051  						highlightLineColor : thisHighlightLineColor,
  1052  						spotRadius : thisSpotRadius,
  1053  						chartRangeMin : thisChartMinYRange,
  1054  						chartRangeMax : thisChartMaxYRange,
  1055  						chartRangeMinX : thisChartMinXRange,
  1056  						chartRangeMaxX : thisChartMaxXRange,
  1057  						normalRangeMin : thisMinNormValue,
  1058  						normalRangeMax : thisMaxNormValue,
  1059  						normalRangeColor : thisNormColor,
  1060  						drawNormalOnTop : thisDrawNormalOnTop
  1061  	
  1062  					});
  1063  					
  1064  					$this = null;
  1065  	
  1066  				}
  1067  	
  1068  				// PIE CHART
  1069  				if (sparklineType == 'pie') {
  1070  	
  1071  						pieColors = $this.data('sparkline-piecolor') || ["#B4CAD3", "#4490B1", "#98AA56", "#da532c","#6E9461", "#0099c6", "#990099", "#717D8A"];
  1072  					    pieWidthHeight = $this.data('sparkline-piesize') || 90;
  1073  					    pieBorderColor = $this.data('border-color') || '#45494C';
  1074  					    pieOffset = $this.data('sparkline-offset') || 0;
  1075  					    
  1076  					$this.sparkline('html', {
  1077  						type : 'pie',
  1078  						width : pieWidthHeight,
  1079  						height : pieWidthHeight,
  1080  						tooltipFormat : '<span style="color: {{color}}">&#9679;</span> ({{percent.1}}%)',
  1081  						sliceColors : pieColors,
  1082  						borderWidth : 1,
  1083  						offset : pieOffset,
  1084  						borderColor : pieBorderColor
  1085  					});
  1086  					
  1087  					$this = null;
  1088  	
  1089  				}
  1090  	
  1091  				// BOX PLOT
  1092  				if (sparklineType == 'box') {
  1093  	
  1094  						thisBoxWidth = $this.data('sparkline-width') || 'auto';
  1095  					    thisBoxHeight = $this.data('sparkline-height') || 'auto';
  1096  					    thisBoxRaw = $this.data('sparkline-boxraw') || false;
  1097  					    thisBoxTarget = $this.data('sparkline-targetval') || 'undefined';
  1098  					    thisBoxMin = $this.data('sparkline-min') || 'undefined';
  1099  					    thisBoxMax = $this.data('sparkline-max') || 'undefined';
  1100  					    thisShowOutlier = $this.data('sparkline-showoutlier') || true;
  1101  					    thisIQR = $this.data('sparkline-outlier-iqr') || 1.5;
  1102  					    thisBoxSpotRadius = $this.data('sparkline-spotradius') || 1.5;
  1103  					    thisBoxLineColor = $this.css('color') || '#000000';
  1104  					    thisBoxFillColor = $this.data('fill-color') || '#c0d0f0';
  1105  					    thisBoxWhisColor = $this.data('sparkline-whis-color') || '#000000';
  1106  					    thisBoxOutlineColor = $this.data('sparkline-outline-color') || '#303030';
  1107  					    thisBoxOutlineFill = $this.data('sparkline-outlinefill-color') || '#f0f0f0';
  1108  					    thisBoxMedianColor = $this.data('sparkline-outlinemedian-color') || '#f00000';
  1109  					    thisBoxTargetColor = $this.data('sparkline-outlinetarget-color') || '#40a020';
  1110  					    
  1111  					$this.sparkline('html', {
  1112  						type : 'box',
  1113  						width : thisBoxWidth,
  1114  						height : thisBoxHeight,
  1115  						raw : thisBoxRaw,
  1116  						target : thisBoxTarget,
  1117  						minValue : thisBoxMin,
  1118  						maxValue : thisBoxMax,
  1119  						showOutliers : thisShowOutlier,
  1120  						outlierIQR : thisIQR,
  1121  						spotRadius : thisBoxSpotRadius,
  1122  						boxLineColor : thisBoxLineColor,
  1123  						boxFillColor : thisBoxFillColor,
  1124  						whiskerColor : thisBoxWhisColor,
  1125  						outlierLineColor : thisBoxOutlineColor,
  1126  						outlierFillColor : thisBoxOutlineFill,
  1127  						medianColor : thisBoxMedianColor,
  1128  						targetColor : thisBoxTargetColor
  1129  	
  1130  					});
  1131  					
  1132  					$this = null;
  1133  	
  1134  				}
  1135  	
  1136  				// BULLET
  1137  				if (sparklineType == 'bullet') {
  1138  	
  1139  					var thisBulletHeight = $this.data('sparkline-height') || 'auto';
  1140  					    thisBulletWidth = $this.data('sparkline-width') || 2;
  1141  					    thisBulletColor = $this.data('sparkline-bullet-color') || '#ed1c24';
  1142  					    thisBulletPerformanceColor = $this.data('sparkline-performance-color') || '#3030f0';
  1143  					    thisBulletRangeColors = $this.data('sparkline-bulletrange-color') || ["#d3dafe", "#a8b6ff", "#7f94ff"];
  1144  					    
  1145  					$this.sparkline('html', {
  1146  	
  1147  						type : 'bullet',
  1148  						height : thisBulletHeight,
  1149  						targetWidth : thisBulletWidth,
  1150  						targetColor : thisBulletColor,
  1151  						performanceColor : thisBulletPerformanceColor,
  1152  						rangeColors : thisBulletRangeColors
  1153  	
  1154  					});
  1155  					
  1156  					$this = null;
  1157  	
  1158  				}
  1159  	
  1160  				// DISCRETE
  1161  				if (sparklineType == 'discrete') {
  1162  	
  1163  					 	thisDiscreteHeight = $this.data('sparkline-height') || 26;
  1164  					    thisDiscreteWidth = $this.data('sparkline-width') || 50;
  1165  					    thisDiscreteLineColor = $this.css('color');
  1166  					    thisDiscreteLineHeight = $this.data('sparkline-line-height') || 5;
  1167  					    thisDiscreteThrushold = $this.data('sparkline-threshold') || 'undefined';
  1168  					    thisDiscreteThrusholdColor = $this.data('sparkline-threshold-color') || '#ed1c24';
  1169  					    
  1170  					$this.sparkline('html', {
  1171  	
  1172  						type : 'discrete',
  1173  						width : thisDiscreteWidth,
  1174  						height : thisDiscreteHeight,
  1175  						lineColor : thisDiscreteLineColor,
  1176  						lineHeight : thisDiscreteLineHeight,
  1177  						thresholdValue : thisDiscreteThrushold,
  1178  						thresholdColor : thisDiscreteThrusholdColor
  1179  	
  1180  					});
  1181  					
  1182  					$this = null;
  1183  	
  1184  				}
  1185  	
  1186  				// TRISTATE
  1187  				if (sparklineType == 'tristate') {
  1188  	
  1189  					 	thisTristateHeight = $this.data('sparkline-height') || 26;
  1190  					    thisTristatePosBarColor = $this.data('sparkline-posbar-color') || '#60f060';
  1191  					    thisTristateNegBarColor = $this.data('sparkline-negbar-color') || '#f04040';
  1192  					    thisTristateZeroBarColor = $this.data('sparkline-zerobar-color') || '#909090';
  1193  					    thisTristateBarWidth = $this.data('sparkline-barwidth') || 5;
  1194  					    thisTristateBarSpacing = $this.data('sparkline-barspacing') || 2;
  1195  					    thisZeroAxis = $this.data('sparkline-zeroaxis') || false;
  1196  					    
  1197  					$this.sparkline('html', {
  1198  	
  1199  						type : 'tristate',
  1200  						height : thisTristateHeight,
  1201  						posBarColor : thisBarColor,
  1202  						negBarColor : thisTristateNegBarColor,
  1203  						zeroBarColor : thisTristateZeroBarColor,
  1204  						barWidth : thisTristateBarWidth,
  1205  						barSpacing : thisTristateBarSpacing,
  1206  						zeroAxis : thisZeroAxis
  1207  	
  1208  					});
  1209  					
  1210  					$this = null;
  1211  	
  1212  				}
  1213  	
  1214  				//COMPOSITE: BAR
  1215  				if (sparklineType == 'compositebar') {
  1216  	
  1217  				 	sparklineHeight = $this.data('sparkline-height') || '20px';
  1218  				    sparklineWidth = $this.data('sparkline-width') || '100%';
  1219  				    sparklineBarWidth = $this.data('sparkline-barwidth') || 3;
  1220  				    thisLineWidth = $this.data('sparkline-line-width') || 1;
  1221  				    thisLineColor = $this.data('data-sparkline-linecolor') || '#ed1c24';
  1222  				    thisBarColor = $this.data('data-sparkline-barcolor') || '#333333';
  1223  					    
  1224  					$this.sparkline($this.data('sparkline-bar-val'), {
  1225  	
  1226  						type : 'bar',
  1227  						width : sparklineWidth,
  1228  						height : sparklineHeight,
  1229  						barColor : thisBarColor,
  1230  						barWidth : sparklineBarWidth
  1231  						//barSpacing: 5
  1232  	
  1233  					});
  1234  	
  1235  					$this.sparkline($this.data('sparkline-line-val'), {
  1236  	
  1237  						width : sparklineWidth,
  1238  						height : sparklineHeight,
  1239  						lineColor : thisLineColor,
  1240  						lineWidth : thisLineWidth,
  1241  						composite : true,
  1242  						fillColor : false
  1243  	
  1244  					});
  1245  					
  1246  					$this = null;
  1247  	
  1248  				}
  1249  	
  1250  				//COMPOSITE: LINE
  1251  				if (sparklineType == 'compositeline') {
  1252  	
  1253  						sparklineHeight = $this.data('sparkline-height') || '20px';
  1254  					    sparklineWidth = $this.data('sparkline-width') || '90px';
  1255  					    sparklineValue = $this.data('sparkline-bar-val');
  1256  					    sparklineValueSpots1 = $this.data('sparkline-bar-val-spots-top') || null;
  1257  					    sparklineValueSpots2 = $this.data('sparkline-bar-val-spots-bottom') || null;
  1258  					    thisLineWidth1 = $this.data('sparkline-line-width-top') || 1;
  1259  					    thisLineWidth2 = $this.data('sparkline-line-width-bottom') || 1;
  1260  					    thisLineColor1 = $this.data('sparkline-color-top') || '#333333';
  1261  					    thisLineColor2 = $this.data('sparkline-color-bottom') || '#ed1c24';
  1262  					    thisSpotRadius1 = $this.data('sparkline-spotradius-top') || 1.5;
  1263  					    thisSpotRadius2 = $this.data('sparkline-spotradius-bottom') || thisSpotRadius1;
  1264  					    thisSpotColor = $this.data('sparkline-spot-color') || '#f08000';
  1265  					    thisMinSpotColor1 = $this.data('sparkline-minspot-color-top') || '#ed1c24';
  1266  					    thisMaxSpotColor1 = $this.data('sparkline-maxspot-color-top') || '#f08000';
  1267  					    thisMinSpotColor2 = $this.data('sparkline-minspot-color-bottom') || thisMinSpotColor1;
  1268  					    thisMaxSpotColor2 = $this.data('sparkline-maxspot-color-bottom') || thisMaxSpotColor1;
  1269  					    thishighlightSpotColor1 = $this.data('sparkline-highlightspot-color-top') || '#50f050';
  1270  					    thisHighlightLineColor1 = $this.data('sparkline-highlightline-color-top') || '#f02020';
  1271  					    thishighlightSpotColor2 = $this.data('sparkline-highlightspot-color-bottom') ||
  1272  					        thishighlightSpotColor1;
  1273  					    thisHighlightLineColor2 = $this.data('sparkline-highlightline-color-bottom') ||
  1274  					        thisHighlightLineColor1;
  1275  					    thisFillColor1 = $this.data('sparkline-fillcolor-top') || 'transparent';
  1276  					    thisFillColor2 = $this.data('sparkline-fillcolor-bottom') || 'transparent';
  1277  					    
  1278  					$this.sparkline(sparklineValue, {
  1279  	
  1280  						type : 'line',
  1281  						spotRadius : thisSpotRadius1,
  1282  	
  1283  						spotColor : thisSpotColor,
  1284  						minSpotColor : thisMinSpotColor1,
  1285  						maxSpotColor : thisMaxSpotColor1,
  1286  						highlightSpotColor : thishighlightSpotColor1,
  1287  						highlightLineColor : thisHighlightLineColor1,
  1288  	
  1289  						valueSpots : sparklineValueSpots1,
  1290  	
  1291  						lineWidth : thisLineWidth1,
  1292  						width : sparklineWidth,
  1293  						height : sparklineHeight,
  1294  						lineColor : thisLineColor1,
  1295  						fillColor : thisFillColor1
  1296  	
  1297  					});
  1298  	
  1299  					$this.sparkline($this.data('sparkline-line-val'), {
  1300  	
  1301  						type : 'line',
  1302  						spotRadius : thisSpotRadius2,
  1303  	
  1304  						spotColor : thisSpotColor,
  1305  						minSpotColor : thisMinSpotColor2,
  1306  						maxSpotColor : thisMaxSpotColor2,
  1307  						highlightSpotColor : thishighlightSpotColor2,
  1308  						highlightLineColor : thisHighlightLineColor2,
  1309  	
  1310  						valueSpots : sparklineValueSpots2,
  1311  	
  1312  						lineWidth : thisLineWidth2,
  1313  						width : sparklineWidth,
  1314  						height : sparklineHeight,
  1315  						lineColor : thisLineColor2,
  1316  						composite : true,
  1317  						fillColor : thisFillColor2
  1318  	
  1319  					});
  1320  					
  1321  					$this = null;
  1322  	
  1323  				}
  1324  	
  1325  			});
  1326  	
  1327  		}// end if
  1328  	
  1329  		/*
  1330  		 * EASY PIE CHARTS
  1331  		 * DEPENDENCY: js/plugins/easy-pie-chart/jquery.easy-pie-chart.min.js
  1332  		 * Usage: <div class="easy-pie-chart txt-color-orangeDark" data-pie-percent="33" data-pie-size="72" data-size="72">
  1333  		 *			<span class="percent percent-sign">35</span>
  1334  		 * 	  	  </div>
  1335  		 */
  1336  	
  1337  		if ($.fn.easyPieChart) {
  1338  	
  1339  			$('.easy-pie-chart').each(function() {
  1340  				var $this = $(this),
  1341  					barColor = $this.css('color') || $this.data('pie-color'),
  1342  				    trackColor = $this.data('pie-track-color') || 'rgba(0,0,0,0.04)',
  1343  				    size = parseInt($this.data('pie-size')) || 25;
  1344  				    
  1345  				$this.easyPieChart({
  1346  					
  1347  					barColor : barColor,
  1348  					trackColor : trackColor,
  1349  					scaleColor : false,
  1350  					lineCap : 'butt',
  1351  					lineWidth : parseInt(size / 8.5),
  1352  					animate : 1500,
  1353  					rotate : -90,
  1354  					size : size,
  1355  					onStep: function(from, to, percent) {
  1356              			$(this.el).find('.percent').text(Math.round(percent));
  1357          			}
  1358  					
  1359  				});
  1360  				
  1361  				$this = null;
  1362  			});
  1363  	
  1364  		} // end if
  1365  	
  1366  	}
  1367  /* ~ END: INITIALIZE CHARTS */
  1368  
  1369  /*
  1370   * INITIALIZE JARVIS WIDGETS
  1371   * Setup Desktop Widgets
  1372   */
  1373  	function setup_widgets_desktop() {
  1374  	
  1375  		if ($.fn.jarvisWidgets && enableJarvisWidgets) {
  1376  
  1377  			$('#widget-grid').jarvisWidgets({
  1378  	
  1379  				grid : 'article',
  1380  				widgets : '.jarviswidget',
  1381  				localStorage : localStorageJarvisWidgets,
  1382  				deleteSettingsKey : '#deletesettingskey-options',
  1383  				settingsKeyLabel : 'Reset settings?',
  1384  				deletePositionKey : '#deletepositionkey-options',
  1385  				positionKeyLabel : 'Reset position?',
  1386  				sortable : sortableJarvisWidgets,
  1387  				buttonsHidden : false,
  1388  				// toggle button
  1389  				toggleButton : true,
  1390  				toggleClass : 'fa fa-minus | fa fa-plus',
  1391  				toggleSpeed : 200,
  1392  				onToggle : function() {
  1393  				},
  1394  				// delete btn
  1395  				deleteButton : true,
  1396  				deleteMsg:'Warning: This action cannot be undone!',
  1397  				deleteClass : 'fa fa-times',
  1398  				deleteSpeed : 200,
  1399  				onDelete : function() {
  1400  				},
  1401  				// edit btn
  1402  				editButton : true,
  1403  				editPlaceholder : '.jarviswidget-editbox',
  1404  				editClass : 'fa fa-cog | fa fa-save',
  1405  				editSpeed : 200,
  1406  				onEdit : function() {
  1407  				},
  1408  				// color button
  1409  				colorButton : true,
  1410  				// full screen
  1411  				fullscreenButton : true,
  1412  				fullscreenClass : 'fa fa-expand | fa fa-compress',
  1413  				fullscreenDiff : 3,
  1414  				onFullscreen : function() {
  1415  				},
  1416  				// custom btn
  1417  				customButton : false,
  1418  				customClass : 'folder-10 | next-10',
  1419  				customStart : function() {
  1420  					alert('Hello you, this is a custom button...');
  1421  				},
  1422  				customEnd : function() {
  1423  					alert('bye, till next time...');
  1424  				},
  1425  				// order
  1426  				buttonOrder : '%refresh% %custom% %edit% %toggle% %fullscreen% %delete%',
  1427  				opacity : 1.0,
  1428  				dragHandle : '> header',
  1429  				placeholderClass : 'jarviswidget-placeholder',
  1430  				indicator : true,
  1431  				indicatorTime : 600,
  1432  				ajax : true,
  1433  				timestampPlaceholder : '.jarviswidget-timestamp',
  1434  				timestampFormat : 'Last update: %m%/%d%/%y% %h%:%i%:%s%',
  1435  				refreshButton : true,
  1436  				refreshButtonClass : 'fa fa-refresh',
  1437  				labelError : 'Sorry but there was a error:',
  1438  				labelUpdated : 'Last Update:',
  1439  				labelRefresh : 'Refresh',
  1440  				labelDelete : 'Delete widget:',
  1441  				afterLoad : function() {
  1442  				},
  1443  				rtl : false, // best not to toggle this!
  1444  				onChange : function() {
  1445  					
  1446  				},
  1447  				onSave : function() {
  1448  					
  1449  				},
  1450  				ajaxnav : $.navAsAjax // declears how the localstorage should be saved (HTML or AJAX Version)
  1451  	
  1452  			});
  1453  	
  1454  		}
  1455  	
  1456  	}
  1457  /*
  1458   * SETUP DESKTOP WIDGET
  1459   */
  1460  	function setup_widgets_mobile() {
  1461  	
  1462  		if (enableMobileWidgets && enableJarvisWidgets) {
  1463  			setup_widgets_desktop();
  1464  		}
  1465  	
  1466  	}
  1467  /* ~ END: INITIALIZE JARVIS WIDGETS */
  1468  
  1469  /*
  1470   * GOOGLE MAPS
  1471   * description: Append google maps to head dynamically (only execute for ajax version)
  1472   * Loads at the begining for ajax pages
  1473   */
  1474  	if ($.navAsAjax || $(".google_maps")){
  1475  		var gMapsLoaded = false;
  1476  		window.gMapsCallback = function() {
  1477  			gMapsLoaded = true;
  1478  			$(window).trigger('gMapsLoaded');
  1479  		};
  1480  		window.loadGoogleMaps = function() {
  1481  			if (gMapsLoaded)
  1482  				return window.gMapsCallback();
  1483  			var script_tag = document.createElement('script');
  1484  			script_tag.setAttribute("type", "text/javascript");
  1485  			script_tag.setAttribute("src", "http://maps.google.com/maps/api/js?sensor=false&callback=gMapsCallback");
  1486  			(document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
  1487  		};
  1488  	}
  1489  /* ~ END: GOOGLE MAPS */
  1490  
  1491  /*
  1492   * LOAD SCRIPTS
  1493   * Usage:
  1494   * Define function = myPrettyCode ()...
  1495   * loadScript("js/my_lovely_script.js", myPrettyCode);
  1496   */
  1497  	function loadScript(scriptName, callback) {
  1498  	
  1499  		if (!jsArray[scriptName]) {
  1500  			jsArray[scriptName] = true;
  1501  	
  1502  			// adding the script tag to the head as suggested before
  1503  			var body = document.getElementsByTagName('body')[0],
  1504  				script = document.createElement('script');
  1505  			script.type = 'text/javascript';
  1506  			script.src = scriptName;
  1507  	
  1508  			// then bind the event to the callback function
  1509  			// there are several events for cross browser compatibility
  1510  			script.onload = callback;
  1511  	
  1512  			// fire the loading
  1513  			body.appendChild(script);
  1514  			
  1515  			// clear DOM reference
  1516  			//body = null;
  1517  			//script = null;
  1518  	
  1519  		} else if (callback) {
  1520  			// changed else to else if(callback)
  1521  			if (debugState){
  1522  				root.root.console.log("This script was already loaded %c: " + scriptName, debugStyle_warning);
  1523  			}
  1524  			//execute function
  1525  			callback();
  1526  		}
  1527  	
  1528  	}
  1529  /* ~ END: LOAD SCRIPTS */
  1530  
  1531  /*
  1532  * APP AJAX REQUEST SETUP
  1533  * Description: Executes and fetches all ajax requests also
  1534  * updates naivgation elements to active
  1535  */
  1536  	if($.navAsAjax) {
  1537  	    // fire this on page load if nav exists
  1538  	    if ($('nav').length) {
  1539  		    checkURL();
  1540  	    }
  1541  	
  1542  	    $(document).on('click', 'nav a[href!="#"]', function(e) {
  1543  		    e.preventDefault();
  1544  		    var $this = $(e.currentTarget);
  1545  	
  1546  		    // if parent is not active then get hash, or else page is assumed to be loaded
  1547  			if (!$this.parent().hasClass("active") && !$this.attr('target')) {
  1548  	
  1549  			    // update window with hash
  1550  			    // you could also do here:  thisDevice === "mobile" - and save a little more memory
  1551  	
  1552  			    if ($.root_.hasClass('mobile-view-activated')) {
  1553  				    $.root_.removeClass('hidden-menu');
  1554  				    $('html').removeClass("hidden-menu-mobile-lock");
  1555  				    window.setTimeout(function() {
  1556  						if (window.location.search) {
  1557  							window.location.href =
  1558  								window.location.href.replace(window.location.search, '')
  1559  									.replace(window.location.hash, '') + '#' + $this.attr('href');
  1560  						} else {
  1561  							window.location.hash = $this.attr('href');
  1562  						}
  1563  				    }, 150);
  1564  				    // it may not need this delay...
  1565  			    } else {
  1566  					if (window.location.search) {
  1567  						window.location.href =
  1568  							window.location.href.replace(window.location.search, '')
  1569  								.replace(window.location.hash, '') + '#' + $this.attr('href');
  1570  					} else {
  1571  						window.location.hash = $this.attr('href');
  1572  					}
  1573  			    }
  1574  			    
  1575  			    // clear DOM reference
  1576  			    // $this = null;
  1577  		    }
  1578  	
  1579  	    });
  1580  	
  1581  	    // fire links with targets on different window
  1582  	    $(document).on('click', 'nav a[target="_blank"]', function(e) {
  1583  		    e.preventDefault();
  1584  		    var $this = $(e.currentTarget);
  1585  	
  1586  		    window.open($this.attr('href'));
  1587  	    });
  1588  	
  1589  	    // fire links with targets on same window
  1590  	    $(document).on('click', 'nav a[target="_top"]', function(e) {
  1591  		    e.preventDefault();
  1592  		    var $this = $(e.currentTarget);
  1593  	
  1594  		    window.location = ($this.attr('href'));
  1595  	    });
  1596  	
  1597  	    // all links with hash tags are ignored
  1598  	    $(document).on('click', 'nav a[href="#"]', function(e) {
  1599  		    e.preventDefault();
  1600  	    });
  1601  	
  1602  	    // DO on hash change
  1603  	    $(window).on('hashchange', function() {
  1604  		    checkURL();
  1605  	    });
  1606  	}
  1607  /*
  1608   * CHECK TO SEE IF URL EXISTS
  1609   */
  1610  	function checkURL() {
  1611  	
  1612  		//get the url by removing the hash
  1613  		//var url = location.hash.replace(/^#/, '');
  1614  		var url = location.href.split('#').splice(1).join('#');
  1615  		//BEGIN: IE11 Work Around
  1616  		if (!url) {
  1617  		
  1618  			try {
  1619  				var documentUrl = window.document.URL;
  1620  				if (documentUrl) {
  1621  					if (documentUrl.indexOf('#', 0) > 0 && documentUrl.indexOf('#', 0) < (documentUrl.length + 1)) {
  1622  						url = documentUrl.substring(documentUrl.indexOf('#', 0) + 1);
  1623  		
  1624  					}
  1625  		
  1626  				}
  1627  		
  1628  			} catch (err) {}
  1629  		}
  1630  		//END: IE11 Work Around
  1631  	
  1632  		container = $('#content');
  1633  		// Do this if url exists (for page refresh, etc...)
  1634  		if (url) {
  1635  			// remove all active class
  1636  			$('nav li.active').removeClass("active");
  1637  			// match the url and add the active class
  1638  			$('nav li:has(a[href="' + url + '"])').addClass("active");
  1639  			var title = ($('nav a[href="' + url + '"]').attr('title'));
  1640  	
  1641  			// change page title from global var
  1642  			document.title = (title || document.title);
  1643  			
  1644  			// debugState
  1645  			if (debugState){
  1646  				root.console.log("Page title: %c " + document.title, debugStyle_green);
  1647  			}
  1648  			
  1649  			// parse url to jquery
  1650  			loadURL(url + location.search, container);
  1651  
  1652  		} else {
  1653  	
  1654  			// grab the first URL from nav
  1655  			var $this = $('nav > ul > li:first-child > a[href!="#"]');
  1656  	
  1657  			//update hash
  1658  			window.location.hash = $this.attr('href');
  1659  			
  1660  			//clear dom reference
  1661  			$this = null;
  1662  	
  1663  		}
  1664  	
  1665  	}
  1666  /*
  1667   * LOAD AJAX PAGES
  1668   */ 
  1669  	function loadURL(url, container) {
  1670  
  1671  		// debugState
  1672  		if (debugState){
  1673  			root.root.console.log("Loading URL: %c" + url, debugStyle);
  1674  		}
  1675  
  1676  		$.ajax({
  1677  			type : "GET",
  1678  			url : url,
  1679  			dataType : 'html',
  1680  			cache : true, // (warning: setting it to false will cause a timestamp and will call the request twice)
  1681  			beforeSend : function() {
  1682  				
  1683  				//IE11 bug fix for googlemaps (delete all google map instances)
  1684  				//check if the page is ajax = true, has google map class and the container is #content
  1685  				if ($.navAsAjax && $(".google_maps")[0] && (container[0] == $("#content")[0]) ) {
  1686  					
  1687  					// target gmaps if any on page
  1688  					var collection = $(".google_maps"),
  1689  						i = 0;
  1690  					// run for each	map
  1691  					collection.each(function() {
  1692  					    i ++;
  1693  					    // get map id from class elements
  1694  					    var divDealerMap = document.getElementById(this.id);
  1695  					    
  1696  					    if(i == collection.length + 1) {
  1697  						    // "callback"
  1698  						} else {
  1699  							// destroy every map found
  1700  							if (divDealerMap) divDealerMap.parentNode.removeChild(divDealerMap);
  1701  
  1702  							// debugState
  1703  							if (debugState){
  1704  								root.console.log("Destroying maps.........%c" + this.id, debugStyle_warning);
  1705  							}
  1706  						}
  1707  					});
  1708  
  1709  					// debugState
  1710  					if (debugState){
  1711  						root.console.log("✔ Google map instances nuked!!!");
  1712  					}
  1713  					
  1714  				} //end fix
  1715  				
  1716  				// destroy all datatable instances
  1717  				if ( $.navAsAjax && $('.dataTables_wrapper')[0] && (container[0] == $("#content")[0]) ) {
  1718  					
  1719  					var tables = $.fn.dataTable.fnTables(true);				
  1720  					$(tables).each(function () {
  1721  						
  1722  						if($(this).find('.details-control').length != 0) {
  1723  							$(this).find('*').addBack().off().remove();
  1724  							$(this).dataTable().fnDestroy();
  1725  						} else {
  1726  							$(this).dataTable().fnDestroy();
  1727  						}
  1728  					    
  1729  					});
  1730  					
  1731  					// debugState
  1732  					if (debugState){
  1733  						root.console.log("✔ Datatable instances nuked!!!");
  1734  					}
  1735  				}
  1736  				// end destroy
  1737  				
  1738  				// pop intervals (destroys jarviswidget related intervals)
  1739  				if ( $.navAsAjax && $.intervalArr.length > 0 && (container[0] == $("#content")[0]) && enableJarvisWidgets ) {
  1740  					
  1741  					while($.intervalArr.length > 0)
  1742  	        			clearInterval($.intervalArr.pop());
  1743  	        			// debugState
  1744  						if (debugState){
  1745  							root.console.log("✔ All JarvisWidget intervals cleared");
  1746  						}
  1747  	        			
  1748  				}
  1749  				// end pop intervals
  1750  				
  1751  				// destroy all widget instances
  1752  				if ( $.navAsAjax && (container[0] == $("#content")[0]) && enableJarvisWidgets && $("#widget-grid")[0] ) {
  1753  					
  1754  					$("#widget-grid").jarvisWidgets('destroy');
  1755  					// debugState
  1756  					if (debugState){
  1757  						root.console.log("✔ JarvisWidgets destroyed");
  1758  					} 
  1759  					
  1760  				}
  1761  				// end destroy all widgets 
  1762  				
  1763  				// cluster destroy: destroy other instances that could be on the page 
  1764  				// this runs a script in the current loaded page before fetching the new page
  1765  				if ( $.navAsAjax && (container[0] == $("#content")[0]) ) {
  1766  
  1767  					/*
  1768  					 * The following elements should be removed, if they have been created:
  1769  					 *
  1770  					 *	colorList
  1771  					 *	icon
  1772  					 *	picker
  1773  					 *	inline
  1774  					 *	And unbind events from elements:
  1775  					 *	
  1776  					 *	icon
  1777  					 *	picker
  1778  					 *	inline
  1779  					 *	especially $(document).on('mousedown')
  1780  					 *	It will be much easier to add namespace to plugin events and then unbind using selected namespace.
  1781  					 *	
  1782  					 *	See also:
  1783  					 *	
  1784  					 *	http://f6design.com/journal/2012/05/06/a-jquery-plugin-boilerplate/
  1785  					 *	http://keith-wood.name/pluginFramework.html
  1786  					 */
  1787  					
  1788  					// this function is below the pagefunction for all pages that has instances
  1789  
  1790  					if (typeof pagedestroy == 'function') { 
  1791  
  1792  					  try {
  1793  						    pagedestroy(); 
  1794  
  1795  						    if (debugState){
  1796  								root.console.log("✔ Pagedestroy()");
  1797  						   } 
  1798  						}
  1799  						catch(err) {
  1800  						   pagedestroy = undefined; 
  1801  
  1802  						   if (debugState){
  1803  								root.console.log("! Pagedestroy() Catch Error");
  1804  						   } 
  1805  					  }
  1806  
  1807  					} 
  1808  
  1809  					// destroy all inline charts
  1810  					
  1811  					if ( $.fn.sparkline && $("#content .sparkline")[0] ) {
  1812  						$("#content .sparkline").sparkline( 'destroy' );
  1813  						
  1814  						if (debugState){
  1815  							root.console.log("✔ Sparkline Charts destroyed!");
  1816  						} 
  1817  					}
  1818  					
  1819  					if ( $.fn.easyPieChart && $("#content .easy-pie-chart")[0] ) {
  1820  						$("#content .easy-pie-chart").easyPieChart( 'destroy' );
  1821  						
  1822  						if (debugState){
  1823  							root.console.log("✔ EasyPieChart Charts destroyed!");
  1824  						} 
  1825  					}
  1826  
  1827  					
  1828  
  1829  					// end destory all inline charts
  1830  					
  1831  					// destroy form controls: Datepicker, select2, autocomplete, mask, bootstrap slider
  1832  					
  1833  					if ( $.fn.select2 && $("#content select.select2")[0] ) {
  1834  						$("#content select.select2").select2('destroy');
  1835  						
  1836  						if (debugState){
  1837  							root.console.log("✔ Select2 destroyed!");
  1838  						}
  1839  					}
  1840  					
  1841  					if ( $.fn.mask && $('#content [data-mask]')[0] ) {
  1842  						$('#content [data-mask]').unmask();
  1843  						
  1844  						if (debugState){
  1845  							root.console.log("✔ Input Mask destroyed!");
  1846  						}
  1847  					}
  1848  					
  1849  					if ( $.fn.datepicker && $('#content .datepicker')[0] ) {
  1850  						$('#content .datepicker').off();
  1851  						$('#content .datepicker').remove();
  1852  						
  1853  						if (debugState){
  1854  							root.console.log("✔ Datepicker destroyed!");
  1855  						}
  1856  					}
  1857  					
  1858  					if ( $.fn.slider && $('#content .slider')[0] ) {
  1859  						$('#content .slider').off();
  1860  						$('#content .slider').remove();
  1861  						
  1862  						if (debugState){
  1863  							root.console.log("✔ Bootstrap Slider destroyed!");
  1864  						}
  1865  					}
  1866  								
  1867  					// end destroy form controls
  1868  					
  1869  					
  1870  				}
  1871  				// end cluster destroy
  1872  				
  1873  				// empty container and var to start garbage collection (frees memory)
  1874  				pagefunction = null;
  1875  				container.removeData().html("");
  1876  				
  1877  				// place cog
  1878  				container.html('<h1 class="ajax-loading-animation"><i class="fa fa-cog fa-spin"></i> Loading...</h1>');
  1879  			
  1880  				// Only draw breadcrumb if it is main content material
  1881  				if (container[0] == $("#content")[0]) {
  1882  					
  1883  					// clear everything else except these key DOM elements
  1884  					// we do this because sometime plugins will leave dynamic elements behind
  1885  					$('body').find('> *').filter(':not(' + ignore_key_elms + ')').empty().remove();
  1886  					
  1887  					// draw breadcrumb
  1888  					drawBreadCrumb();
  1889  					
  1890  					// scroll up
  1891  					$("html").animate({
  1892  						scrollTop : 0
  1893  					}, "fast");
  1894  				} 
  1895  				// end if
  1896  			},
  1897  			success : function(data) {
  1898  				
  1899  				// dump data to container
  1900  				container.css({
  1901  					opacity : '0.0'
  1902  				}).html(data).delay(50).animate({
  1903  					opacity : '1.0'
  1904  				}, 300);
  1905  				
  1906  				// clear data var
  1907  				data = null;
  1908  				container = null;
  1909  			},
  1910  			error : function(xhr, status, thrownError, error) {
  1911  				container.html('<h4 class="ajax-loading-error"><i class="fa fa-warning txt-color-orangeDark"></i> Error requesting <span class="txt-color-red">' + url + '</span>: ' + xhr.status + ' <span style="text-transform: capitalize;">'  + thrownError + '</span></h4>');
  1912  			},
  1913  			async : true 
  1914  		});
  1915  	
  1916  	}
  1917  /*
  1918   * UPDATE BREADCRUMB
  1919   */ 
  1920  	function drawBreadCrumb(opt_breadCrumbs) {
  1921  		var a = $("nav li.active > a"),
  1922  			b = a.length;
  1923  	
  1924  		bread_crumb.empty(), 
  1925  		bread_crumb.append($("<li>Home</li>")), a.each(function() {
  1926  			bread_crumb.append($("<li></li>").html($.trim($(this).clone().children(".badge").remove().end().text()))), --b || (document.title = bread_crumb.find("li:last-child").text())
  1927  		});
  1928  		
  1929  		// Push breadcrumb manually -> drawBreadCrumb(["Users", "John Doe"]);
  1930  		// Credits: Philip Whitt | philip.whitt@sbcglobal.net
  1931  		if (opt_breadCrumbs != undefined) {
  1932  			$.each(opt_breadCrumbs, function(index, value) {
  1933  				bread_crumb.append($("<li></li>").html(value)); 
  1934  				document.title = bread_crumb.find("li:last-child").text();
  1935  			});
  1936  		}
  1937  	}
  1938  /* ~ END: APP AJAX REQUEST SETUP */
  1939  
  1940  /*
  1941   * PAGE SETUP
  1942   * Description: fire certain scripts that run through the page
  1943   * to check for form elements, tooltip activation, popovers, etc...
  1944   */
  1945  	function pageSetUp() {
  1946  		if (thisDevice === "desktop"){
  1947  			// is desktop
  1948  			
  1949  			// activate tooltips
  1950  			$("[rel=tooltip], [data-rel=tooltip]").tooltip();
  1951  		
  1952  			// activate popovers
  1953  			$("[rel=popover], [data-rel=popover]").popover();
  1954  		
  1955  			// activate popovers with hover states
  1956  			$("[rel=popover-hover], [data-rel=popover-hover]").popover({
  1957  				trigger : "hover"
  1958  			});
  1959  	
  1960  			// setup widgets
  1961  			setup_widgets_desktop();
  1962  		
  1963  			// activate inline charts
  1964  			runAllCharts();
  1965  		
  1966  			// run form elements
  1967  			runAllForms();
  1968  	
  1969  		} else {
  1970  			
  1971  			// is mobile
  1972  			
  1973  			// activate popovers
  1974  			$("[rel=popover], [data-rel=popover]").popover();
  1975  		
  1976  			// activate popovers with hover states
  1977  			$("[rel=popover-hover], [data-rel=popover-hover]").popover({
  1978  				trigger : "hover"
  1979  			});
  1980  		
  1981  			// activate inline charts
  1982  			runAllCharts();
  1983  		
  1984  			// setup widgets
  1985  			setup_widgets_mobile();
  1986  		
  1987  			// run form elements
  1988  			runAllForms();
  1989  			
  1990  		}
  1991  	
  1992  	}
  1993  /* ~ END: PAGE SETUP */
  1994  
  1995  /*
  1996   * ONE POP OVER THEORY
  1997   * Keep only 1 active popover per trigger - also check and hide active popover if user clicks on document
  1998   */
  1999  	$('body').on('click', function(e) {
  2000  		$('[rel="popover"], [data-rel="popover"]').each(function() {
  2001  			//the 'is' for buttons that trigger popups
  2002  			//the 'has' for icons within a button that triggers a popup
  2003  			if (!$(this).is(e.target) && $(this).has(e.target).length === 0 && $('.popover').has(e.target).length === 0) {
  2004  				$(this).popover('hide');
  2005  			}
  2006  		});
  2007  	}); 
  2008  /* ~ END: ONE POP OVER THEORY */
  2009  
  2010  /*
  2011   * DELETE MODEL DATA ON HIDDEN
  2012   * Clears the model data once it is hidden, this way you do not create duplicated data on multiple modals
  2013   */
  2014  	$('body').on('hidden.bs.modal', '.modal', function () {
  2015  	  $(this).removeData('bs.modal');
  2016  	});
  2017  /* ~ END: DELETE MODEL DATA ON HIDDEN */
  2018  
  2019  /*
  2020   * HELPFUL FUNCTIONS
  2021   * We have included some functions below that can be resued on various occasions
  2022   * 
  2023   * Get param value
  2024   * example: alert( getParam( 'param' ) );
  2025   */
  2026  	function getParam(name) {
  2027  	    name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
  2028  	    var regexS = "[\\?&]" + name + "=([^&#]*)";
  2029  	    var regex = new RegExp(regexS);
  2030  	    var results = regex.exec(window.location.href);
  2031  	    if (results == null)
  2032  	        return "";
  2033  	    else
  2034  	        return results[1];
  2035  	}
  2036  /* ~ END: HELPFUL FUNCTIONS */