hjg
2024-07-09 30304784e82d4bba24121328da8eb8490aec4f4f
提交 | 用户 | 时间
58d006 1 /*!
A 2  * Ace v1.3.5
3  */
4
5 if (typeof jQuery === 'undefined') { throw new Error('Ace\'s JavaScript requires jQuery') }
6
7 /**
8  Required. Ace's Basic File to Initiliaze Different Parts and Some Variables.
9 */
10
11 //document ready function
12 jQuery(function($) {
13   try {
14     ace.demo.init();
15   } catch(e) {}
16 });
17
18
19 //some basic variables
20 (function(undefined) {
21     if( !('ace' in window) ) window['ace'] = {}
22     if( !('helper' in window['ace']) ) window['ace'].helper = {}
23     if( !('vars' in window['ace']) ) window['ace'].vars = {}
24     window['ace'].vars['icon'] = ' ace-icon ';
25     window['ace'].vars['.icon'] = '.ace-icon';
26
27     ace.vars['touch']    = ('ontouchstart' in window);//(('ontouchstart' in document.documentElement) || (window.DocumentTouch && document instanceof DocumentTouch));
28     
29     //sometimes the only good way to work around browser's pecularities is to detect them using user-agents
30     //though it's not accurate
31     var agent = navigator.userAgent
32     ace.vars['webkit'] = !!agent.match(/AppleWebKit/i)
33     ace.vars['safari'] = !!agent.match(/Safari/i) && !agent.match(/Chrome/i);
34     ace.vars['android'] = ace.vars['safari'] && !!agent.match(/Android/i)
35     ace.vars['ios_safari'] = !!agent.match(/OS ([4-9])(_\d)+ like Mac OS X/i) && !agent.match(/CriOS/i)
36     
37     ace.vars['ie'] = window.navigator.msPointerEnabled || (document.all && document.querySelector);//8-11
38     ace.vars['old_ie'] = document.all && !document.addEventListener;//8 and below
39     ace.vars['very_old_ie']    = document.all && !document.querySelector;//7 and below
40     ace.vars['firefox'] = 'MozAppearance' in document.documentElement.style;
41     
42     ace.vars['non_auto_fixed'] = ace.vars['android'] || ace.vars['ios_safari'];
43     
44     
45     //sometimes we try to use 'tap' event instead of 'click' if jquery mobile plugin is available
46     ace['click_event'] = ace.vars['touch'] && jQuery.fn.tap ? 'tap' : 'click';
47 })();
48
49
50
51 (function($ , undefined) {
52
53     ace.demo = {
54         functions: {},
55         
56         init: function(initAnyway) {
57             //initAnyway used to make sure the call is from our RequireJS app and not a document ready event!
58             var initAnyway = !!initAnyway && true;
59             if(typeof requirejs !== "undefined" && !initAnyway) return;
60             
61             for(var func in ace.demo.functions) if(ace.demo.functions.hasOwnProperty(func)) {
62                 ace.demo.functions[func]();
63             }
64         }
65     }
66
67
68     ace.demo.functions.basics = function() {
69         // for android and ios we don't use "top:auto" when breadcrumbs is fixed
70         if(ace.vars['non_auto_fixed']) {
71             $('body').addClass('mob-safari');
72         }
73
74         ace.vars['transition'] = ace.vars['animation'] || !!$.support.transition;
75     }
76     
77     ace.demo.functions.enableSidebar = function() {
78         //initiate sidebar function
79         var $sidebar = $('.sidebar');
80         if($.fn.ace_sidebar) $sidebar.ace_sidebar();
81         if($.fn.ace_sidebar_scroll) $sidebar.ace_sidebar_scroll({
82             //for other options please see documentation
83             'include_toggle': false || ace.vars['safari'] || ace.vars['ios_safari'] //true = include toggle button in the scrollbars
84         });
85         if($.fn.ace_sidebar_hover)    $sidebar.ace_sidebar_hover({
86             'sub_hover_delay': 750,
87             'sub_scroll_style': 'no-track scroll-thin scroll-margin scroll-visible'
88         });
89     }
90
91     
92     //Load content via ajax
93     ace.demo.functions.enableDemoAjax = function() {
94         if(!$.fn.ace_ajax) return;
95  
96         if(window.Pace) {
97             window.paceOptions = {
98                 ajax: true,
99                 document: true,
100                 eventLag: false // disabled
101                 //elements: {selectors: ['.page-content-area']}
102             }
103         }
104
105         var demo_ajax_options = {
106              'close_active': true,
107              
108              close_mobile_menu: '#sidebar',
109              close_dropdowns: true,
110              
111              'default_url': 'page/index',//default hash
112              'content_url': function(hash) {
113                 //***NOTE***
114                 //this is for Ace demo only, you should change it to return a valid URL
115                 //please refer to documentation for more info
116
117                 if( !hash.match(/^page\//) ) return false;
118                 var path = document.location.pathname;
119
120                 //for example in Ace HTML demo version we convert /ajax/index.html#page/gallery to > /ajax/content/gallery.html and load it
121                 if(path.match(/(\/ajax\/)(index\.html)?/))
122                     return path.replace(/(\/ajax\/)(index\.html)?/, '/ajax/content/'+hash.replace(/^page\//, '')+'.html') ;
123
124                 //for example in Ace PHP demo version we convert "ajax.php#page/dashboard" to "ajax.php?page=dashboard" and load it
125                 return path + "?" + hash.replace(/\//, "=");
126               }              
127         }
128            
129         //for IE9 and below we exclude PACE loader (using conditional IE comments)
130         //for other browsers we use the following extra ajax loader options
131         if(window.Pace) {
132             demo_ajax_options['loading_overlay'] = 'body';//the opaque overlay is applied to 'body'
133         }
134
135         //initiate ajax loading on this element( which is .page-content-area[data-ajax-content=true] in Ace's demo)
136         $('[data-ajax-content=true]').ace_ajax(demo_ajax_options)
137
138         //if general error happens and ajax is working, let's stop loading icon & PACE
139         $(window).on('error.ace_ajax', function() {
140             $('[data-ajax-content=true]').each(function() {
141                 var $this = $(this);
142                 if( $this.ace_ajax('working') ) {
143                     if(window.Pace && Pace.running) Pace.stop();
144                     $this.ace_ajax('stopLoading', true);
145                 }
146             })
147         })
148     }
149
150     /////////////////////////////
151
152     ace.demo.functions.handleScrollbars = function() {
153         //add scrollbars for navbar dropdowns
154         var has_scroll = !!$.fn.ace_scroll;
155         if(has_scroll) $('.dropdown-content').ace_scroll({reset: false, mouseWheelLock: true})
156
157         //reset scrolls bars on window resize
158         if(has_scroll && !ace.vars['old_ie']) {//IE has an issue with widget fullscreen on ajax?!!!
159             $(window).on('resize.reset_scroll', function() {
160                 $('.ace-scroll:not(.scroll-disabled)').not(':hidden').ace_scroll('reset');
161             });
162             if(has_scroll) $(document).on('settings.ace.reset_scroll', function(e, name) {
163                 if(name == 'sidebar_collapsed') $('.ace-scroll:not(.scroll-disabled)').not(':hidden').ace_scroll('reset');
164             });
165         }
166     }
167
168
169     ace.demo.functions.dropdownAutoPos = function() {
170         //change a dropdown to "dropup" depending on its position
171         $(document).on('click.dropdown.pos', '.dropdown-toggle[data-position="auto"]', function() {
172             var offset = $(this).offset();
173             var parent = $(this.parentNode);
174
175             if ( parseInt(offset.top + $(this).height()) + 50 
176                     >
177                 (ace.helper.scrollTop() + ace.helper.winHeight() - parent.find('.dropdown-menu').eq(0).height()) 
178                 ) parent.addClass('dropup');
179             else parent.removeClass('dropup');
180         });
181     }
182
183     
184     ace.demo.functions.navbarHelpers = function() {
185         //prevent dropdowns from hiding when a from is clicked
186         /**$(document).on('click', '.dropdown-navbar form', function(e){
187             e.stopPropagation();
188         });*/
189
190
191         //disable navbar icon animation upon click
192         $('.ace-nav [class*="icon-animated-"]').closest('a').one('click', function(){
193             var icon = $(this).find('[class*="icon-animated-"]').eq(0);
194             var $match = icon.attr('class').match(/icon\-animated\-([\d\w]+)/);
195             icon.removeClass($match[0]);
196         });
197
198
199         //prevent dropdowns from hiding when a tab is selected
200         $(document).on('click', '.dropdown-navbar .nav-tabs', function(e){
201             e.stopPropagation();
202             var $this , href
203             var that = e.target
204             if( ($this = $(e.target).closest('[data-toggle=tab]')) && $this.length > 0) {
205                 $this.tab('show');
206                 e.preventDefault();
207                 $(window).triggerHandler('resize.navbar.dropdown')
208             }
209         });
210     }
211
212     
213     ace.demo.functions.sidebarTooltips = function() {
214         //tooltip in sidebar items
215         $('.sidebar .nav-list .badge[title],.sidebar .nav-list .badge[title]').each(function() {
216             var tooltip_class = $(this).attr('class').match(/tooltip\-(?:\w+)/);
217             tooltip_class = tooltip_class ? tooltip_class[0] : 'tooltip-error';
218             $(this).tooltip({
219                 'placement': function (context, source) {
220                     var offset = $(source).offset();
221
222                     if( parseInt(offset.left) < parseInt(document.body.scrollWidth / 2) ) return 'right';
223                     return 'left';
224                 },
225                 container: 'body',
226                 template: '<div class="tooltip '+tooltip_class+'"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
227             });
228         });
229         
230         //or something like this if items are dynamically inserted
231         /**
232         $('.sidebar').tooltip({
233             'placement': function (context, source) {
234                 var offset = $(source).offset();
235
236                 if( parseInt(offset.left) < parseInt(document.body.scrollWidth / 2) ) return 'right';
237                 return 'left';
238             },
239             selector: '.nav-list .badge[title],.nav-list .label[title]',
240             container: 'body',
241             template: '<div class="tooltip tooltip-error"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
242         });
243         */
244     }
245     
246     
247
248     ace.demo.functions.scrollTopBtn = function() {
249         //the scroll to top button
250         var scroll_btn = $('.btn-scroll-up');
251         if(scroll_btn.length > 0) {
252             var is_visible = false;
253             $(window).on('scroll.scroll_btn', function() {
254                 var scroll = ace.helper.scrollTop();
255                 var h = ace.helper.winHeight();
256                 var body_sH = document.body.scrollHeight;
257                 if(scroll > parseInt(h / 4) || (scroll > 0 && body_sH >= h && h + scroll >= body_sH - 1)) {//|| for smaller pages, when reached end of page
258                     if(!is_visible) {
259                         scroll_btn.addClass('display');
260                         is_visible = true;
261                     }
262                 } else {
263                     if(is_visible) {
264                         scroll_btn.removeClass('display');
265                         is_visible = false;
266                     }
267                 }
268             }).triggerHandler('scroll.scroll_btn');
269
270             scroll_btn.on(ace.click_event, function(){
271                 var duration = Math.min(500, Math.max(100, parseInt(ace.helper.scrollTop() / 3)));
272                 $('html,body').animate({scrollTop: 0}, duration);
273                 return false;
274             });
275         }
276     }
277
278
279     
280     ace.demo.functions.someBrowserFix = function() {
281         //chrome and webkit have a problem here when resizing from 479px to more
282         //we should force them redraw the navbar!
283         if( ace.vars['webkit'] ) {
284             var ace_nav = $('.ace-nav').get(0);
285             if( ace_nav ) $(window).on('resize.webkit_fix' , function(){
286                 ace.helper.redraw(ace_nav);
287             });
288         }
289         
290         
291         //fix an issue with ios safari, when an element is fixed and an input receives focus
292         if(ace.vars['ios_safari']) {
293           $(document).on('ace.settings.ios_fix', function(e, event_name, event_val) {
294             if(event_name != 'navbar_fixed') return;
295
296             $(document).off('focus.ios_fix blur.ios_fix', 'input,textarea,.wysiwyg-editor');
297             if(event_val == true) {
298               $(document).on('focus.ios_fix', 'input,textarea,.wysiwyg-editor', function() {
299                 $(window).on('scroll.ios_fix', function() {
300                     var navbar = $('#navbar').get(0);
301                     if(navbar) ace.helper.redraw(navbar);
302                 });
303               }).on('blur.ios_fix', 'input,textarea,.wysiwyg-editor', function() {
304                 $(window).off('scroll.ios_fix');
305               })
306             }
307           }).triggerHandler('ace.settings.ios_fix', ['navbar_fixed', $('#navbar').css('position') == 'fixed']);
308         }
309     }
310
311     
312     
313     ace.demo.functions.bsCollapseToggle = function() {
314         //bootstrap collapse component icon toggle
315         $(document).on('hide.bs.collapse show.bs.collapse', function (ev) {
316             var panel_id = ev.target.getAttribute('id')
317             var panel = $('a[href*="#'+ panel_id+'"]');
318             if(panel.length == 0) panel = $('a[data-target*="#'+ panel_id+'"]');
319             if(panel.length == 0) return;
320
321             panel.find(ace.vars['.icon']).each(function(){
322                 var $icon = $(this)
323
324                 var $match
325                 var $icon_down = null
326                 var $icon_up = null
327                 if( ($icon_down = $icon.attr('data-icon-show')) ) {
328                     $icon_up = $icon.attr('data-icon-hide')
329                 }
330                 else if( $match = $icon.attr('class').match(/fa\-(.*)\-(up|down)/) ) {
331                     $icon_down = 'fa-'+$match[1]+'-down'
332                     $icon_up = 'fa-'+$match[1]+'-up'
333                 }
334
335                 if($icon_down) {
336                     if(ev.type == 'show') $icon.removeClass($icon_down).addClass($icon_up)
337                         else $icon.removeClass($icon_up).addClass($icon_down)
338                         
339                     return false;//ignore other icons that match, one is enough
340                 }
341
342             });
343         })
344     }
345     
346
347     
348     //in small devices display navbar dropdowns like modal boxes
349     ace.demo.functions.smallDeviceDropdowns = function() {
350       if(ace.vars['old_ie']) return;
351       
352       $(document)
353       .on('shown.bs.dropdown.navbar', '.ace-nav > li.dropdown-modal', function(e) {
354         adjustNavbarDropdown.call(this);
355         var self = this;
356         $(window).on('resize.navbar.dropdown', function() {
357             adjustNavbarDropdown.call(self);
358         })
359       })
360       .on('hidden.bs.dropdown.navbar', '.ace-nav > li.dropdown-modal', function(e) {
361         $(window).off('resize.navbar.dropdown');
362         resetNavbarDropdown.call(this);
363       })
364      
365       function adjustNavbarDropdown() {
366         var $sub = $(this).find('> .dropdown-menu');
367
368         if( $sub.css('position') == 'fixed' ) {
369             var win_width = parseInt($(window).width());
370             var offset_w = win_width > 320 ? 60 : (win_width > 240 ? 40 : 30);
371             var avail_width = parseInt(win_width) - offset_w;
372             var avail_height = parseInt($(window).height()) - 30;
373             
374             var width = parseInt(Math.min(avail_width , 320));
375             //we set 'width' here for text wrappings and spacings to take effect before calculating scrollHeight
376             $sub.css('width', width);
377
378             var tabbed = false;
379             var extra_parts = 0;
380             var dropdown_content = $sub.find('.tab-pane.active .dropdown-content.ace-scroll');
381             if(dropdown_content.length == 0) dropdown_content = $sub.find('.dropdown-content.ace-scroll');
382             else tabbed = true;
383
384             var parent_menu = dropdown_content.closest('.dropdown-menu');
385             var scrollHeight = $sub[0].scrollHeight;
386             if(dropdown_content.length == 1) {
387                 //sometimes there's no scroll-content, for example in detached scrollbars
388                 var content =  dropdown_content.find('.scroll-content')[0];
389                 if(content) {
390                     scrollHeight = content.scrollHeight;
391                 }
392             
393                 extra_parts += parent_menu.find('.dropdown-header').outerHeight();
394                 extra_parts += parent_menu.find('.dropdown-footer').outerHeight();
395                 
396                 var tab_content = parent_menu.closest('.tab-content');
397                 if( tab_content.length != 0 ) {
398                     extra_parts += tab_content.siblings('.nav-tabs').eq(0).height();
399                 }
400             }
401             
402
403             
404             var height = parseInt(Math.min(avail_height , 480, scrollHeight + extra_parts));
405             var left = parseInt(Math.abs((avail_width + offset_w - width)/2));
406             var top = parseInt(Math.abs((avail_height + 30 - height)/2));
407
408             
409             var zindex = parseInt($sub.css('z-index')) || 0;
410
411             $sub.css({'height': height, 'left': left, 'right': 'auto', 'top': top - (!tabbed ? 1 : 3)});
412             if(dropdown_content.length == 1) {
413                 if(!ace.vars['touch']) {
414                     dropdown_content.ace_scroll('update', {size: height - extra_parts}).ace_scroll('enable').ace_scroll('reset');
415                 }
416                 else {
417                     dropdown_content
418                     .ace_scroll('disable').css('max-height', height - extra_parts).addClass('overflow-scroll');
419                 }
420             }
421             $sub.css('height', height + (!tabbed ? 2 : 7));//for bottom border adjustment and tab content paddings
422             
423             
424             if($sub.hasClass('user-menu')) {
425                 $sub.css('height', '');//because of user-info hiding/showing at different widths, which changes above 'scrollHeight', so we remove it!
426                 
427                 //user menu is re-positioned in small widths
428                 //but we need to re-position again in small heights as well (modal mode)
429                 var user_info = $(this).find('.user-info');
430                 if(user_info.length == 1 && user_info.css('position') == 'fixed') {
431                     user_info.css({'left': left, 'right': 'auto', 'top': top, 'width': width - 2, 'max-width': width - 2, 'z-index': zindex + 1});
432                 }
433                 else user_info.css({'left': '', 'right': '', 'top': '', 'width': '', 'max-width': '', 'z-index': ''});
434             }
435             
436             //dropdown's z-index is limited by parent .navbar's z-index (which doesn't make sense because dropdowns are fixed!)
437             //so for example when in 'content-slider' page, fixed modal toggle buttons go above are dropdowns
438             //so we increase navbar's z-index to fix this!
439             $(this).closest('.navbar.navbar-fixed-top').css('z-index', zindex);
440         }
441         else {
442             if($sub.length != 0) resetNavbarDropdown.call(this, $sub);
443         }
444       }
445
446       //reset scrollbars and user menu
447       function resetNavbarDropdown($sub) {
448         $sub = $sub || $(this).find('> .dropdown-menu');
449       
450         if($sub.length > 0) {
451             $sub
452             .css({'width': '', 'height': '', 'left': '', 'right': '', 'top': ''})
453             .find('.dropdown-content').each(function() {
454                 if(ace.vars['touch']) {
455                     $(this).css('max-height', '').removeClass('overflow-scroll');
456                 }
457
458                 var size = parseInt($(this).attr('data-size') || 0) || $.fn.ace_scroll.defaults.size;
459                 $(this).ace_scroll('update', {size: size}).ace_scroll('enable').ace_scroll('reset');
460             })
461             
462             if( $sub.hasClass('user-menu') ) {
463                 var user_info = 
464                 $(this).find('.user-info')
465                 .css({'left': '', 'right': '', 'top': '', 'width': '', 'max-width': '', 'z-index': ''});
466             }
467         }
468         
469         $(this).closest('.navbar').css('z-index', '');
470       }
471     }
472
473 })(jQuery);
474
475
476 //some ace helper functions
477 (function($$ , undefined) {//$$ is ace.helper
478  $$.unCamelCase = function(str) {
479     return str.replace(/([a-z])([A-Z])/g, function(match, c1, c2){ return c1+'-'+c2.toLowerCase() })
480  }
481  $$.strToVal = function(str) {
482     var res = str.match(/^(?:(true)|(false)|(null)|(\-?[\d]+(?:\.[\d]+)?)|(\[.*\]|\{.*\}))$/i);
483
484     var val = str;
485     if(res) {
486         if(res[1]) val = true;
487         else if(res[2]) val = false;
488         else if(res[3]) val = null;    
489         else if(res[4]) val = parseFloat(str);
490         else if(res[5]) {
491             try { val = JSON.parse(str) }
492             catch (err) {}
493         }
494     }
495
496     return val;
497  }
498  $$.getAttrSettings = function(elem, attr_list, prefix) {
499     if(!elem) return;
500     var list_type = attr_list instanceof Array ? 1 : 2;
501     //attr_list can be Array or Object(key/value)
502     var prefix = prefix ? prefix.replace(/([^\-])$/ , '$1-') : '';
503     prefix = 'data-' + prefix;
504
505     var settings = {}
506     for(var li in attr_list) if(attr_list.hasOwnProperty(li)) {
507         var name = list_type == 1 ? attr_list[li] : li;
508         var attr_val, attr_name = $$.unCamelCase(name.replace(/[^A-Za-z0-9]{1,}/g , '-')).toLowerCase()
509
510         if( ! ((attr_val = elem.getAttribute(prefix + attr_name))  ) ) continue;
511         settings[name] = $$.strToVal(attr_val);
512     }
513
514     return settings;
515  }
516
517  $$.scrollTop = function() {
518     return document.scrollTop || document.documentElement.scrollTop || document.body.scrollTop
519  }
520  $$.winHeight = function() {
521     return window.innerHeight || document.documentElement.clientHeight;
522  }
523  $$.redraw = function(elem, force) {
524     if(!elem) return;
525     var saved_val = elem.style['display'];
526     elem.style.display = 'none';
527     elem.offsetHeight;
528     if(force !== true) {
529         elem.style.display = saved_val;
530     }
531     else {
532         //force redraw for example in old IE
533         setTimeout(function() {
534             elem.style.display = saved_val;
535         }, 10);
536     }
537  }
538 })(ace.helper);;/**
539  <b>Load content via Ajax </b>. For more information please refer to documentation #basics/ajax
540 */
541
542 (function($ , undefined) {
543     var ajax_loaded_scripts = {}
544
545     function AceAjax(contentArea, settings) {
546         var $contentArea = $(contentArea);
547         var self = this;
548         $contentArea.attr('data-ajax-content', 'true');
549         
550         //get a list of 'data-*' attributes that override 'defaults' and 'settings'
551         var attrib_values = ace.helper.getAttrSettings(contentArea, $.fn.ace_ajax.defaults);
552         this.settings = $.extend({}, $.fn.ace_ajax.defaults, settings, attrib_values);
553
554
555         var working = false;
556         var $overlay = $();//empty set
557
558         this.force_reload = false;//set jQuery ajax's cache option to 'false' to reload content
559         this.loadUrl = function(hash, cache, manual_trigger) {
560             var url = false;
561             hash = hash.replace(/^(\#\!)?\#/, '');
562             
563             this.force_reload = (cache === false)
564             
565             if(typeof this.settings.content_url === 'function') url = this.settings.content_url(hash);
566             if(typeof url === 'string') this.getUrl(url, hash, manual_trigger);
567         }
568         
569         this.loadAddr = function(url, hash, cache) {
570             this.force_reload = (cache === false);
571             this.getUrl(url, hash, false);
572         }
573
574
575         this.reload = function() {
576             var hash = $.trim(window.location.hash);
577             if(!hash && this.settings.default_url) hash = this.settings.default_url;
578             
579             this.loadUrl(hash, false);
580         }
581         this.post = function(url, data, updateView, extraParams) {
582             var url = url || $.trim(location.href.replace(location.hash,''));
583             if(!url) return;
584             var data = data || {}
585             var updateView = updateView || false;
586             this.getUrl(url, null, false, 'POST', data, updateView, extraParams);
587         }
588         
589         
590         this.getUrl = function(url, hash, manual_trigger, method, data, updateView, extraParams) {
591             if(working) {
592                 return;
593             }
594             
595             var method = method || 'GET';
596             var updateView = (method == 'GET') || (method == 'POST' && updateView == true)
597             var data = data || null;
598         
599             var event
600             $contentArea.trigger(event = $.Event('ajaxloadstart'), {url: url, hash: hash, method: method, data: data})
601             if (event.isDefaultPrevented()) return;
602             
603             self.startLoading();
604             
605             
606             var ajax_params = method == 'GET' ? {'url': url, 'cache': !this.force_reload} : {'url': url, 'method' : 'POST', 'data': data}
607             if(method == 'POST' && typeof extraParams == 'object') ajax_params = $.extend({}, ajax_params, extraParams);
608
609             $.ajax(ajax_params)
610             .error(function() {
611                 $contentArea.trigger('ajaxloaderror', {url: url, hash: hash, method: method, data: data});
612                 
613                 self.stopLoading(true);
614             })
615             .done(function(result) {
616                 $contentArea.trigger('ajaxloaddone', {url: url, hash: hash, method: method, data: data});
617                 if(method == 'POST') {
618                     var event
619                     $contentArea.trigger(event = $.Event('ajaxpostdone', {url: url, data: data, result: result}))
620                     if( event.isDefaultPrevented() ) updateView = false;
621                 }
622                 
623                 
624                 var link_element = null, link_text = '';
625                 if(typeof self.settings.update_active === 'function') {
626                     link_element = self.settings.update_active.call(null, hash, url, method, updateView);
627                 }
628                 else if(self.settings.update_active === true && hash) {
629                     link_element = $('a[data-url="'+hash+'"]');
630                     if(link_element.length > 0) {
631                         var nav = link_element.closest('.nav');
632                         if(nav.length > 0) {
633                             nav.find('.active').each(function(){
634                                 var $class = 'active';
635                                 if( $(this).hasClass('hover') || self.settings.close_active ) $class += ' open';
636                                 
637                                 $(this).removeClass($class);                            
638                                 if(self.settings.close_active) {
639                                     $(this).find(' > .submenu').css('display', '');
640                                 }
641                             })
642                             
643                             var active_li = link_element.closest('li').addClass('active').parents('.nav li').addClass('active open');
644                             nav.closest('.sidebar[data-sidebar-scroll=true]').each(function() {
645                                 var $this = $(this);
646                                 $this.ace_sidebar_scroll('reset');
647                                 if(manual_trigger == true) $this.ace_sidebar_scroll('scroll_to_active');//first time only
648                             })
649                         }
650                     }
651                 }
652
653                 /////////
654                 if(typeof self.settings.update_breadcrumbs === 'function') {
655                     link_text = self.settings.update_breadcrumbs.call(null, hash, url, link_element, method, updateView);
656                 }
657                 else if(self.settings.update_breadcrumbs === true && link_element != null && link_element.length > 0) {
658                     link_text = updateBreadcrumbs(link_element);
659                 }
660                 /////////
661                 
662                 $overlay.addClass('content-loaded').detach();
663                 if(updateView) {
664                     //convert "title" and "link" tags to "div" tags for later processing
665                     result = String(result)
666                         .replace(/<(title|link)([\s\>])/gi,'<div class="hidden ajax-append-$1"$2')
667                         .replace(/<\/(title|link)\>/gi,'</div>')
668                     $contentArea.empty().html(result);
669                 }
670                 
671                 $(self.settings.loading_overlay || $contentArea).append($overlay);
672
673
674
675                 //remove previous stylesheets inserted via ajax
676                 if(updateView) setTimeout(function() {
677                     $('head').find('link.ace-ajax-stylesheet').remove();
678
679                     var main_selectors = ['link.ace-main-stylesheet', 'link#main-ace-style', 'link[href*="/ace.min.css"]', 'link[href*="/ace.css"]']
680                     var ace_style = [];
681                     for(var m = 0; m < main_selectors.length; m++) {
682                         ace_style = $('head').find(main_selectors[m]).first();
683                         if(ace_style.length > 0) break;
684                     }
685                     
686                     $contentArea.find('.ajax-append-link').each(function(e) {
687                         var $link = $(this);
688                         if ( $link.attr('href') ) {
689                             var new_link = jQuery('<link />', {type : 'text/css', rel: 'stylesheet', 'class': 'ace-ajax-stylesheet'})
690                             if( ace_style.length > 0 ) new_link.insertBefore(ace_style);
691                             else new_link.appendTo('head');
692                             new_link.attr('href', $link.attr('href'));//we set "href" after insertion, for IE to work
693                         }
694                         $link.remove();
695                     })
696                 }, 10);
697
698                 //////////////////////
699
700                 if(typeof self.settings.update_title === 'function') {
701                     self.settings.update_title.call(null, hash, url, link_text, method, updateView);
702                 }
703                 else if(self.settings.update_title === true && method == 'GET') {
704                     updateTitle(link_text);
705                 }
706
707                 if( !manual_trigger && updateView ) {
708                     $('html,body').animate({scrollTop: 0}, 250);
709                 }
710
711                 //////////////////////
712                 $contentArea.trigger('ajaxloadcomplete', {url: url, hash: hash, method: method, data:data});
713                 //////////////////////
714                 
715                 
716                 //if result contains call to "loadScripts" then don't stopLoading now
717                 var re = /\.(?:\s*)ace(?:_a|A)jax(?:\s*)\((?:\s*)(?:\'|\")loadScripts(?:\'|\")/;
718                 if(result.match(re)) self.stopLoading();
719                 else self.stopLoading(true);
720             })
721         }
722         
723         
724         ///////////////////////
725         var fixPos = false;
726         var loadTimer = null;
727         this.startLoading = function() {
728             if(working) return;
729             working = true;
730             
731             if(!this.settings.loading_overlay && $contentArea.css('position') == 'static') {
732                 $contentArea.css('position', 'relative');//for correct icon positioning
733                 fixPos = true;
734             }
735                 
736             $overlay.remove();
737             $overlay = $('<div class="ajax-loading-overlay"><i class="ajax-loading-icon '+(this.settings.loading_icon || '')+'"></i> '+this.settings.loading_text+'</div>')
738
739             if(this.settings.loading_overlay == 'body') $('body').append($overlay.addClass('ajax-overlay-body'));
740             else if(this.settings.loading_overlay) $(this.settings.loading_overlay).append($overlay);
741             else $contentArea.append($overlay);
742
743             
744             if(this.settings.max_load_wait !== false) 
745              loadTimer = setTimeout(function() {
746                 loadTimer = null;
747                 if(!working) return;
748                 
749                 var event
750                 $contentArea.trigger(event = $.Event('ajaxloadlong'))
751                 if (event.isDefaultPrevented()) return;
752                 
753                 self.stopLoading(true);
754              }, this.settings.max_load_wait * 1000);
755         }
756         
757         this.stopLoading = function(stopNow) {
758             if(stopNow === true) {
759                 working = false;
760                 
761                 $overlay.remove();
762                 if(fixPos) {
763                     $contentArea.css('position', '');//restore previous 'position' value
764                     fixPos = false;
765                 }
766                 
767                 if(loadTimer != null) {
768                     clearTimeout(loadTimer);
769                     loadTimer = null;
770                 }
771             }
772             else {
773                 $overlay.addClass('almost-loaded');
774                 
775                 $contentArea.one('ajaxscriptsloaded.inner_call', function() {
776                     self.stopLoading(true);
777                     /**
778                     if(window.Pace && Pace.running == true) {
779                         Pace.off('done');
780                         Pace.once('done', function() { self.stopLoading(true) })
781                     }
782                     else self.stopLoading(true);
783                     */
784                 })
785             }
786         }
787         
788         this.working = function() {
789             return working;
790         }
791         ///////////////////////
792         
793         
794         
795         function updateBreadcrumbs(link_element) {
796             var link_text = '';
797          
798             //update breadcrumbs
799             var breadcrumbs = $('.breadcrumb');
800             if(breadcrumbs.length > 0 && breadcrumbs.is(':visible')) {
801                 breadcrumbs.find('> li:not(:first-child)').remove();
802
803                 var i = 0;        
804                 link_element.parents('.nav li').each(function() {
805                     var link = $(this).find('> a');
806                     
807                     var link_clone = link.clone();
808                     link_clone.find('i,.fa,.glyphicon,.ace-icon,.menu-icon,.badge,.label').remove();
809                     var text = link_clone.text();
810                     link_clone.remove();
811                     
812                     var href = link.attr('href');
813
814                     if(i == 0) {
815                         var li = $('<li class="active"></li>').appendTo(breadcrumbs);
816                         li.text(text);
817                         link_text = text;
818                     }
819                     else {
820                         var li = $('<li><a /></li>').insertAfter(breadcrumbs.find('> li:first-child'));
821                         li.find('a').attr('href', href).text(text);
822                     }
823                     i++;
824                 })
825             }
826             
827             return link_text;
828          }
829          
830          function updateTitle(link_text) {
831             var $title = $contentArea.find('.ajax-append-title');
832             if($title.length > 0) {
833                 document.title = $title.text();
834                 $title.remove();
835             }
836             else if(link_text.length > 0) {
837                 var extra = $.trim(String(document.title).replace(/^(.*)[\-]/, ''));//for example like " - Ace Admin"
838                 if(extra) extra = ' - ' + extra;
839                 link_text = $.trim(link_text) + extra;
840             }
841          }
842          
843          
844          this.loadScripts = function(scripts, callback) {
845             var scripts = scripts || [];
846             $.ajaxPrefilter('script', function(opts) {opts.cache = true});
847             setTimeout(function() {
848                 //let's keep a list of loaded scripts so that we don't load them more than once!
849                 
850                 function finishLoading() {
851                     if(typeof callback === 'function') callback();
852                     $('.btn-group[data-toggle="buttons"] > .btn').button();
853                     
854                     $contentArea.trigger('ajaxscriptsloaded');
855                 }
856                 
857                 //var deferreds = [];
858                 var deferred_count = 0;//deferreds count
859                 var resolved = 0;
860                 for(var i = 0; i < scripts.length; i++) if(scripts[i]) {
861                     (function() {
862                         var script_name = "js-"+scripts[i].replace(/[^\w\d\-]/g, '-').replace(/\-\-/g, '-');
863                         if( ajax_loaded_scripts[script_name] !== true )    deferred_count++;
864                     })()
865                 }
866                 
867
868                 function nextScript(index) {
869                     index += 1;
870                     if(index < scripts.length) loadScript(index);
871                     else {
872                         finishLoading();
873                     }
874                 }
875                 
876                 function loadScript(index) {
877                     index = index || 0;
878                     if(!scripts[index]) {//could be null sometimes
879                         return nextScript(index);
880                     }
881                 
882                     var script_name = "js-"+scripts[index].replace(/[^\w\d\-]/g, '-').replace(/\-\-/g, '-');
883                     //only load scripts that are not loaded yet!
884                     if( ajax_loaded_scripts[script_name] !== true ) {
885                         $.getScript(scripts[index])
886                         .done(function() {
887                             ajax_loaded_scripts[script_name] = true;
888                         })
889                         //.fail(function() {
890                         //})
891                         .complete(function() {
892                             resolved++;
893                             if(resolved >= deferred_count && working) {
894                                 finishLoading();
895                             }
896                             else {
897                                 nextScript(index);
898                             }
899                         })
900                     }
901                     else {//script previoisly loaded
902                         nextScript(index);
903                     }
904                 }
905                 
906                 
907                 if (deferred_count > 0) {
908                     loadScript();
909                 }
910                 else {
911                     finishLoading();
912                 }
913
914             }, 10)
915         }
916         
917         
918         
919         /////////////////
920         $(window)
921         .off('hashchange.ace_ajax')
922         .on('hashchange.ace_ajax', function(e, manual_trigger) {
923             var hash = $.trim(window.location.hash);
924             if(!hash || hash.length == 0) return;
925             
926             if(self.settings.close_mobile_menu) {
927                 try {$(self.settings.close_mobile_menu).ace_sidebar('mobileHide')} catch(e){}
928             }
929             if(self.settings.close_dropdowns) {
930                 $('.dropdown.open .dropdown-toggle').dropdown('toggle');
931             }
932             
933             self.loadUrl(hash, null, manual_trigger);
934         }).trigger('hashchange.ace_ajax', [true]);
935         
936         var hash = $.trim(window.location.hash);
937         if(!hash && this.settings.default_url) window.location.hash = this.settings.default_url;
938
939     }//AceAjax
940
941
942
943     $.fn.aceAjax = $.fn.ace_ajax = function (option, value, value2, value3, value4) {
944         var method_call;
945
946         var $set = this.each(function () {
947             var $this = $(this);
948             var data = $this.data('ace_ajax');
949             var options = typeof option === 'object' && option;
950
951             if (!data) $this.data('ace_ajax', (data = new AceAjax(this, options)));
952             if (typeof option === 'string' && typeof data[option] === 'function') {
953                 if(value4 !== undefined) method_call = data[option](value, value2, value3, value4);
954                 else if(value3 !== undefined) method_call = data[option](value, value2, value3);
955                 else if(value2 !== undefined) method_call = data[option](value, value2);
956                 else method_call = data[option](value);
957             }
958         });
959
960         return (method_call === undefined) ? $set : method_call;
961     }
962     
963     
964     
965     $.fn.aceAjax.defaults = $.fn.ace_ajax.defaults = {
966         content_url: false,
967         default_url: false,
968         loading_icon: 'fa fa-spin fa-spinner fa-2x orange',
969         loading_text: '',
970         loading_overlay: null,
971         update_breadcrumbs: true,
972         update_title: true,
973         update_active: true,
974         close_active: false,
975         max_load_wait: false,
976         close_mobile_menu: false,
977         close_dropdowns: false
978      }
979
980 })(window.jQuery);
981
982 ;/**
983  <b>Custom drag event for touch devices</b> used in scrollbars.
984  For better touch event handling and extra options a more advanced solution such as <u>Hammer.js</u> is recommended.
985 */
986
987 //based on but not dependent on jQuery mobile
988 /*
989 * jQuery Mobile v1.3.2
990 * http://jquerymobile.com
991 *
992 * Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors
993 * Released under the MIT license.
994 * http://jquery.org/license
995 *
996 */
997 (function($ , undefined) {
998
999     if(!ace.vars['touch']) return;
1000
1001     var touchStartEvent = "touchstart MSPointerDown pointerdown",// : "mousedown",
1002             touchStopEvent  =  "touchend touchcancel MSPointerUp MSPointerCancel pointerup pointercancel",// : "mouseup",
1003             touchMoveEvent  =  "touchmove MSPointerMove MSPointerHover pointermove";// : "mousemove";
1004
1005
1006     $.event.special.ace_drag = {
1007         setup: function() {
1008             var min_threshold = 0;
1009         
1010             var $this = $(this);
1011             $this.on(touchStartEvent, function(event) {        
1012                 var data = event.originalEvent.touches ?
1013                     event.originalEvent.touches[ 0 ] :
1014                     event,
1015                     start = {
1016                         //time: Date.now(),
1017                         coords: [ data.pageX, data.pageY ],
1018                         origin: $(event.target)
1019                     },
1020                     stop;
1021                     //start.origin.trigger({'type' : 'ace_dragStart', 'start':(start || [-1,-1])});
1022                     
1023                     var direction = false, dx = 0, dy = 0;
1024
1025                 function moveHandler(event) {
1026                     if (!start) {
1027                         return;
1028                     }
1029                     var data = event.originalEvent.touches ?
1030                             event.originalEvent.touches[ 0 ] :
1031                             event;
1032                     stop = {
1033                         coords: [ data.pageX, data.pageY ]
1034                     };
1035                     
1036                     // prevent scrolling
1037                     //if ( Math.abs(start.coords[1] - stop.coords[1]) > 0 || Math.abs(start.coords[0] - stop.coords[01]) > 0 ) {
1038                         //event.preventDefault();
1039                     //}
1040
1041
1042                     if (start && stop) {
1043                         dx = 0;
1044                         dy = 0;
1045
1046                         direction = 
1047                             (
1048                              Math.abs(dy = start.coords[ 1 ] - stop.coords[ 1 ]) > min_threshold
1049                                 && 
1050                              Math.abs(dx = start.coords[ 0 ] - stop.coords[ 0 ]) <= Math.abs(dy)
1051                             )
1052                             ? 
1053                             (dy > 0 ? 'up' : 'down')
1054                             :
1055                             (
1056                              Math.abs(dx = start.coords[ 0 ] - stop.coords[ 0 ]) > min_threshold
1057                                 && 
1058                              Math.abs( dy ) <= Math.abs(dx)
1059                             )
1060                             ?
1061                             (dx > 0 ? 'left' : 'right')
1062                             :
1063                             false;
1064                             
1065
1066                             if( direction !== false ) {
1067                              var retval = {cancel: false}
1068                              start.origin.trigger({
1069                                 'type': 'ace_drag',
1070                                 //'start': start.coords,
1071                                 //'stop': stop.coords,
1072                                 'direction': direction,
1073                                 'dx': dx,
1074                                 'dy': dy,
1075                                 'retval': retval
1076                              })
1077
1078                                // prevent document scrolling unless retval.cancel == true
1079                               if( retval.cancel == false ) event.preventDefault();
1080                             }
1081                     }
1082                     start.coords[0] = stop.coords[0];
1083                     start.coords[1] = stop.coords[1];
1084                 }
1085
1086                 $this
1087                 .on(touchMoveEvent, moveHandler)
1088                 .one(touchStopEvent, function(event) {
1089                     $this.off(touchMoveEvent, moveHandler);
1090                     //start.origin.trigger({'type' : 'ace_dragEnd', 'stop':(stop || [-1,-1])});
1091                     
1092                     start = stop = undefined;
1093                 
1094                 });
1095             });
1096         }
1097     }
1098
1099 })(window.jQuery);;/**
1100  <b>Sidebar functions</b>. Collapsing/expanding, toggling mobile view menu and other sidebar functions.
1101 */
1102
1103 (function($ , undefined) {
1104     var sidebar_count = 0;
1105
1106     function Sidebar(sidebar, settings) {
1107         var self = this;
1108         this.$sidebar = $(sidebar);
1109         this.$sidebar.attr('data-sidebar', 'true');
1110         if( !this.$sidebar.attr('id') ) this.$sidebar.attr( 'id' , 'id-sidebar-'+(++sidebar_count) )
1111
1112         
1113         //get a list of 'data-*' attributes that override 'defaults' and 'settings'
1114         var attrib_values = ace.helper.getAttrSettings(sidebar, $.fn.ace_sidebar.defaults, 'sidebar-');
1115         this.settings = $.extend({}, $.fn.ace_sidebar.defaults, settings, attrib_values);
1116
1117
1118         //some vars
1119         this.minimized = false;//will be initialized later
1120         this.collapsible = false;//...
1121         this.horizontal = false;//...
1122         this.mobile_view = false;//
1123
1124
1125         //return an array containing sidebar state variables
1126         this.vars = function() {
1127             return {'minimized': this.minimized, 'collapsible': this.collapsible, 'horizontal': this.horizontal, 'mobile_view': this.mobile_view}
1128         }
1129         this.get = function(name) {
1130             if(this.hasOwnProperty(name)) return this[name];
1131         }
1132         this.set = function(name, value) {
1133             if(this.hasOwnProperty(name)) this[name] = value;
1134         }
1135         
1136
1137         //return a reference to self (sidebar instance)
1138         this.ref = function() {
1139             return this;
1140         }
1141
1142         
1143         //toggle icon for sidebar collapse/expand button
1144         var toggleIcon = function(minimized, save) {
1145             var icon = $(this).find(ace.vars['.icon']), icon1, icon2;
1146             if(icon.length > 0) {
1147                 icon1 = icon.attr('data-icon1');//the icon for expanded state
1148                 icon2 = icon.attr('data-icon2');//the icon for collapsed state
1149
1150                 if(typeof minimized !== "undefined") {
1151                     if(minimized) icon.removeClass(icon1).addClass(icon2);
1152                     else icon.removeClass(icon2).addClass(icon1);
1153                 }
1154                 else {
1155                     icon.toggleClass(icon1).toggleClass(icon2);
1156                 }
1157                 
1158                 try {
1159                     if(save !== false) ace.settings.saveState(icon.get(0));
1160                 } catch(e) {}
1161             }
1162         }
1163         
1164         //if not specified, find the toggle button related to this sidebar
1165         var findToggleBtn = function() {
1166             var toggle_btn = self.$sidebar.find('.sidebar-collapse');
1167             if(toggle_btn.length == 0) toggle_btn = $('.sidebar-collapse[data-target="#'+(self.$sidebar.attr('id')||'')+'"]');
1168             if(toggle_btn.length != 0) toggle_btn = toggle_btn[0];
1169             else toggle_btn = null;
1170             
1171             return toggle_btn;
1172         }
1173         
1174         
1175         //collapse/expand sidebar
1176         this.toggleMenu = function(toggle_btn, save) {
1177             if(this.collapsible) return;
1178
1179             this.minimized = !this.minimized;
1180             var save = !(toggle_btn === false || save === false);
1181             
1182         
1183             if(this.minimized) this.$sidebar.addClass('menu-min');
1184             else this.$sidebar.removeClass('menu-min');
1185
1186             try {
1187                 if(save) ace.settings.saveState(sidebar, 'class', 'menu-min', this.minimized);
1188             } catch(e) {}
1189         
1190             if( !toggle_btn ) {
1191                 toggle_btn = findToggleBtn();
1192             }
1193             if(toggle_btn) {
1194                 toggleIcon.call(toggle_btn, this.minimized, save);
1195             }
1196
1197             //force redraw for ie8
1198             if(ace.vars['old_ie']) ace.helper.redraw(sidebar);
1199             
1200             
1201             $(document).trigger('settings.ace', ['sidebar_collapsed' , this.minimized, sidebar, save]);
1202         }
1203         this.collapse = function(toggle_btn, save) {
1204             if(this.collapsible) return;
1205             this.minimized = false;
1206             
1207             this.toggleMenu(toggle_btn, save);
1208         }
1209         this.expand = function(toggle_btn, save) {
1210             if(this.collapsible) return;
1211             this.minimized = true;
1212             
1213             this.toggleMenu(toggle_btn, save);
1214         }
1215         
1216
1217         
1218         this.showResponsive = function() {
1219             this.$sidebar.removeClass(responsive_min_class).removeClass(responsive_max_class);
1220         }
1221         
1222         //collapse/expand in 2nd mobile style
1223         this.toggleResponsive = function(toggle_btn, showMenu) {
1224             if( !this.mobile_view || this.mobile_style != 3 ) return;
1225         
1226             if( this.$sidebar.hasClass('menu-min') ) {
1227                 //remove menu-min because it interferes with responsive-max
1228                 this.$sidebar.removeClass('menu-min');
1229                 var btn = findToggleBtn();
1230                 if(btn) toggleIcon.call(btn);
1231             }
1232
1233
1234             var showMenu = typeof showMenu !== 'undefined' ? showMenu : this.$sidebar.hasClass(responsive_min_class);
1235             if(showMenu) {
1236                 this.$sidebar.addClass(responsive_max_class).removeClass(responsive_min_class);
1237             }
1238             else {
1239                 this.$sidebar.removeClass(responsive_max_class).addClass(responsive_min_class);
1240             }
1241             this.minimized = !showMenu;
1242
1243
1244             if( !toggle_btn ) {
1245                 toggle_btn = this.$sidebar.find('.sidebar-expand');
1246                 if(toggle_btn.length == 0) toggle_btn = $('.sidebar-expand[data-target="#'+(this.$sidebar.attr('id')||'')+'"]');
1247                 if(toggle_btn.length != 0) toggle_btn = toggle_btn[0];
1248                 else toggle_btn = null;
1249             }
1250             
1251             if(toggle_btn) {
1252                 var icon = $(toggle_btn).find(ace.vars['.icon']), icon1, icon2;
1253                 if(icon.length > 0) {
1254                     icon1 = icon.attr('data-icon1');//the icon for expanded state
1255                     icon2 = icon.attr('data-icon2');//the icon for collapsed state
1256
1257                     if(!showMenu) icon.removeClass(icon2).addClass(icon1);
1258                     else icon.removeClass(icon1).addClass(icon2);
1259                 }
1260             }
1261
1262             $(document).triggerHandler('settings.ace', ['sidebar_collapsed' , this.minimized]);
1263         }
1264         
1265         
1266         //some helper functions
1267         
1268         //determine if we have 4th mobile style responsive sidebar and we are in mobile view
1269         this.is_collapsible = function() {
1270             var toggle
1271             return (this.$sidebar.hasClass('navbar-collapse'))
1272             && ((toggle = $('.navbar-toggle[data-target="#'+(this.$sidebar.attr('id')||'')+'"]').get(0)) != null)
1273             &&  toggle.scrollHeight > 0
1274             //sidebar is collapsible and collapse button is visible?
1275         }
1276         //determine if we are in mobile view
1277         this.is_mobile_view = function() {
1278             var toggle
1279             return ((toggle = $('.menu-toggler[data-target="#'+(this.$sidebar.attr('id')||'')+'"]').get(0)) != null)
1280             &&  toggle.scrollHeight > 0
1281         }
1282
1283
1284         //toggling (show/hide) submenu elements
1285         this.$sidebar.on(ace.click_event+'.ace.submenu', '.nav-list', function (ev) {
1286             var nav_list = this;
1287
1288             //check to see if we have clicked on an element which is inside a .dropdown-toggle element?!
1289             //if so, it means we should toggle a submenu
1290             var link_element = $(ev.target).closest('a');
1291             if(!link_element || link_element.length == 0) return;//return if not clicked inside a link element
1292
1293             var minimized  = self.minimized && !self.collapsible;
1294             //if .sidebar is .navbar-collapse and in small device mode, then let minimized be uneffective
1295     
1296             if( !link_element.hasClass('dropdown-toggle') ) {//it doesn't have a submenu return
1297                 //just one thing before we return
1298                 //if sidebar is collapsed(minimized) and we click on a first level menu item
1299                 //and the click is on the icon, not on the menu text then let's cancel event and cancel navigation
1300                 //Good for touch devices, that when the icon is tapped to see the menu text, navigation is cancelled
1301                 //navigation is only done when menu text is tapped
1302
1303                 if( ace.click_event == 'tap'
1304                     &&
1305                     minimized
1306                     &&
1307                     link_element.get(0).parentNode.parentNode == nav_list )//only level-1 links
1308                 {
1309                     var text = link_element.find('.menu-text').get(0);
1310                     if( text != null && ev.target != text && !$.contains(text , ev.target) ) {//not clicking on the text or its children
1311                         ev.preventDefault();
1312                         return false;
1313                     }
1314                 }
1315
1316
1317                 //ios safari only has a bit of a problem not navigating to link address when scrolling down
1318                 //specify data-link attribute to ignore this
1319                 if(ace.vars['ios_safari'] && link_element.attr('data-link') !== 'false') {
1320                     //only ios safari has a bit of a problem not navigating to link address when scrolling down
1321                     //please see issues section in documentation
1322                     document.location = link_element.attr('href');
1323                     ev.preventDefault();
1324                     return false;
1325                 }
1326
1327                 return;
1328             }
1329             
1330             ev.preventDefault();
1331             
1332             
1333
1334
1335             var sub = link_element.siblings('.submenu').get(0);
1336             if(!sub) return false;
1337             var $sub = $(sub);
1338
1339             var height_change = 0;//the amount of height change in .nav-list
1340
1341             var parent_ul = sub.parentNode.parentNode;
1342             if
1343             (
1344                 ( minimized && parent_ul == nav_list )
1345                  || 
1346                 ( ( $sub.parent().hasClass('hover') && $sub.css('position') == 'absolute' ) && !self.collapsible )
1347             )
1348             {
1349                 return false;
1350             }
1351
1352             
1353             var sub_hidden = (sub.scrollHeight == 0)
1354
1355             //if not open and visible, let's open it and make it visible
1356             if( sub_hidden && self.settings.hide_open_subs ) {//being shown now
1357               $(parent_ul).find('> .open > .submenu').each(function() {
1358                 //close all other open submenus except for the active one
1359                 if(this != sub && !$(this.parentNode).hasClass('active')) {
1360                     height_change -= this.scrollHeight;
1361                     self.hide(this, self.settings.duration, false);
1362                 }
1363               })
1364             }
1365
1366             if( sub_hidden ) {//being shown now
1367                 self.show(sub, self.settings.duration);
1368                 //if a submenu is being shown and another one previously started to hide, then we may need to update/hide scrollbars
1369                 //but if no previous submenu is being hidden, then no need to check if we need to hide the scrollbars in advance
1370                 if(height_change != 0) height_change += sub.scrollHeight;//we need new updated 'scrollHeight' here
1371             } else {
1372                 self.hide(sub, self.settings.duration);
1373                 height_change -= sub.scrollHeight;
1374                 //== -1 means submenu is being hidden
1375             }
1376
1377             //hide scrollbars if content is going to be small enough that scrollbars is not needed anymore
1378             //do this almost before submenu hiding begins
1379             //but when minimized submenu's toggle should have no effect
1380             if (height_change != 0) {
1381                 if(self.$sidebar.attr('data-sidebar-scroll') == 'true' && !self.minimized) 
1382                     self.$sidebar.ace_sidebar_scroll('prehide', height_change)
1383             }
1384
1385             return false;
1386         })
1387
1388         var submenu_working = false;
1389         this.show = function(sub, $duration, shouldWait) {
1390             //'shouldWait' indicates whether to wait for previous transition (submenu toggle) to be complete or not?
1391             shouldWait = (shouldWait !== false);
1392             if(shouldWait && submenu_working) return false;
1393                     
1394             var $sub = $(sub);
1395             var event;
1396             $sub.trigger(event = $.Event('show.ace.submenu'))
1397             if (event.isDefaultPrevented()) {
1398                 return false;
1399             }
1400             
1401             if(shouldWait) submenu_working = true;
1402
1403
1404             $duration = typeof $duration !== 'undefined' ? $duration : this.settings.duration;
1405             
1406             $sub.css({
1407                 height: 0,
1408                 overflow: 'hidden',
1409                 display: 'block'
1410             })
1411             .removeClass('nav-hide').addClass('nav-show')//only for window < @grid-float-breakpoint and .navbar-collapse.menu-min
1412             .parent().addClass('open');
1413             
1414             sub.scrollTop = 0;//this is for submenu_hover when sidebar is minimized and a submenu is scrollTop'ed using scrollbars ...
1415
1416             
1417             var complete = function(ev, trigger) {
1418                 ev && ev.stopPropagation();
1419                 $sub
1420                 .css({'transition-property': '', 'transition-duration': '', overflow:'', height: ''})
1421                 //if(ace.vars['webkit']) ace.helper.redraw(sub);//little Chrome issue, force redraw ;)
1422
1423                 if(trigger !== false) $sub.trigger($.Event('shown.ace.submenu'))
1424                 
1425                 if(shouldWait) submenu_working = false;
1426             }
1427             
1428             
1429             var finalHeight = sub.scrollHeight;
1430
1431             if($duration == 0 || finalHeight == 0 || !$.support.transition.end) {
1432                 //(if duration is zero || element is hidden (scrollHeight == 0) || CSS3 transitions are not available)
1433                 complete();
1434             }
1435             else {
1436                 $sub
1437                 .css({
1438                      'height': finalHeight,
1439                      'transition-property': 'height',
1440                      'transition-duration': ($duration/1000)+'s'
1441                     }
1442                 )
1443                 .one($.support.transition.end, complete);
1444                 
1445                 //there is sometimes a glitch, so maybe retry
1446                 if(ace.vars['android'] ) {
1447                     setTimeout(function() {
1448                         complete(null, false);
1449                         ace.helper.redraw(sub);
1450                     }, $duration + 20);
1451                 }
1452             }
1453
1454             return true;
1455          }
1456          
1457          
1458          this.hide = function(sub, $duration, shouldWait) {
1459             //'shouldWait' indicates whether to wait for previous transition (submenu toggle) to be complete or not?
1460             shouldWait = (shouldWait !== false);
1461             if(shouldWait && submenu_working) return false;
1462          
1463             
1464             var $sub = $(sub);
1465             var event;
1466             $sub.trigger(event = $.Event('hide.ace.submenu'))
1467             if (event.isDefaultPrevented()) {
1468                 return false;
1469             }
1470             
1471             if(shouldWait) submenu_working = true;
1472             
1473
1474             $duration = typeof $duration !== 'undefined' ? $duration : this.settings.duration;
1475             
1476             
1477             var initialHeight = sub.scrollHeight;
1478             $sub.css({
1479                 height: initialHeight,
1480                 overflow: 'hidden',
1481                 display: 'block'
1482             })
1483             .parent().removeClass('open');
1484
1485             sub.offsetHeight;
1486             //forces the "sub" to re-consider the new 'height' before transition
1487
1488             
1489             var complete = function(ev, trigger) {
1490                 ev && ev.stopPropagation();
1491                 $sub
1492                 .css({display: 'none', overflow:'', height: '', 'transition-property': '', 'transition-duration': ''})
1493                 .removeClass('nav-show').addClass('nav-hide')//only for window < @grid-float-breakpoint and .navbar-collapse.menu-min
1494
1495                 if(trigger !== false) $sub.trigger($.Event('hidden.ace.submenu'))
1496                 
1497                 if(shouldWait) submenu_working = false;
1498             }
1499             
1500             
1501             if( $duration == 0 || initialHeight == 0 || !$.support.transition.end) {
1502                 //(if duration is zero || element is hidden (scrollHeight == 0) || CSS3 transitions are not available)
1503                 complete();
1504             }
1505             else {
1506                 $sub
1507                 .css({
1508                      'height': 0,
1509                      'transition-property': 'height',
1510                      'transition-duration': ($duration/1000)+'s'
1511                     }
1512                 )
1513                 .one($.support.transition.end, complete);
1514                 
1515                 //there is sometimes a glitch, so maybe retry
1516                 if(ace.vars['android'] ) {
1517                     setTimeout(function() {
1518                         complete(null, false);
1519                         ace.helper.redraw(sub);
1520                     }, $duration + 20);
1521                 }
1522             }
1523
1524             return true;
1525          }
1526
1527          this.toggle = function(sub, $duration) {
1528             $duration = $duration || self.settings.duration;
1529          
1530             if( sub.scrollHeight == 0 ) {//if an element is hidden scrollHeight becomes 0
1531                 if( this.show(sub, $duration) ) return 1;
1532             } else {
1533                 if( this.hide(sub, $duration) ) return -1;
1534             }
1535             return 0;
1536          }
1537
1538
1539         //sidebar vars
1540         var minimized_menu_class  = 'menu-min';
1541         var responsive_min_class  = 'responsive-min';
1542         var responsive_max_class  = 'responsive-max';
1543         var horizontal_menu_class = 'h-sidebar';
1544
1545         var sidebar_mobile_style = function() {
1546             //differnet mobile menu styles
1547             this.mobile_style = 1;//default responsive mode with toggle button inside navbar
1548             if(this.$sidebar.hasClass('responsive') && !$('.menu-toggler[data-target="#'+this.$sidebar.attr('id')+'"]').hasClass('navbar-toggle')) this.mobile_style = 2;//toggle button behind sidebar
1549              else if(this.$sidebar.hasClass(responsive_min_class)) this.mobile_style = 3;//minimized menu
1550               else if(this.$sidebar.hasClass('navbar-collapse')) this.mobile_style = 4;//collapsible (bootstrap style)
1551         }
1552         sidebar_mobile_style.call(self);
1553           
1554         function update_vars() {
1555             this.mobile_view = this.mobile_style < 4 && this.is_mobile_view();
1556             this.collapsible = !this.mobile_view && this.is_collapsible();
1557
1558             this.minimized = 
1559             (!this.collapsible && this.$sidebar.hasClass(minimized_menu_class))
1560              ||
1561             (this.mobile_style == 3 && this.mobile_view && this.$sidebar.hasClass(responsive_min_class))
1562
1563             this.horizontal = !(this.mobile_view || this.collapsible) && this.$sidebar.hasClass(horizontal_menu_class)
1564         }
1565
1566         //update some basic variables
1567         $(window).on('resize.sidebar.vars' , function(){
1568             update_vars.call(self);
1569         }).triggerHandler('resize.sidebar.vars')
1570         
1571         
1572         
1573         
1574         
1575         this.mobileToggle = function(showMenu) {
1576             var showMenu = typeof showMenu === "undefined" ? undefined : showMenu;
1577             
1578             if(this.mobile_view) {
1579                 if(this.mobile_style == 1 || this.mobile_style == 2) {
1580                     this.toggleMobile(null, showMenu);
1581                 }
1582                 else if(this.mobile_style == 3) {
1583                     this.toggleResponsive(null, showMenu);
1584                 }
1585             }
1586             else if(this.collapsible) {
1587                 this.toggleCollapsible(null, showMenu);
1588             }
1589         }
1590         this.mobileShow = function() {
1591             this.mobileToggle(true);
1592         }
1593         this.mobileHide = function() {
1594             this.mobileToggle(false);
1595         }
1596         
1597         
1598         
1599         this.toggleMobile = function(toggle_btn, showMenu) {
1600             if(!(this.mobile_style == 1 || this.mobile_style == 2)) return;
1601             
1602             var showMenu = typeof showMenu !== 'undefined' ? showMenu : !this.$sidebar.hasClass('display');
1603             if(!toggle_btn) {
1604                 toggle_btn = $('.menu-toggler[data-target="#'+(this.$sidebar.attr('id')||'')+'"]');
1605                 if(toggle_btn.length != 0) toggle_btn = toggle_btn[0];
1606                 else toggle_btn = null;
1607             }
1608             if(showMenu) {
1609                 this.$sidebar.addClass('display');
1610                 if(toggle_btn) $(toggle_btn).addClass('display');
1611             }
1612             else {
1613                 this.$sidebar.removeClass('display');
1614                 if(toggle_btn) $(toggle_btn).removeClass('display');
1615             }
1616         }
1617         
1618         
1619         this.toggleCollapsible = function(toggle_btn, showMenu) {
1620             if(this.mobile_style != 4) return;
1621             
1622             var showMenu = typeof showMenu !== 'undefined' ? showMenu : !this.$sidebar.hasClass('in');
1623             if(showMenu) {
1624                 this.$sidebar.collapse('show');
1625             }
1626             else {
1627                 this.$sidebar.removeClass('display');
1628                 this.$sidebar.collapse('hide');
1629             }    
1630         }
1631
1632     }//end of Sidebar
1633     
1634
1635     //sidebar events
1636     
1637     //menu-toggler
1638     $(document)
1639     .on(ace.click_event+'.ace.menu', '.menu-toggler', function(e){
1640         var btn = $(this);
1641         var sidebar = $(btn.attr('data-target'));
1642         if(sidebar.length == 0) return;
1643         
1644         e.preventDefault();
1645                 
1646         //sidebar.toggleClass('display');
1647         //btn.toggleClass('display');
1648         
1649         sidebar.ace_sidebar('toggleMobile', this);
1650         
1651         var click_event = ace.click_event+'.ace.autohide';
1652         var auto_hide = sidebar.attr('data-auto-hide') === 'true';
1653
1654         if( btn.hasClass('display') ) {
1655             //hide menu if clicked outside of it!
1656             if(auto_hide) {
1657                 $(document).on(click_event, function(ev) {
1658                     if( sidebar.get(0) == ev.target || $.contains(sidebar.get(0), ev.target) ) {
1659                         ev.stopPropagation();
1660                         return;
1661                     }
1662
1663                     sidebar.ace_sidebar('toggleMobile', this, false);
1664                     $(document).off(click_event);
1665                 })
1666             }
1667
1668             if(sidebar.attr('data-sidebar-scroll') == 'true') sidebar.ace_sidebar_scroll('reset');
1669         }
1670         else {
1671             if(auto_hide) $(document).off(click_event);
1672         }
1673
1674         return false;
1675     })
1676     //sidebar collapse/expand button
1677     .on(ace.click_event+'.ace.menu', '.sidebar-collapse', function(e){
1678         
1679         var target = $(this).attr('data-target'), $sidebar = null;
1680         if(target) $sidebar = $(target);
1681         if($sidebar == null || $sidebar.length == 0) $sidebar = $(this).closest('.sidebar');
1682         if($sidebar.length == 0) return;
1683
1684         e.preventDefault();
1685         $sidebar.ace_sidebar('toggleMenu', this);
1686     })
1687     //this button is used in `mobile_style = 3` responsive menu style to expand minimized sidebar
1688     .on(ace.click_event+'.ace.menu', '.sidebar-expand', function(e){
1689         var target = $(this).attr('data-target'), $sidebar = null;
1690         if(target) $sidebar = $(target);
1691         if($sidebar == null || $sidebar.length == 0) $sidebar = $(this).closest('.sidebar');
1692         if($sidebar.length == 0) return;    
1693     
1694         var btn = this;
1695         e.preventDefault();
1696         $sidebar.ace_sidebar('toggleResponsive', this);
1697         
1698         var click_event = ace.click_event+'.ace.autohide';
1699         if($sidebar.attr('data-auto-hide') === 'true') {
1700             if( $sidebar.hasClass(responsive_max_class) ) {
1701                 $(document).on(click_event, function(ev) {
1702                     if( $sidebar.get(0) == ev.target || $.contains($sidebar.get(0), ev.target) ) {
1703                         ev.stopPropagation();
1704                         return;
1705                     }
1706
1707                     $sidebar.ace_sidebar('toggleResponsive', btn);
1708                     $(document).off(click_event);
1709                 })
1710             }
1711             else {
1712                 $(document).off(click_event);
1713             }
1714         }
1715     })
1716
1717     
1718     $.fn.ace_sidebar = function (option, value, value2) {
1719         var method_call;
1720
1721         var $set = this.each(function () {
1722             var $this = $(this);
1723             var data = $this.data('ace_sidebar');
1724             var options = typeof option === 'object' && option;
1725
1726             if (!data) $this.data('ace_sidebar', (data = new Sidebar(this, options)));
1727             if (typeof option === 'string' && typeof data[option] === 'function') {
1728                 if(value instanceof Array) method_call = data[option].apply(data, value);
1729                 else if(value2 !== undefined) method_call = data[option](value, value2);
1730                 else method_call = data[option](value);
1731             }
1732         });
1733
1734         return (method_call === undefined) ? $set : method_call;
1735     };
1736     
1737     
1738     $.fn.ace_sidebar.defaults = {
1739         'duration': 300,
1740         'hide_open_subs': true
1741     }
1742
1743
1744 })(window.jQuery);
1745 ;/**
1746  <b>Scrollbars for sidebar</b>. This approach can <span class="text-danger">only</span> be used on <u>fixed</u> sidebar.
1747  It doesn't use <u>"overflow:hidden"</u> CSS property and therefore can be used with <u>.hover</u> submenus and minimized sidebar.
1748  Except when in mobile view and menu toggle button is not in the navbar.
1749 */
1750
1751 (function($ , undefined) {
1752     //if( !$.fn.ace_scroll ) return;
1753
1754     var old_safari = ace.vars['safari'] && navigator.userAgent.match(/version\/[1-5]/i)
1755     //NOTE
1756     //Safari on windows has not been updated for a long time.
1757     //And it has a problem when sidebar is fixed & scrollable and there is a CSS3 animation inside page content.
1758     //Very probably windows users of safari have migrated to another browser by now!
1759
1760     var is_element_pos =
1761     'getComputedStyle' in window ?
1762     //el.offsetHeight is used to force redraw and recalculate 'el.style.position' esp. for webkit!
1763     function(el, pos) { el.offsetHeight; return window.getComputedStyle(el).position == pos }
1764     :
1765     function(el, pos) { el.offsetHeight; return $(el).css('position') == pos }
1766     
1767         
1768     function Sidebar_Scroll(sidebar , settings) {
1769         var self = this;
1770
1771         var $window = $(window);
1772         var $sidebar = $(sidebar),
1773             $nav = $sidebar.find('.nav-list'),
1774             $toggle = $sidebar.find('.sidebar-toggle').eq(0),
1775             $shortcuts = $sidebar.find('.sidebar-shortcuts').eq(0);
1776             
1777         var nav = $nav.get(0);
1778         if(!nav) return;
1779         
1780         
1781         var attrib_values = ace.helper.getAttrSettings(sidebar, $.fn.ace_sidebar_scroll.defaults);
1782         this.settings = $.extend({}, $.fn.ace_sidebar_scroll.defaults, settings, attrib_values);
1783         var scroll_to_active = self.settings.scroll_to_active;
1784     
1785     
1786         var ace_sidebar = $sidebar.ace_sidebar('ref');
1787         $sidebar.attr('data-sidebar-scroll', 'true');
1788             
1789         
1790         var scroll_div = null,
1791             scroll_content = null,
1792             scroll_content_div = null,
1793             bar = null,
1794             track = null,
1795             ace_scroll = null;
1796
1797
1798         this.is_scrolling = false;
1799         var _initiated = false;
1800         this.sidebar_fixed = is_element_pos(sidebar, 'fixed');
1801         
1802         var $avail_height, $content_height;
1803
1804         
1805         var available_height = function() {
1806             //available window space
1807             var offset = $nav.parent().offset();//because `$nav.offset()` considers the "scrolled top" amount as well
1808             if(self.sidebar_fixed) offset.top -= ace.helper.scrollTop();
1809
1810             return $window.innerHeight() - offset.top - ( self.settings.include_toggle ? 0 : $toggle.outerHeight() ) + 1;
1811         }
1812         var content_height = function() {
1813             return nav.clientHeight;//we don't use nav.scrollHeight here, because hover submenus are considered in calculating scrollHeight despite position=absolute!
1814         }
1815
1816         
1817         
1818         var initiate = function(on_page_load) {
1819             if( _initiated ) return;
1820             if( !self.sidebar_fixed ) return;//eligible??
1821             //return if we want scrollbars only on "fixed" sidebar and sidebar is not "fixed" yet!
1822
1823             //initiate once
1824             $nav.wrap('<div class="nav-wrap-up pos-rel" />');
1825             $nav.after('<div><div></div></div>');
1826
1827             $nav.wrap('<div class="nav-wrap" />');
1828             if(!self.settings.include_toggle) $toggle.css({'z-index': 1});
1829             if(!self.settings.include_shortcuts) $shortcuts.css({'z-index': 99});
1830
1831             scroll_div = $nav.parent().next()
1832             .ace_scroll({
1833                 size: available_height(),
1834                 //reset: true,
1835                 mouseWheelLock: true,
1836                 hoverReset: false,
1837                 dragEvent: true,
1838                 styleClass: self.settings.scroll_style,
1839                 touchDrag: false//disable touch drag event on scrollbars, we'll add a custom one later
1840             })
1841             .closest('.ace-scroll').addClass('nav-scroll');
1842             
1843             ace_scroll = scroll_div.data('ace_scroll');
1844
1845             scroll_content = scroll_div.find('.scroll-content').eq(0);
1846             scroll_content_div = scroll_content.find(' > div').eq(0);
1847             
1848             track = $(ace_scroll.get_track());
1849             bar = track.find('.scroll-bar').eq(0);
1850
1851             if(self.settings.include_shortcuts && $shortcuts.length != 0) {
1852                 $nav.parent().prepend($shortcuts).wrapInner('<div />');
1853                 $nav = $nav.parent();
1854             }
1855             if(self.settings.include_toggle && $toggle.length != 0) {
1856                 $nav.append($toggle);
1857                 $nav.closest('.nav-wrap').addClass('nav-wrap-t');//it just helps to remove toggle button's top border and restore li:last-child's bottom border
1858             }
1859
1860             $nav.css({position: 'relative'});
1861             if( self.settings.scroll_outside == true ) scroll_div.addClass('scrollout');
1862             
1863             nav = $nav.get(0);
1864             nav.style.top = 0;
1865             scroll_content.on('scroll.nav', function() {
1866                 nav.style.top = (-1 * this.scrollTop) + 'px';
1867             });
1868             
1869             //mousewheel library available?
1870             $nav.on(!!$.event.special.mousewheel ? 'mousewheel.ace_scroll' : 'mousewheel.ace_scroll DOMMouseScroll.ace_scroll', function(event){
1871                 if( !self.is_scrolling || !ace_scroll.is_active() ) {
1872                     return !self.settings.lock_anyway;
1873                 }
1874                 //transfer $nav's mousewheel event to scrollbars
1875                 return scroll_div.trigger(event);
1876             });
1877             
1878             $nav.on('mouseenter.ace_scroll', function() {
1879                 track.addClass('scroll-hover');
1880             }).on('mouseleave.ace_scroll', function() {
1881                 track.removeClass('scroll-hover');
1882             });
1883
1884
1885             /**
1886             $(document.body).on('touchmove.nav', function(event) {
1887                 if( self.is_scrolling && $.contains(sidebar, event.target) ) {
1888                     event.preventDefault();
1889                     return false;
1890                 }
1891             })
1892             */
1893
1894             //you can also use swipe event in a similar way //swipe.nav
1895             var content = scroll_content.get(0);
1896             $nav.on('ace_drag.nav', function(event) {
1897                 if( !self.is_scrolling || !ace_scroll.is_active() ) {
1898                     event.retval.cancel = true;
1899                     return;
1900                 }
1901                 
1902                 //if submenu hover is being scrolled let's cancel sidebar scroll!
1903                 if( $(event.target).closest('.can-scroll').length != 0 ) {
1904                     event.retval.cancel = true;
1905                     return;
1906                 }
1907
1908                 if(event.direction == 'up' || event.direction == 'down') {
1909                     
1910                     ace_scroll.move_bar(true);
1911                     
1912                     var distance = event.dy;
1913                     
1914                     distance = parseInt(Math.min($avail_height, distance))
1915                     if(Math.abs(distance) > 2) distance = distance * 2;
1916                     
1917                     if(distance != 0) {
1918                         content.scrollTop = content.scrollTop + distance;
1919                         nav.style.top = (-1 * content.scrollTop) + 'px';
1920                     }
1921                 }
1922             });
1923             
1924
1925             //for drag only
1926             if(self.settings.smooth_scroll) {
1927                 $nav
1928                 .on('touchstart.nav MSPointerDown.nav pointerdown.nav', function(event) {
1929                     $nav.css('transition-property', 'none');
1930                     bar.css('transition-property', 'none');
1931                 })
1932                 .on('touchend.nav touchcancel.nav MSPointerUp.nav MSPointerCancel.nav pointerup.nav pointercancel.nav', function(event) {
1933                     $nav.css('transition-property', 'top');
1934                     bar.css('transition-property', 'top');
1935                 });
1936             }
1937             
1938             
1939
1940             if(old_safari && !self.settings.include_toggle) {
1941                 var toggle = $toggle.get(0);
1942                 if(toggle) scroll_content.on('scroll.safari', function() {
1943                     ace.helper.redraw(toggle);
1944                 });
1945             }
1946
1947             _initiated = true;
1948
1949             //if the active item is not visible, scroll down so that it becomes visible
1950             //only the first time, on page load
1951             if(on_page_load == true) {
1952                 self.reset();//try resetting at first
1953
1954                 if( scroll_to_active ) {
1955                     self.scroll_to_active();
1956                 }
1957                 scroll_to_active = false;
1958             }
1959             
1960             
1961             
1962             if( typeof self.settings.smooth_scroll === 'number' && self.settings.smooth_scroll > 0) {
1963                 $nav.css({'transition-property': 'top', 'transition-duration': (self.settings.smooth_scroll / 1000).toFixed(2)+'s'})
1964                 bar.css({'transition-property': 'top', 'transition-duration': (self.settings.smooth_scroll / 1500).toFixed(2)+'s'})
1965                 
1966                 scroll_div
1967                 .on('drag.start', function(e) {
1968                     e.stopPropagation();
1969                     $nav.css('transition-property', 'none')
1970                 })
1971                 .on('drag.end', function(e) {
1972                     e.stopPropagation();
1973                     $nav.css('transition-property', 'top')
1974                 });
1975             }
1976             
1977             if(ace.vars['android']) {
1978                 //force hide address bar, because its changes don't trigger window resize and become kinda ugly
1979                 var val = ace.helper.scrollTop();
1980                 if(val < 2) {
1981                     window.scrollTo( val, 0 );
1982                     setTimeout( function() {
1983                         self.reset();
1984                     }, 20 );
1985                 }
1986                 
1987                 var last_height = ace.helper.winHeight() , new_height;
1988                 $(window).on('scroll.ace_scroll', function() {
1989                     if(self.is_scrolling && ace_scroll.is_active()) {
1990                         new_height = ace.helper.winHeight();
1991                         if(new_height != last_height) {
1992                             last_height = new_height;
1993                             self.reset();
1994                         }
1995                     }
1996                 });
1997             }
1998         }
1999         
2000         
2001         
2002         
2003         this.scroll_to_active = function() {
2004             if( !ace_scroll || !ace_scroll.is_active() ) return;
2005             try {
2006                 //sometimes there's no active item or not 'offsetTop' property
2007                 var $active;
2008                 
2009                 var vars = ace_sidebar['vars']()
2010
2011                 var nav_list = $sidebar.find('.nav-list')
2012                 if(vars['minimized'] && !vars['collapsible']) {
2013                     $active = nav_list.find('> .active')
2014                 }
2015                 else {
2016                     $active = $nav.find('> .active.hover')
2017                     if($active.length == 0)    $active = $nav.find('.active:not(.open)')
2018                 }
2019
2020             
2021                 var top = $active.outerHeight();
2022                 nav_list = nav_list.get(0);
2023                 var active = $active.get(0);
2024                 while(active != nav_list) {
2025                     top += active.offsetTop;
2026                     active = active.parentNode;
2027                 }
2028
2029                 var scroll_amount = top - scroll_div.height();
2030                 if(scroll_amount > 0) {
2031                     nav.style.top = -scroll_amount + 'px';
2032                     scroll_content.scrollTop(scroll_amount);
2033                 }
2034             }catch(e){}
2035         }
2036         
2037         
2038         
2039         this.reset = function(recalc) {
2040             if(recalc === true) {
2041                 this.sidebar_fixed = is_element_pos(sidebar, 'fixed');
2042             }
2043             
2044             if( !this.sidebar_fixed ) {
2045                 this.disable();
2046                 return;//eligible??
2047             }
2048
2049             //return if we want scrollbars only on "fixed" sidebar and sidebar is not "fixed" yet!
2050
2051             if( !_initiated ) initiate();
2052             //initiate scrollbars if not yet
2053             
2054             var vars = ace_sidebar['vars']();
2055             
2056
2057             //enable if:
2058             //menu is not collapsible mode (responsive navbar-collapse mode which has default browser scrollbar)
2059             //menu is not horizontal or horizontal but mobile view (which is not navbar-collapse)
2060             //and available height is less than nav's height
2061             
2062
2063             var enable_scroll = !vars['collapsible'] && !vars['horizontal']
2064                                 && ($avail_height = available_height()) < ($content_height = nav.clientHeight);
2065                                 //we don't use nav.scrollHeight here, because hover submenus are considered in calculating scrollHeight despite position=absolute!
2066
2067                                 
2068             this.is_scrolling = true;
2069             if( enable_scroll ) {
2070                 scroll_content_div.css({height: $content_height, width: 8});
2071                 scroll_div.prev().css({'max-height' : $avail_height})
2072                 ace_scroll.update({size: $avail_height})
2073                 ace_scroll.enable();
2074                 ace_scroll.reset();
2075             }
2076             if( !enable_scroll || !ace_scroll.is_active() ) {
2077                 if(this.is_scrolling) this.disable();
2078             }
2079             else {
2080                 $sidebar.addClass('sidebar-scroll');
2081             }
2082             
2083             //return this.is_scrolling;
2084         }
2085         
2086         
2087         
2088         this.disable = function() {
2089             this.is_scrolling = false;
2090             if(scroll_div) {
2091                 scroll_div.css({'height' : '', 'max-height' : ''});
2092                 scroll_content_div.css({height: '', width: ''});//otherwise it will have height and takes up some space even when invisible
2093                 scroll_div.prev().css({'max-height' : ''})
2094                 ace_scroll.disable();
2095             }
2096
2097             if(parseInt(nav.style.top) < 0 && self.settings.smooth_scroll && $.support.transition.end) {
2098                 $nav.one($.support.transition.end, function() {
2099                     $sidebar.removeClass('sidebar-scroll');
2100                     $nav.off('.trans');
2101                 });
2102             } else {
2103                 $sidebar.removeClass('sidebar-scroll');
2104             }
2105
2106             nav.style.top = 0;
2107         }
2108         
2109         this.prehide = function(height_change) {
2110             if(!this.is_scrolling || ace_sidebar.get('minimized')) return;//when minimized submenu's toggle should have no effect
2111             
2112             if(content_height() + height_change < available_height()) {
2113                 this.disable();
2114             }
2115             else if(height_change < 0) {
2116                 //if content height is decreasing
2117                 //let's move nav down while a submenu is being hidden
2118                 var scroll_top = scroll_content.scrollTop() + height_change
2119                 if(scroll_top < 0) return;
2120
2121                 nav.style.top = (-1 * scroll_top) + 'px';
2122             }
2123         }
2124         
2125         
2126         this._reset = function(recalc) {
2127             if(recalc === true) {
2128                 this.sidebar_fixed = is_element_pos(sidebar, 'fixed');
2129             }
2130             
2131             if(ace.vars['webkit']) 
2132                 setTimeout(function() { self.reset() } , 0);
2133             else this.reset();
2134         }
2135         
2136         
2137         this.set_hover = function() {
2138             if(track) track.addClass('scroll-hover');
2139         }
2140         
2141         this.get = function(name) {
2142             if(this.hasOwnProperty(name)) return this[name];
2143         }
2144         this.set = function(name, value) {
2145             if(this.hasOwnProperty(name)) this[name] = value;
2146         }
2147         this.ref = function() {
2148             //return a reference to self
2149             return this;
2150         }
2151         
2152         this.updateStyle = function(styleClass) {
2153             if(ace_scroll == null) return;
2154             ace_scroll.update({styleClass: styleClass});
2155         }
2156
2157         
2158         //change scrollbar size after a submenu is hidden/shown
2159         //but don't change if sidebar is minimized
2160         $sidebar.on('hidden.ace.submenu.sidebar_scroll shown.ace.submenu.sidebar_scroll', '.submenu', function(e) {
2161             e.stopPropagation();
2162
2163             if( !ace_sidebar.get('minimized') ) {
2164                 //webkit has a little bit of a glitch!!!
2165                 self._reset();
2166                 if( e.type == 'shown' ) self.set_hover();
2167             }
2168         });
2169
2170         
2171         initiate(true);//true = on_page_load
2172     }
2173     
2174
2175     
2176     //reset on document and window changes
2177     $(document).on('settings.ace.sidebar_scroll', function(ev, event_name, event_val){
2178         $('.sidebar[data-sidebar-scroll=true]').each(function() {
2179             var $this = $(this);
2180             var sidebar_scroll = $this.ace_sidebar_scroll('ref');
2181
2182             if( event_name == 'sidebar_collapsed' && is_element_pos(this, 'fixed') ) {
2183                 if( $this.attr('data-sidebar-hover') == 'true' ) $this.ace_sidebar_hover('reset');
2184                 sidebar_scroll._reset();
2185             }
2186             else if( event_name === 'sidebar_fixed' || event_name === 'navbar_fixed' ) {
2187                 var is_scrolling = sidebar_scroll.get('is_scrolling');
2188                 var sidebar_fixed = is_element_pos(this, 'fixed')
2189                 sidebar_scroll.set('sidebar_fixed', sidebar_fixed);
2190
2191                 if(sidebar_fixed && !is_scrolling) {
2192                     sidebar_scroll._reset();
2193                 }
2194                 else if( !sidebar_fixed ) {
2195                     sidebar_scroll.disable();
2196                 }
2197             }
2198         
2199         });
2200     });
2201     
2202     $(window).on('resize.ace.sidebar_scroll', function(){
2203         $('.sidebar[data-sidebar-scroll=true]').each(function() {
2204             var $this = $(this);
2205             if( $this.attr('data-sidebar-hover') == 'true' ) $this.ace_sidebar_hover('reset');
2206             /////////////
2207             var sidebar_scroll = $(this).ace_sidebar_scroll('ref');
2208             
2209             var sidebar_fixed = is_element_pos(this, 'fixed')
2210             sidebar_scroll.set('sidebar_fixed', sidebar_fixed);
2211             sidebar_scroll._reset();
2212         });
2213     })
2214     
2215
2216     
2217     
2218      /////////////////////////////////////////////
2219      if(!$.fn.ace_sidebar_scroll) {
2220       $.fn.ace_sidebar_scroll = function (option, value) {
2221         var method_call;
2222
2223         var $set = this.each(function () {
2224             var $this = $(this);
2225             var data = $this.data('ace_sidebar_scroll');
2226             var options = typeof option === 'object' && option;
2227
2228             if (!data) $this.data('ace_sidebar_scroll', (data = new Sidebar_Scroll(this, options)));
2229             if (typeof option === 'string' && typeof data[option] === 'function') {
2230                 method_call = data[option](value);
2231             }
2232         });
2233
2234         return (method_call === undefined) ? $set : method_call;
2235      }
2236      
2237      
2238      $.fn.ace_sidebar_scroll.defaults = {
2239         'scroll_to_active': true,
2240         'include_shortcuts': true,
2241         'include_toggle': false,
2242         'smooth_scroll': 150,
2243         'scroll_outside': false,
2244         'scroll_style': '',
2245         'lock_anyway': false
2246      }
2247      
2248     }
2249
2250 })(window.jQuery);;/**
2251  <b>Submenu hover adjustment</b>. Automatically move up a submenu to fit into screen when some part of it goes beneath window.
2252  Pass a "true" value as an argument and submenu will have native browser scrollbars when necessary.
2253 */
2254
2255 (function($ , undefined) {
2256
2257  if( ace.vars['very_old_ie'] ) return;
2258  //ignore IE7 & below
2259
2260  var hasTouch = ace.vars['touch'];
2261  var nativeScroll = ace.vars['old_ie'] || hasTouch;
2262  
2263
2264  var is_element_pos =
2265     'getComputedStyle' in window ?
2266     //el.offsetHeight is used to force redraw and recalculate 'el.style.position' esp. for webkit!
2267     function(el, pos) { el.offsetHeight; return window.getComputedStyle(el).position == pos }
2268     :
2269     function(el, pos) { el.offsetHeight; return $(el).css('position') == pos }
2270
2271
2272
2273  $(window).on('resize.sidebar.ace_hover', function() {
2274     $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('update_vars').ace_sidebar_hover('reset');
2275  })
2276
2277  $(document).on('settings.ace.ace_hover', function(e, event_name, event_val) {
2278     if(event_name == 'sidebar_collapsed') $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('reset');
2279     else if(event_name == 'navbar_fixed') $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('update_vars');
2280  })
2281  
2282  var sidebars = [];
2283
2284  function Sidebar_Hover(sidebar , settings) {
2285     var self = this, that = this;
2286     
2287     var attrib_values = ace.helper.getAttrSettings(sidebar, $.fn.ace_sidebar_hover.defaults);
2288     this.settings = $.extend({}, $.fn.ace_sidebar_hover.defaults, settings, attrib_values);
2289     
2290
2291     var $sidebar = $(sidebar), nav_list = $sidebar.find('.nav-list').get(0);
2292     $sidebar.attr('data-sidebar-hover', 'true');
2293     
2294     sidebars.push($sidebar);
2295
2296     var sidebar_vars = {};
2297     var old_ie = ace.vars['old_ie'];
2298
2299     
2300     
2301     var scroll_right = false;
2302     //scroll style class
2303     var hasHoverDelay = self.settings.sub_hover_delay || false;
2304     
2305     if(hasTouch && hasHoverDelay) self.settings.sub_hover_delay = parseInt(Math.max(self.settings.sub_hover_delay, 2500));//for touch device, delay is at least 2.5sec
2306
2307     var $window = $(window);
2308     //navbar used for adding extra offset from top when adjusting submenu
2309     var $navbar = $('.navbar').eq(0);
2310     var navbar_fixed = $navbar.css('position') == 'fixed';
2311     this.update_vars = function() {
2312         navbar_fixed = $navbar.css('position') == 'fixed';
2313     }
2314
2315     self.dirty = false;
2316     //on window resize or sidebar expand/collapse a previously "pulled up" submenu should be reset back to its default position
2317     //for example if "pulled up" in "responsive-min" mode, in "fullmode" should not remain "pulled up"
2318     this.reset = function() {
2319         if( self.dirty == false ) return;
2320         self.dirty = false;//so don't reset is not called multiple times in a row!
2321     
2322         $sidebar.find('.submenu').each(function() {
2323             var $sub = $(this), li = $sub.parent();
2324             $sub.css({'top': '', 'bottom': '', 'max-height': ''});
2325             
2326             if($sub.hasClass('ace-scroll')) {
2327                 $sub.ace_scroll('disable');
2328             }
2329             else {
2330                 $sub.removeClass('sub-scroll');
2331             }
2332              
2333             if( is_element_pos(this, 'absolute') ) $sub.addClass('can-scroll');
2334             else $sub.removeClass('can-scroll');
2335
2336             li.removeClass('pull_up').find('.menu-text:first').css('margin-top', '');
2337         })
2338
2339         $sidebar.find('.hover-show').removeClass('hover-show hover-shown hover-flip');
2340     }
2341     
2342     this.updateStyle = function(newStyle) {
2343         sub_scroll_style = newStyle;
2344         $sidebar.find('.submenu.ace-scroll').ace_scroll('update', {styleClass: newStyle});
2345     }
2346     this.changeDir = function(dir) {
2347         scroll_right = (dir === 'right');
2348     }
2349     
2350     
2351     //update submenu scrollbars on submenu hide & show
2352
2353     var lastScrollHeight = -1;
2354     //hide scrollbars if it's going to be not needed anymore!
2355     if(!nativeScroll)
2356     $sidebar.on('hide.ace.submenu.sidebar_hover', '.submenu', function(e) {
2357         if(lastScrollHeight < 1) return;
2358
2359         e.stopPropagation();
2360         var $sub = $(this).closest('.ace-scroll.can-scroll');
2361         if($sub.length == 0 || !is_element_pos($sub[0], 'absolute')) return;
2362
2363         if($sub[0].scrollHeight - this.scrollHeight < lastScrollHeight) {
2364             $sub.ace_scroll('disable');
2365         }
2366     });
2367
2368     
2369     
2370     
2371     //reset scrollbars 
2372     if(!nativeScroll)
2373     $sidebar.on('shown.ace.submenu.sidebar_hover hidden.ace.submenu.sidebar_hover', '.submenu', function(e) {
2374         if(lastScrollHeight < 1) return;
2375     
2376         var $sub = $(this).closest('.ace-scroll.can-scroll');
2377         if($sub.length == 0 || !is_element_pos($sub[0], 'absolute') ) return;
2378         
2379         var sub_h = $sub[0].scrollHeight;
2380         
2381         if(lastScrollHeight > 14 && sub_h - lastScrollHeight > 4) {
2382             $sub.ace_scroll('enable').ace_scroll('reset');//don't update track position
2383         }
2384         else {
2385             $sub.ace_scroll('disable');
2386         }
2387     });
2388
2389
2390     ///////////////////////
2391
2392
2393     var currentScroll = -1;
2394
2395     //some mobile browsers don't have mouseenter
2396     var event_1 = !hasTouch ? 'mouseenter.sub_hover' : 'touchstart.sub_hover';// pointerdown.sub_hover';
2397     var event_2 = !hasTouch ? 'mouseleave.sub_hover' : 'touchend.sub_hover touchcancel.sub_hover';// pointerup.sub_hover pointercancel.sub_hover';
2398     
2399     $sidebar.on(event_1, '.nav-list li, .sidebar-shortcuts', function (e) {
2400         sidebar_vars = $sidebar.ace_sidebar('vars');
2401         
2402     
2403         //ignore if collapsible mode (mobile view .navbar-collapse) so it doesn't trigger submenu movements
2404         //or return if horizontal but not mobile_view (style 1&3)
2405         if( sidebar_vars['collapsible'] /**|| sidebar_vars['horizontal']*/ ) return;
2406         
2407         var $this = $(this);
2408
2409         var shortcuts = false;
2410         var has_hover = $this.hasClass('hover');
2411         
2412         var sub = $this.find('> .submenu').get(0);
2413         if( !(sub || ((this.parentNode == nav_list || has_hover || (shortcuts = $this.hasClass('sidebar-shortcuts'))) /**&& sidebar_vars['minimized']*/)) ) {
2414             if(sub) $(sub).removeClass('can-scroll');
2415             return;//include .compact and .hover state as well?
2416         }
2417         
2418         var target_element = sub, is_abs = false;
2419         if( !target_element && this.parentNode == nav_list ) target_element = $this.find('> a > .menu-text').get(0);
2420         if( !target_element && shortcuts ) target_element = $this.find('.sidebar-shortcuts-large').get(0);
2421         if( (!target_element || !(is_abs = is_element_pos(target_element, 'absolute'))) && !has_hover ) {
2422             if(sub) $(sub).removeClass('can-scroll');
2423             return;
2424         }
2425         
2426         
2427         var sub_hide = hasHoverDelay ? getSubHide(this) : null;
2428         //var show_sub = false;
2429
2430         if(sub) {
2431          if(is_abs) {
2432             self.dirty = true;
2433             
2434             var newScroll = ace.helper.scrollTop();
2435             //if submenu is becoming visible for first time or document has been scrolled, then adjust menu
2436             if( (hasHoverDelay && !sub_hide.is_visible()) || (!hasTouch && newScroll != currentScroll) || old_ie ) {
2437                 //try to move/adjust submenu if the parent is a li.hover or if submenu is minimized
2438                 //if( is_element_pos(sub, 'absolute') ) {//for example in small device .hover > .submenu may not be absolute anymore!
2439                     $(sub).addClass('can-scroll');
2440                     //show_sub = true;
2441                     if(!old_ie && !hasTouch) adjust_submenu.call(this, sub);
2442                     else {
2443                         //because ie8 needs some time for submenu to be displayed and real value of sub.scrollHeight be kicked in
2444                         var that = this;
2445                         setTimeout(function() {    adjust_submenu.call(that, sub) }, 0)
2446                     }
2447                 //}
2448                 //else $(sub).removeClass('can-scroll');
2449             }
2450             currentScroll = newScroll;
2451          }
2452          else {
2453             $(sub).removeClass('can-scroll');
2454          }
2455         }
2456         //if(show_sub) 
2457         hasHoverDelay && sub_hide.show();
2458         
2459      }).on(event_2, '.nav-list li, .sidebar-shortcuts', function (e) {
2460         sidebar_vars = $sidebar.ace_sidebar('vars');
2461         
2462         if( sidebar_vars['collapsible'] /**|| sidebar_vars['horizontal']*/ ) return;
2463
2464         if( !$(this).hasClass('hover-show') ) return;
2465
2466         hasHoverDelay && getSubHide(this).hideDelay();
2467      });
2468      
2469     
2470     function subHide(li_sub) {
2471         var self = li_sub, $self = $(self);
2472         var timer = null;
2473         var visible = false;
2474         
2475         this.show = function() {
2476             if(timer != null) clearTimeout(timer);
2477             timer = null;        
2478
2479             $self.addClass('hover-show hover-shown');
2480             visible = true;
2481
2482             //let's hide .hover-show elements that are not .hover-shown anymore (i.e. marked for hiding in hideDelay)
2483             for(var i = 0; i < sidebars.length ; i++)
2484             {
2485               sidebars[i].find('.hover-show').not('.hover-shown').each(function() {
2486                 getSubHide(this).hide();
2487               })
2488             }
2489         }
2490         
2491         this.hide = function() {
2492             visible = false;
2493             
2494             $self.removeClass('hover-show hover-shown hover-flip');
2495             
2496             if(timer != null) clearTimeout(timer);
2497             timer = null;
2498             
2499             var sub = $self.find('> .submenu').get(0);
2500             if(sub) getSubScroll(sub, 'hide');
2501         }
2502         
2503         this.hideDelay = function(callback) {
2504             if(timer != null) clearTimeout(timer);
2505             
2506             $self.removeClass('hover-shown');//somehow marked for hiding
2507             
2508             timer = setTimeout(function() {
2509                 visible = false;
2510                 $self.removeClass('hover-show hover-flip');
2511                 timer = null;
2512                 
2513                 var sub = $self.find('> .submenu').get(0);
2514                 if(sub) getSubScroll(sub, 'hide');
2515                 
2516                 if(typeof callback === 'function') callback.call(this);
2517             }, that.settings.sub_hover_delay);
2518         }
2519         
2520         this.is_visible = function() {
2521             return visible;
2522         }
2523     }
2524     function getSubHide(el) {
2525         var sub_hide = $(el).data('subHide');
2526         if(!sub_hide) $(el).data('subHide', (sub_hide = new subHide(el)));
2527         return sub_hide;
2528     }
2529     
2530     
2531     function getSubScroll(el, func) {
2532         var sub_scroll = $(el).data('ace_scroll');
2533         if(!sub_scroll) return false;
2534         if(typeof func === 'string') {
2535             sub_scroll[func]();
2536             return true;
2537         }
2538         return sub_scroll;
2539     }    
2540     
2541     function adjust_submenu(sub) {
2542         var $li = $(this);
2543         var $sub = $(sub);
2544         sub.style.top = '';
2545         sub.style.bottom = '';
2546
2547
2548         var menu_text = null
2549         if( sidebar_vars['minimized'] && (menu_text = $li.find('.menu-text').get(0)) ) {
2550             //2nd level items don't have .menu-text
2551             menu_text.style.marginTop = '';
2552         }
2553
2554         var scroll = ace.helper.scrollTop();
2555         var navbar_height = 0;
2556
2557         var $scroll = scroll;
2558         
2559         if( navbar_fixed ) {
2560             navbar_height = sidebar.offsetTop;//$navbar.height();
2561             $scroll += navbar_height + 1;
2562             //let's avoid our submenu from going below navbar
2563             //because of chrome z-index stacking issue and firefox's normal .submenu over fixed .navbar flicker issue
2564         }
2565
2566
2567
2568
2569         var off = $li.offset();
2570         off.top = parseInt(off.top);
2571         
2572         var extra = 0, parent_height;
2573         
2574         sub.style.maxHeight = '';//otherwise scrollHeight won't be consistent in consecutive calls!?
2575         var sub_h = sub.scrollHeight;
2576         var parent_height = $li.height();
2577         if(menu_text) {
2578             extra = parent_height;
2579             off.top += extra;
2580         }
2581         var sub_bottom = parseInt(off.top + sub_h)
2582
2583         var move_up = 0;
2584         var winh = $window.height();
2585
2586
2587         //if the bottom of menu is going to go below visible window
2588
2589         var top_space = parseInt(off.top - $scroll - extra);//available space on top
2590         var win_space = winh;//available window space
2591         
2592         var horizontal = sidebar_vars['horizontal'], horizontal_sub = false;
2593         if(horizontal && this.parentNode == nav_list) {
2594             move_up = 0;//don't move up first level submenu in horizontal mode
2595             off.top += $li.height();
2596             horizontal_sub = true;//first level submenu
2597         }
2598
2599         if(!horizontal_sub && (move_up = (sub_bottom - (winh + scroll))) >= 0 ) {
2600             //don't move up more than available space
2601             move_up = move_up < top_space ? move_up : top_space;
2602
2603             //move it up a bit more if there's empty space
2604             if(move_up == 0) move_up = 20;
2605             if(top_space - move_up > 10) {
2606                 move_up += parseInt(Math.min(25, top_space - move_up));
2607             }
2608
2609
2610             //move it down if submenu's bottom is going above parent LI
2611             if(off.top + (parent_height - extra) > (sub_bottom - move_up)) {
2612                 move_up -= (off.top + (parent_height - extra) - (sub_bottom - move_up));
2613             }
2614
2615             if(move_up > 0) {
2616                 sub.style.top = -(move_up) + 'px';
2617                 if( menu_text ) {
2618                     menu_text.style.marginTop = -(move_up) + 'px';
2619                 }
2620             }
2621         }
2622         if(move_up < 0) move_up = 0;//when it goes below
2623         
2624         var pull_up = move_up > 0 && move_up > parent_height - 20;
2625         if(pull_up) {
2626             $li.addClass('pull_up');
2627         }
2628         else $li.removeClass('pull_up');
2629         
2630         
2631         //flip submenu if out of window width
2632         if(horizontal) {
2633             if($li.parent().parent().hasClass('hover-flip')) $li.addClass('hover-flip');//if a parent is already flipped, flip it then!
2634             else {
2635                 var sub_off = $sub.offset();
2636                 var sub_w = $sub.width();
2637                 var win_w = $window.width();
2638                 if(sub_off.left + sub_w > win_w) {
2639                     $li.addClass('hover-flip');
2640                 }
2641             }
2642         }
2643
2644
2645         //don't add scrollbars if it contains .hover menus
2646         var has_hover = $li.hasClass('hover') && !sidebar_vars['mobile_view'];
2647         if(has_hover && $sub.find('> li > .submenu').length > 0) return;
2648
2649     
2650         //if(  ) {
2651             var scroll_height = (win_space - (off.top - scroll)) + (move_up);
2652             //if after scroll, the submenu is above parent LI, then move it down
2653             var tmp = move_up - scroll_height;
2654             if(tmp > 0 && tmp < parent_height) scroll_height += parseInt(Math.max(parent_height, parent_height - tmp));
2655
2656             scroll_height -= 5;
2657             
2658             if(scroll_height < 90) {
2659                 return;
2660             }
2661             
2662             var ace_scroll = false;
2663             if(!nativeScroll) {
2664                 ace_scroll = getSubScroll(sub);
2665                 if(ace_scroll == false) {
2666                     $sub.ace_scroll({
2667                         //hideOnIdle: true,
2668                         observeContent: true,
2669                         detached: true,
2670                         updatePos: false,
2671                         reset: true,
2672                         mouseWheelLock: true,
2673                         styleClass: self.settings.sub_scroll_style
2674                     });
2675                     ace_scroll = getSubScroll(sub);
2676                     
2677                     var track = ace_scroll.get_track();
2678                     if(track) {
2679                         //detach it from body and insert it after submenu for better and cosistent positioning
2680                         $sub.after(track);
2681                     }
2682                 }
2683                 
2684                 ace_scroll.update({size: scroll_height});
2685             }
2686             else {
2687                 $sub
2688                 .addClass('sub-scroll')
2689                 .css('max-height', (scroll_height)+'px')
2690             }
2691
2692
2693             lastScrollHeight = scroll_height;
2694             if(!nativeScroll && ace_scroll) {
2695                 if(scroll_height > 14 && sub_h - scroll_height > 4) {
2696                     ace_scroll.enable()
2697                     ace_scroll.reset();
2698                 }            
2699                 else {
2700                     ace_scroll.disable();
2701                 }
2702
2703                 //////////////////////////////////
2704                 var track = ace_scroll.get_track();
2705                 if(track) {
2706                     track.style.top = -(move_up - extra - 1) + 'px';
2707                     
2708                     var off = $sub.position();
2709                     var left = off.left 
2710                     if( !scroll_right ) {
2711                         left += ($sub.outerWidth() - ace_scroll.track_size());
2712                     }
2713                     else {
2714                         left += 2;
2715                     }
2716                     track.style.left = parseInt(left) + 'px';
2717                     
2718                     if(horizontal_sub) {//first level submenu
2719                         track.style.left = parseInt(left - 2) + 'px';
2720                         track.style.top = parseInt(off.top) + (menu_text ? extra - 2 : 0) + 'px';
2721                     }
2722                 }
2723             }
2724         //}
2725
2726
2727         //again force redraw for safari!
2728         if( ace.vars['safari'] ) {
2729             ace.helper.redraw(sub)
2730         }
2731    }
2732
2733 }
2734  
2735  
2736  
2737  /////////////////////////////////////////////
2738  $.fn.ace_sidebar_hover = function (option, value) {
2739     var method_call;
2740
2741     var $set = this.each(function () {
2742         var $this = $(this);
2743         var data = $this.data('ace_sidebar_hover');
2744         var options = typeof option === 'object' && option;
2745
2746         if (!data) $this.data('ace_sidebar_hover', (data = new Sidebar_Hover(this, options)));
2747         if (typeof option === 'string' && typeof data[option] === 'function') {
2748             method_call = data[option](value);
2749         }
2750     });
2751
2752     return (method_call === undefined) ? $set : method_call;
2753  }
2754  
2755   $.fn.ace_sidebar_hover.defaults = {
2756     'sub_sub_hover_delay': 750,
2757     'sub_scroll_style': 'no-track scroll-thin'
2758  }
2759  
2760
2761 })(window.jQuery);
2762
2763 ;/**
2764  <b>Widget boxes</b>
2765 */
2766 (function($ , undefined) {
2767
2768     var Widget_Box = function(box, options) {
2769         this.$box = $(box);
2770         var that = this;
2771         //this.options = $.extend({}, $.fn.widget_box.defaults, options);
2772
2773         this.reload = function() {
2774             var $box = this.$box;
2775             var $remove_position = false;
2776             if($box.css('position') == 'static') {
2777                 $remove_position = true;
2778                 $box.addClass('position-relative');
2779             }
2780             $box.append('<div class="widget-box-overlay"><i class="'+ ace.vars['icon'] + 'loading-icon fa fa-spinner fa-spin fa-2x white"></i></div>');
2781
2782             $box.one('reloaded.ace.widget', function() {
2783                 $box.find('.widget-box-overlay').remove();
2784                 if($remove_position) $box.removeClass('position-relative');
2785             });
2786         }
2787
2788         this.closeFast = function() {
2789             this.close(0);
2790         }
2791         this.close = function(closeSpeed) {
2792             var $box = this.$box;
2793             var closeSpeed   = typeof closeSpeed === 'undefined' ? 300 : closeSpeed;
2794             $box.fadeOut(closeSpeed , function(){
2795                     $box.trigger('closed.ace.widget');
2796                     $box.remove();
2797                 }
2798             )
2799         }
2800         
2801         this.toggleFast = function() {
2802             this.toggle(null, null, 0, 0);
2803         }
2804         
2805         this.toggle = function(type, button, expandSpeed, collapseSpeed) {
2806             var $box = this.$box;
2807             var $body = $box.find('.widget-body').eq(0);
2808             var $icon = null;
2809             
2810             var event_name = type || ($box.hasClass('collapsed') ? 'show' : 'hide');
2811             var event_complete_name = event_name == 'show' ? 'shown' : 'hidden';
2812
2813             if( !button ) {
2814                 button = $box.find('> .widget-header a[data-action=collapse]').eq(0);
2815                 if(button.length == 0) button = null;
2816             }
2817
2818             if(button) {
2819             
2820                 $icon = button.find(ace.vars['.icon']).eq(0);
2821
2822                 var $match
2823                 var $icon_down = null
2824                 var $icon_up = null
2825                 if( ($icon_down = $icon.attr('data-icon-show')) ) {
2826                     $icon_up = $icon.attr('data-icon-hide')
2827                 }
2828                 else if( $match = $icon.attr('class').match(/fa\-(.*)\-(up|down)/) ) {
2829                     $icon_down = 'fa-'+$match[1]+'-down'
2830                     $icon_up = 'fa-'+$match[1]+'-up'
2831                 }
2832             }
2833
2834             var expandSpeed   = typeof expandSpeed === 'undefined' ? 250 : expandSpeed;
2835             var collapseSpeed = typeof collapseSpeed === 'undefined' ? 200 : collapseSpeed;
2836             
2837
2838             if( event_name == 'show' ) {
2839                 if($icon) $icon.removeClass($icon_down).addClass($icon_up);
2840
2841                 $body.hide();
2842                 $box.removeClass('collapsed');
2843                 $body.slideDown(expandSpeed, function(){
2844                     $box.trigger(event_complete_name+'.ace.widget')
2845                 })
2846             }
2847             else {
2848                 if($icon) $icon.removeClass($icon_up).addClass($icon_down);
2849                 $body.slideUp(collapseSpeed, function(){
2850                         $box.addClass('collapsed')
2851                         $box.trigger(event_complete_name+'.ace.widget')
2852                     }
2853                 );
2854             }
2855         }
2856         
2857         this.hide = function() {
2858             this.toggle('hide');
2859         }
2860         this.show = function() {
2861             this.toggle('show');
2862         }
2863         
2864         
2865         this.fullscreen = function() {
2866             var $icon = this.$box.find('> .widget-header a[data-action=fullscreen]').find(ace.vars['.icon']).eq(0);
2867             var $icon_expand = null
2868             var $icon_compress = null
2869             if( ($icon_expand = $icon.attr('data-icon1')) ) {
2870                 $icon_compress = $icon.attr('data-icon2')
2871             }
2872             else {
2873                 $icon_expand = 'fa-expand';
2874                 $icon_compress = 'fa-compress';
2875             }
2876             
2877             
2878             if(!this.$box.hasClass('fullscreen')) {
2879                 $icon.removeClass($icon_expand).addClass($icon_compress);
2880                 this.$box.addClass('fullscreen');
2881                 
2882                 applyScrollbars(this.$box, true);
2883             }
2884             else {
2885                 $icon.addClass($icon_expand).removeClass($icon_compress);
2886                 this.$box.removeClass('fullscreen');
2887                 
2888                 applyScrollbars(this.$box, false);
2889             }
2890             
2891             this.$box.trigger('fullscreened.ace.widget')
2892         }
2893
2894     }
2895     
2896     $.fn.widget_box = function (option, value) {
2897         var method_call;
2898
2899         var $set = this.each(function () {
2900             var $this = $(this);
2901             var data = $this.data('widget_box');
2902             var options = typeof option === 'object' && option;
2903
2904             if (!data) $this.data('widget_box', (data = new Widget_Box(this, options)));
2905             if (typeof option === 'string') method_call = data[option](value);
2906         });
2907
2908         return (method_call === undefined) ? $set : method_call;
2909     };
2910
2911
2912     $(document).on('click.ace.widget', '.widget-header a[data-action]', function (ev) {
2913         ev.preventDefault();
2914
2915         var $this = $(this);
2916         var $box = $this.closest('.widget-box');
2917         if( $box.length == 0 || $box.hasClass('ui-sortable-helper') ) return;
2918
2919         var $widget_box = $box.data('widget_box');
2920         if (!$widget_box) {
2921             $box.data('widget_box', ($widget_box = new Widget_Box($box.get(0))));
2922         }
2923
2924         var $action = $this.data('action');
2925         if($action == 'collapse') {
2926             var event_name = $box.hasClass('collapsed') ? 'show' : 'hide';
2927
2928             var event
2929             $box.trigger(event = $.Event(event_name+'.ace.widget'))
2930             if (event.isDefaultPrevented()) return
2931
2932             $widget_box.toggle(event_name, $this);
2933         }
2934         else if($action == 'close') {
2935             var event
2936             $box.trigger(event = $.Event('close.ace.widget'))
2937             if (event.isDefaultPrevented()) return
2938
2939             $widget_box.close();
2940         }
2941         else if($action == 'reload') {
2942             $this.blur();
2943             var event
2944             $box.trigger(event = $.Event('reload.ace.widget'))
2945             if (event.isDefaultPrevented()) return
2946
2947             $widget_box.reload();
2948         }
2949         else if($action == 'fullscreen') {
2950             var event
2951             $box.trigger(event = $.Event('fullscreen.ace.widget'))
2952             if (event.isDefaultPrevented()) return
2953         
2954             $widget_box.fullscreen();
2955         }
2956         else if($action == 'settings') {
2957             $box.trigger('setting.ace.widget')
2958         }
2959
2960     });
2961     
2962         
2963     function applyScrollbars($widget, enable) {
2964         var $main = $widget.find('.widget-main').eq(0);
2965         $(window).off('resize.widget.scroll');
2966         
2967         //IE8 has an unresolvable issue!!! re-scrollbaring with unknown values?!
2968         var nativeScrollbars = ace.vars['old_ie'] || ace.vars['touch'];
2969         
2970         if(enable) {
2971             var ace_scroll = $main.data('ace_scroll');
2972             if( ace_scroll ) {
2973                 $main.data('save_scroll', {size: ace_scroll['size'], lock: ace_scroll['lock'], lock_anyway: ace_scroll['lock_anyway']});
2974             }
2975             
2976             var size = $widget.height() - $widget.find('.widget-header').height() - 10;//extra paddings
2977             size = parseInt(size);
2978             
2979             $main.css('min-height', size);
2980             if( !nativeScrollbars ) {
2981                 if( ace_scroll ) {
2982                     $main.ace_scroll('update', {'size': size, 'mouseWheelLock': true, 'lockAnyway': true});
2983                 }
2984                 else {
2985                     $main.ace_scroll({'size': size, 'mouseWheelLock': true, 'lockAnyway': true});
2986                 }
2987                 $main.ace_scroll('enable').ace_scroll('reset');
2988             }
2989             else {
2990                 if( ace_scroll ) $main.ace_scroll('disable');
2991                 $main.css('max-height', size).addClass('overflow-scroll');
2992             }
2993             
2994             
2995             $(window)
2996             .on('resize.widget.scroll', function() {
2997                 var size = $widget.height() - $widget.find('.widget-header').height() - 10;//extra paddings
2998                 size = parseInt(size);
2999                 
3000                 $main.css('min-height', size);
3001                 if( !nativeScrollbars ) {
3002                     $main.ace_scroll('update', {'size': size}).ace_scroll('reset');
3003                 }
3004                 else {
3005                     $main.css('max-height', size).addClass('overflow-scroll');
3006                 }
3007             });
3008         }
3009         
3010         else  {
3011             $main.css('min-height', '');
3012             var saved_scroll = $main.data('save_scroll');
3013             if(saved_scroll) {
3014                 $main
3015                 .ace_scroll('update', {'size': saved_scroll['size'], 'mouseWheelLock': saved_scroll['lock'], 'lockAnyway': saved_scroll['lock_anyway']})
3016                 .ace_scroll('enable')
3017                 .ace_scroll('reset');
3018             }
3019             
3020             if( !nativeScrollbars ) {                
3021                 if(!saved_scroll) $main.ace_scroll('disable');                
3022             }
3023             else {
3024                 $main.css('max-height', '').removeClass('overflow-scroll');
3025             }
3026         }
3027     }
3028
3029 })(window.jQuery);;/**
3030  <b>Settings box</b>. It's good for demo only. You don't need this.
3031 */
3032 (function($ , undefined) {
3033
3034  $('#ace-settings-btn').on(ace.click_event, function(e){
3035     e.preventDefault();
3036
3037     $(this).toggleClass('open');
3038     $('#ace-settings-box').toggleClass('open');
3039  })
3040
3041  $('#ace-settings-navbar').on('click', function(){
3042     ace.settingFunction.navbar_fixed(null, this.checked);
3043  })
3044
3045  $('#ace-settings-sidebar').on('click', function(){
3046     ace.settingFunction.sidebar_fixed(null, this.checked);
3047  })
3048
3049  $('#ace-settings-breadcrumbs').on('click', function(){
3050     ace.settingFunction.breadcrumbs_fixed(null, this.checked);
3051  })
3052
3053  $('#ace-settings-add-container').on('click', function(){
3054     ace.settingFunction.main_container_fixed(null, this.checked);
3055  })
3056
3057
3058
3059  $('#ace-settings-compact').on('click', function(){
3060     if(this.checked) {
3061         $('#sidebar').addClass('compact');
3062         var hover = $('#ace-settings-hover');
3063         if( hover.length > 0 ) {
3064             hover.removeAttr('checked').trigger('click');
3065         }
3066     }
3067     else {
3068         $('#sidebar').removeClass('compact');
3069         $('#sidebar[data-sidebar-scroll=true]').ace_sidebar_scroll('reset')
3070     }
3071     
3072     if(ace.vars['old_ie']) ace.helper.redraw($('#sidebar')[0], true);
3073  })
3074
3075
3076  $('#ace-settings-highlight').on('click', function(){
3077     if(this.checked) $('#sidebar .nav-list > li').addClass('highlight');
3078     else $('#sidebar .nav-list > li').removeClass('highlight');
3079     
3080     if(ace.vars['old_ie']) ace.helper.redraw($('#sidebar')[0]);
3081  })
3082
3083
3084  $('#ace-settings-hover').on('click', function(){
3085     if($('#sidebar').hasClass('h-sidebar')) return;
3086     if(this.checked) {
3087         $('#sidebar li').addClass('hover')
3088         .filter('.open').removeClass('open').find('> .submenu').css('display', 'none');
3089         //and remove .open items
3090     }
3091     else {
3092         $('#sidebar li.hover').removeClass('hover');
3093
3094         var compact = $('#ace-settings-compact');
3095         if( compact.length > 0 && compact.get(0).checked ) {
3096             compact.trigger('click');
3097         }
3098     }
3099     
3100     $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('reset')
3101     $('.sidebar[data-sidebar-scroll=true]').ace_sidebar_scroll('reset')
3102     
3103     if(ace.vars['old_ie']) ace.helper.redraw($('#sidebar')[0]);
3104  })
3105
3106  
3107  
3108  //these are only for Ace demo! 
3109  //we want to save only important states(sidebar-fixed and sidebar-collapsed) so before fixing sidebar or collpasing it, hide mobile menu or remove extra classes!
3110  //and then save class name, etc to localStorage for later retrieval
3111  
3112  /**
3113  $(document).on('presettings.ace', function(ev, event_name, event_val, event_source, save_state) {
3114     if( !save_state ) return false;
3115     
3116     var $event_name = event_name;
3117     if( (event_name == 'sidebar_fixed' || event_name == 'sidebar_collapsed') ) {
3118         var sidebar = event_source ? $(event_source) : $('#sidebar');
3119         var tmpClassName = sidebar.attr('class');
3120         sidebar.attr('class', event_name == 'sidebar_fixed' ? 'sidebar-fixed' : 'menu-min');//don't save these classes in demo
3121     
3122         //we don't use 'one' because other 'settings.ace' events could be triggered before the 'sidebar_*' one!
3123         $(document).on('settings.ace.sidebar', function(ev, event_name) {
3124             if( (event_name == $event_name) ) {
3125                 sidebar.addClass(tmpClassName);
3126                 $(document).off('settings.ace.sidebar');
3127             }
3128         });
3129     }
3130     else if( (event_name == 'navbar_fixed') ) {
3131         var navbar = event_source ? $(event_source) : $('#navbar');
3132         var tmpClassName = navbar.attr('class');
3133         navbar.attr('class', 'navbar-fixed-top');//don't save these classes in demo
3134     
3135         //we don't use 'one' because other 'settings.ace' events could be triggered before the 'sidebar_*' one!
3136         $(document).on('settings.ace.navbar', function(ev, event_name) {
3137             if( (event_name == $event_name) ) {
3138                 navbar.addClass(tmpClassName);
3139                 $(document).off('settings.ace.navbar');
3140             }
3141         });
3142     }
3143
3144  });
3145  */
3146
3147
3148  //check/uncheck the checkbox in settings box
3149  var checkbox = this;
3150  $(document).on('settings.ace', function(ev, event_name, event_val, event_source, save_state) {
3151     var checkbox = '';
3152     switch(event_name) {
3153         case 'navbar_fixed':
3154             checkbox = 'ace-settings-navbar';
3155         break;
3156         
3157         case 'sidebar_fixed':
3158             checkbox = 'ace-settings-sidebar';
3159         break;
3160         
3161         case 'breadcrumbs_fixed':
3162             checkbox = 'ace-settings-breadcrumbs';
3163         break;
3164         
3165         case 'main_container_fixed':
3166             checkbox = 'ace-settings-add-container';
3167         break;
3168     }
3169     
3170     if( checkbox && (checkbox = document.getElementById(checkbox)) ) {
3171         $(checkbox).prop('checked', event_val);
3172
3173         try {
3174             if(save_state == true) ace.settings.saveState(checkbox, 'checked');
3175         } catch(e) {}
3176     }
3177  });
3178
3179
3180   ////
3181   ace.settingFunction = {
3182     navbar_fixed : function(navbar, fixed , save, chain) {
3183         if(ace.vars['very_old_ie']) return false;
3184         
3185         var navbar = navbar || '#navbar';
3186         if(typeof navbar === 'string') navbar = $(navbar).get(0);
3187         if(!navbar) return false;
3188     
3189         var fixed = fixed || false;
3190         var save = typeof save !== 'undefined' ? save : true;
3191         
3192
3193         var event;
3194         $(document).trigger(event = $.Event('presettings.ace'), ['navbar_fixed' , fixed , navbar, save]);
3195         if (event.isDefaultPrevented()) {
3196             return false;
3197         }
3198
3199     
3200         if(chain !== false && !fixed) {
3201             //unfix sidebar as well
3202             var sidebar = $('#sidebar');
3203             if(sidebar.hasClass('sidebar-fixed')) {
3204                 ace.settingFunction.sidebar_fixed(sidebar.get(0), false, save);
3205             }
3206         }
3207
3208         if(fixed) {
3209             $(navbar).addClass('navbar-fixed-top');
3210         } else {
3211             $(navbar).removeClass('navbar-fixed-top');
3212         }
3213
3214         if(save) {
3215             ace.settings.saveState(navbar, 'class', 'navbar-fixed-top', fixed);//the 'last' boolean means whether to append this classname or to remove it from previous value            
3216         }
3217
3218         $(document).trigger('settings.ace', ['navbar_fixed' , fixed , navbar, save]);
3219     },
3220
3221
3222     sidebar_fixed : function(sidebar, fixed , save, chain) {
3223         if(ace.vars['very_old_ie']) return false;
3224         
3225         var sidebar = sidebar || '#sidebar';
3226         if(typeof sidebar === 'string') sidebar = $(sidebar).get(0);
3227         if(!sidebar) return false;
3228         
3229
3230         var fixed = fixed || false;
3231         var save = typeof save !== 'undefined' ? save : true;
3232         
3233         
3234         var event;
3235         $(document).trigger(event = $.Event('presettings.ace'), ['sidebar_fixed' , fixed , sidebar, save]);
3236         if (event.isDefaultPrevented()) {
3237             return false;
3238         }
3239         
3240         
3241         if(chain !== false) {
3242             if(fixed) {
3243                 //fix navbar as well
3244                 ace.settingFunction.navbar_fixed(null, true, save);
3245             }
3246
3247             else {
3248                 //unfix breadcrumbs as well
3249                 ace.settingFunction.breadcrumbs_fixed(null, false, save);
3250             }
3251         }
3252
3253         var toggler = $('#menu-toggler');
3254         if(fixed) {
3255             $(sidebar).addClass('sidebar-fixed');
3256             toggler.addClass('fixed');
3257         } else {
3258             $(sidebar).removeClass('sidebar-fixed');
3259             toggler.removeClass('fixed');
3260         }
3261         
3262         if( save ) {
3263             ace.settings.saveState(sidebar, 'class', 'sidebar-fixed', fixed);//the 'last' boolean means whether to append this classname or to remove it from previous value
3264             if(toggler.length != 0) ace.settings.saveState(toggler[0], 'class', 'fixed', fixed);
3265         }
3266
3267         $(document).trigger('settings.ace', ['sidebar_fixed' , fixed , sidebar, save]);
3268     },
3269     
3270     //fixed position
3271     breadcrumbs_fixed : function(breadcrumbs, fixed , save, chain) {
3272         if(ace.vars['very_old_ie']) return false;
3273
3274         var breadcrumbs = breadcrumbs || '#breadcrumbs';
3275         if(typeof breadcrumbs === 'string') breadcrumbs = $(breadcrumbs).get(0);
3276         if(!breadcrumbs) return false;
3277     
3278         var fixed = fixed || false;
3279         var save = typeof save !== 'undefined' ? save : true;
3280         
3281         
3282         var event;
3283         $(document).trigger(event = $.Event('presettings.ace'), ['breadcrumbs_fixed' , fixed , breadcrumbs, save]);
3284         if (event.isDefaultPrevented()) {
3285             return false;
3286         }
3287         
3288         
3289         if(fixed && chain !== false) {
3290             //fix sidebar and navbar as well
3291             ace.settingFunction.sidebar_fixed(null, true, save);
3292         }
3293
3294         if(fixed) {
3295             $(breadcrumbs).addClass('breadcrumbs-fixed');
3296         } else {
3297             $(breadcrumbs).removeClass('breadcrumbs-fixed');
3298         }
3299         
3300         if( save ) {
3301             ace.settings.saveState(breadcrumbs, 'class', 'breadcrumbs-fixed', fixed);
3302         }
3303
3304         $(document).trigger('settings.ace', ['breadcrumbs_fixed' , fixed , breadcrumbs, save]);
3305     },
3306
3307     //fixed size
3308     main_container_fixed : function(main_container, fixed , save) {
3309         if(ace.vars['very_old_ie']) return false;
3310         
3311         var fixed = fixed || false;//fixed width? inside .container
3312         var save = typeof save !== 'undefined' ? save : true;
3313         
3314         var main_container = main_container || '#main-container';
3315         if(typeof main_container === 'string') main_container = $(main_container).get(0);
3316         if(!main_container) return false;
3317         
3318         
3319         var event;
3320         $(document).trigger(event = $.Event('presettings.ace'), ['main_container_fixed' , fixed , main_container, save]);
3321         if (event.isDefaultPrevented()) {
3322             return false;
3323         }
3324         
3325         
3326         var navbar_container = $('#navbar-container');
3327         if(fixed) {
3328             $(main_container).addClass('container');
3329             $(navbar_container).addClass('container');
3330         } else {
3331             $(main_container).removeClass('container');
3332             $(navbar_container).removeClass('container');
3333         }
3334
3335         
3336         if( save ) {
3337             ace.settings.saveState(main_container, 'class', 'container', fixed);
3338             if(navbar_container.length != 0) ace.settings.saveState(navbar_container[0], 'class', 'container', fixed);
3339         }
3340
3341         
3342         if(navigator.userAgent.match(/webkit/i)) {
3343             //webkit has a problem redrawing and moving around the sidebar background in realtime
3344             //so we do this, to force redraw
3345             //there will be no problems with webkit if the ".container" class is statically put inside HTML code.
3346             $('#sidebar').toggleClass('menu-min')
3347             setTimeout(function() {    $('#sidebar').toggleClass('menu-min') } , 10)
3348         }
3349         
3350         $(document).trigger('settings.ace', ['main_container_fixed', fixed, main_container, save]);
3351     }
3352     /**
3353     ,
3354     sidebar_collapsed : function(sidebar, collapsed , save) {
3355         if(ace.vars['very_old_ie']) return false;
3356
3357         var sidebar = sidebar || '#sidebar';
3358         if(typeof sidebar === 'string') sidebar = $(sidebar).get(0);
3359         if(!sidebar) return false;
3360
3361         var collapsed = collapsed || false;
3362         var save = typeof save !== 'undefined' ? save : true;
3363         
3364         
3365         var event;
3366         $(document).trigger(event = $.Event('presettings.ace'), ['sidebar_collapsed' , collapsed , sidebar, save]);
3367         if (event.isDefaultPrevented()) {
3368             return false;
3369         }
3370         
3371
3372         if(collapsed) {
3373             $('#sidebar').addClass('menu-min');
3374         } else {
3375             $('#sidebar').removeClass('menu-min');
3376         }
3377         
3378         if( save ) {
3379             ace.settings.saveState(sidebar, 'class', 'menu-min', collapsed);//the 'last' boolean means whether to append this classname or to remove it from previous value
3380         }
3381
3382         $(document).trigger('settings.ace', ['sidebar_collapsed' , collapsed, sidebar, save]);
3383     }
3384     */
3385   }
3386
3387
3388 })(jQuery);;/**
3389 <b>RTL</b> (right-to-left direction for Arabic, Hebrew, Persian languages).
3390 It's good for demo only.
3391 You should hard code RTL-specific changes inside your HTML/server-side code.
3392 Dynamically switching to RTL using Javascript is not a good idea.
3393 Please refer to documentation for more info.
3394 */
3395
3396
3397 (function($ , undefined) {
3398  //Switching to RTL (right to left) Mode
3399  $('#ace-settings-rtl').removeAttr('checked').on('click', function(){
3400     switch_direction();
3401  });
3402  
3403  
3404  //>>> you should hard code changes inside HTML for RTL direction
3405  //you shouldn't use this function to switch direction
3406  //this is only for dynamically switching for Ace's demo
3407  //take a look at this function to see what changes should be made
3408  //also take a look at docs for some tips
3409  var switch_direction = function() {
3410     if($('#ace-rtl-stylesheet').length == 0) {
3411         //let's load RTL stylesheet only when needed!
3412         var ace_style = $('head').find('link.ace-main-stylesheet');
3413         if(ace_style.length == 0) {
3414             ace_style = $('head').find('link[href*="/ace.min.css"],link[href*="/ace-part2.min.css"]');
3415             if(ace_style.length == 0) {
3416                 ace_style = $('head').find('link[href*="/ace.css"],link[href*="/ace-part2.css"]');
3417             }
3418         }
3419         
3420         var ace_skins = $('head').find('link#ace-skins-stylesheet');
3421         var stylesheet_url = ace_style.first().attr('href').replace(/(\.min)?\.css$/i , '-rtl$1.css');
3422         $.ajax({
3423             'url': stylesheet_url
3424         }).done(function() {
3425             var new_link = jQuery('<link />', {type : 'text/css', rel: 'stylesheet', 'id': 'ace-rtl-stylesheet'})
3426             if(ace_skins.length > 0) {
3427                 new_link.insertAfter(ace_skins);
3428             }
3429             else if(ace_style.length > 0){
3430                 new_link.insertAfter(ace_style.last());
3431             }
3432             else new_link.appendTo('head');
3433         
3434             new_link.attr('href', stylesheet_url);
3435             //we set "href" after insertion, for IE to work
3436             
3437             applyChanges();
3438             if(window.Pace && Pace.running)    Pace.stop();
3439         })        
3440     }
3441     else {
3442         applyChanges();
3443     }
3444     
3445     //in ajax when new content is loaded, we dynamically apply RTL changes again
3446     //please note that this is only for Ace demo
3447     //for info about RTL see Ace's docs
3448     $('.page-content-area[data-ajax-content=true]').on('ajaxscriptsloaded.rtl', function() {
3449         if( $('body').hasClass('rtl') ) {
3450             applyChanges(this);
3451         }
3452     });
3453
3454     /////////////////////////
3455     function applyChanges(el) {
3456         var $body = $(document.body);
3457         if(!el) $body.toggleClass('rtl');//el is 'body'
3458
3459         el = el || document.body;        
3460         var $container = $(el);
3461         $container
3462         //toggle pull-right class on dropdown-menu
3463         .find('.dropdown-menu:not(.datepicker-dropdown,.colorpicker)').toggleClass('dropdown-menu-right')
3464         .end()
3465         //swap pull-left & pull-right
3466         .find('.pull-right:not(.dropdown-menu,blockquote,.profile-skills .pull-right)').removeClass('pull-right').addClass('tmp-rtl-pull-right')
3467         .end()
3468         .find('.pull-left:not(.dropdown-submenu,.profile-skills .pull-left)').removeClass('pull-left').addClass('pull-right')
3469         .end()
3470         .find('.tmp-rtl-pull-right').removeClass('tmp-rtl-pull-right').addClass('pull-left')
3471         .end()
3472         
3473         .find('.chosen-select').toggleClass('chosen-rtl').next().toggleClass('chosen-rtl');
3474         
3475
3476         function swap_classes(class1, class2) {
3477             $container
3478              .find('.'+class1).removeClass(class1).addClass('tmp-rtl-'+class1)
3479              .end()
3480              .find('.'+class2).removeClass(class2).addClass(class1)
3481              .end()
3482              .find('.tmp-rtl-'+class1).removeClass('tmp-rtl-'+class1).addClass(class2)
3483         }
3484
3485         swap_classes('align-left', 'align-right');
3486         swap_classes('no-padding-left', 'no-padding-right');
3487         swap_classes('arrowed', 'arrowed-right');
3488         swap_classes('arrowed-in', 'arrowed-in-right');
3489         swap_classes('tabs-left', 'tabs-right');
3490         swap_classes('messagebar-item-left', 'messagebar-item-right');//for inbox page
3491         
3492         $('.modal.aside-vc').ace_aside('flip').ace_aside('insideContainer');
3493         
3494         
3495         //mirror all icons and attributes that have a "fa-*-right|left" attrobute
3496         $container.find('.fa').each(function() {
3497             if(this.className.match(/ui-icon/) || $(this).closest('.fc-button').length > 0) return;
3498             //skip mirroring icons of plugins that have built in RTL support
3499
3500             var l = this.attributes.length;
3501             for(var i = 0 ; i < l ; i++) {
3502                 var val = this.attributes[i].value;
3503                 if(val.match(/fa\-(?:[\w\-]+)\-left/)) 
3504                     this.attributes[i].value = val.replace(/fa\-([\w\-]+)\-(left)/i , 'fa-$1-right')
3505                  else if(val.match(/fa\-(?:[\w\-]+)\-right/)) 
3506                     this.attributes[i].value = val.replace(/fa\-([\w\-]+)\-(right)/i , 'fa-$1-left')
3507             }
3508         });
3509         
3510         //browsers are incosistent with horizontal scroll and RTL
3511         //so let's make our scrollbars LTR and wrap the content inside RTL
3512         var rtl = $body.hasClass('rtl');
3513         if(rtl)    {
3514             $container.find('.scroll-hz').addClass('make-ltr')
3515             .find('.scroll-content')
3516             .wrapInner('<div class="make-rtl" />');
3517             $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('changeDir', 'right');
3518         }
3519         else {
3520             //remove the wrap
3521             $container.find('.scroll-hz').removeClass('make-ltr')
3522             .find('.make-rtl').children().unwrap();
3523             $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('changeDir', 'left');
3524         }
3525         if($.fn.ace_scroll) $container.find('.scroll-hz').ace_scroll('reset') //to reset scrollLeft
3526
3527         //redraw the traffic pie chart on homepage with a different parameter
3528         try {
3529             var placeholder = $('#piechart-placeholder');
3530             if(placeholder.length > 0) {
3531                 var pos = $body.hasClass('rtl') ? 'nw' : 'ne';//draw on north-west or north-east?
3532                 placeholder.data('draw').call(placeholder.get(0) , placeholder, placeholder.data('chart'), pos);
3533             }
3534         }catch(e) {}
3535         
3536         
3537         ace.helper.redraw(el, true);
3538     }
3539  }
3540 })(jQuery);
3541
3542
3543 ;/**
3544  <b>Select a different skin</b>. It's good for demo only.
3545  You should hard code skin-specific changes inside your HTML/server-side code.
3546  Please refer to documentation for more info.
3547 */
3548
3549 (function($ , undefined) {
3550   try {
3551     $('#skin-colorpicker').ace_colorpicker({'auto_pos': false});
3552   } catch(e) {}
3553
3554   $('#skin-colorpicker').on('change', function(){
3555     var skin_class = $(this).find('option:selected').data('skin');
3556
3557     if($('#ace-skins-stylesheet').length == 0) {
3558         //let's load skins stylesheet only when needed!
3559         var ace_style = $('head').find('link.ace-main-stylesheet');
3560         if(ace_style.length == 0) {
3561             ace_style = $('head').find('link[href*="/ace.min.css"],link[href*="/ace-part2.min.css"]');
3562             if(ace_style.length == 0) {
3563                 ace_style = $('head').find('link[href*="/ace.css"],link[href*="/ace-part2.css"]');
3564             }
3565         }
3566         
3567         var stylesheet_url = ace_style.first().attr('href').replace(/(\.min)?\.css$/i , '-skins$1.css');
3568         $.ajax({
3569             'url': stylesheet_url
3570         }).done(function() {
3571             var new_link = jQuery('<link />', {type : 'text/css', rel: 'stylesheet', 'id': 'ace-skins-stylesheet'})
3572             if(ace_style.length > 0){
3573                 new_link.insertAfter(ace_style.last());
3574             }
3575             else new_link.appendTo('head');
3576     
3577             new_link.attr('href', stylesheet_url);
3578             //we set "href" after insertion, for IE to work
3579             
3580             applyChanges(skin_class);
3581             if(window.Pace && Pace.running)    Pace.stop();
3582         })
3583     }
3584     else {
3585         applyChanges(skin_class);
3586     }
3587
3588
3589     function applyChanges(skin_class) {
3590         //skin cookie tip
3591         var body = $(document.body);
3592         body.removeClass('no-skin skin-1 skin-2 skin-3');
3593         //if(skin_class != 'skin-0') {
3594             body.addClass(skin_class);
3595             ace.data.set('skin', skin_class);
3596             //save the selected skin to cookies
3597             //which can later be used by your server side app to set the skin
3598             //for example: <body class="<?php echo $_COOKIE['ace_skin']; ?>"
3599         //} else ace.data.remove('skin');
3600         
3601         var skin3_colors = ['red', 'blue', 'green', ''];
3602
3603         
3604             //undo skin-1
3605             $('.ace-nav > li.grey').removeClass('dark');
3606             
3607             //undo skin-2
3608             $('.ace-nav > li').removeClass('no-border margin-1');
3609             $('.ace-nav > li:not(:last-child)').removeClass('light-pink').find('> a > '+ace.vars['.icon']).removeClass('pink').end().eq(0).find('.badge').removeClass('badge-warning');
3610             $('.sidebar-shortcuts .btn')
3611             .removeClass('btn-pink btn-white')
3612             .find(ace.vars['.icon']).removeClass('white');
3613             
3614             //undo skin-3
3615             $('.ace-nav > li.grey').removeClass('red').find('.badge').removeClass('badge-yellow');
3616             $('.sidebar-shortcuts .btn').removeClass('btn-primary btn-white')
3617             var i = 0;
3618             $('.sidebar-shortcuts .btn').each(function() {
3619                 $(this).find(ace.vars['.icon']).removeClass(skin3_colors[i++]);
3620             })
3621         
3622         
3623
3624         
3625         var skin0_buttons = ['btn-success', 'btn-info', 'btn-warning', 'btn-danger'];
3626         if(skin_class == 'no-skin') {
3627             var i = 0;
3628             $('.sidebar-shortcuts .btn').each(function() {
3629                 $(this).attr('class', 'btn ' + skin0_buttons[i++%4]);
3630             })
3631             
3632             $('.sidebar[data-sidebar-scroll=true]').ace_sidebar_scroll('updateStyle', '');
3633             $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('updateStyle', 'no-track scroll-thin');
3634         }
3635
3636         else if(skin_class == 'skin-1') {
3637             $('.ace-nav > li.grey').addClass('dark');
3638             var i = 0;
3639             $('.sidebar-shortcuts')
3640             .find('.btn').each(function() {
3641                 $(this).attr('class', 'btn ' + skin0_buttons[i++%4]);
3642             })
3643             
3644             $('.sidebar[data-sidebar-scroll=true]').ace_sidebar_scroll('updateStyle', 'scroll-white no-track');
3645             $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('updateStyle', 'no-track scroll-thin scroll-white');
3646         }
3647
3648         else if(skin_class == 'skin-2') {
3649             $('.ace-nav > li').addClass('no-border margin-1');
3650             $('.ace-nav > li:not(:last-child)').addClass('light-pink').find('> a > '+ace.vars['.icon']).addClass('pink').end().eq(0).find('.badge').addClass('badge-warning');
3651             
3652             $('.sidebar-shortcuts .btn').attr('class', 'btn btn-white btn-pink')
3653             .find(ace.vars['.icon']).addClass('white');
3654             
3655             $('.sidebar[data-sidebar-scroll=true]').ace_sidebar_scroll('updateStyle', 'scroll-white no-track');
3656             $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('updateStyle', 'no-track scroll-thin scroll-white');
3657         }
3658
3659         //skin-3
3660         //change shortcut buttons classes, this should be hard-coded if you want to choose this skin
3661         else if(skin_class == 'skin-3') {
3662             body.addClass('no-skin');//because skin-3 has many parts of no-skin as well
3663             
3664             $('.ace-nav > li.grey').addClass('red').find('.badge').addClass('badge-yellow');
3665             
3666             var i = 0;
3667             $('.sidebar-shortcuts .btn').each(function() {
3668                 $(this).attr('class', 'btn btn-primary btn-white');
3669                 $(this).find(ace.vars['.icon']).addClass(skin3_colors[i++]);
3670             })
3671             
3672             $('.sidebar[data-sidebar-scroll=true]').ace_sidebar_scroll('updateStyle', 'scroll-dark no-track');
3673             $('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('updateStyle', 'no-track scroll-thin');
3674         }
3675
3676         //some sizing differences may be there in skins, so reset scrollbar size
3677         $('.sidebar[data-sidebar-scroll=true]').ace_sidebar_scroll('reset')
3678         //$('.sidebar[data-sidebar-hover=true]').ace_sidebar_hover('reset')
3679         
3680         if(ace.vars['old_ie']) ace.helper.redraw(document.body, true);
3681     }
3682
3683  })
3684 })(jQuery);;/**
3685  The widget box reload button/event handler. You should use your own handler. An example is available at <i class="text-info">examples/widgets.html</i>.
3686  <u><i class="glyphicon glyphicon-flash"></i> You don't need this. Used for demo only</u>
3687 */
3688
3689 (function($ , undefined) {
3690
3691     //***default action for reload in this demo
3692     //you should remove this and add your own handler for each specific .widget-box
3693     //when data is finished loading or processing is done you can call $box.trigger('reloaded.ace.widget')
3694     $(document).on('reload.ace.widget', '.widget-box', function (ev) {
3695         var $box = $(this);
3696         
3697         //trigger the reloaded event to remove the spinner icon after 1-2 seconds
3698         setTimeout(function() {
3699             $box.trigger('reloaded.ace.widget');
3700         }, parseInt(Math.random() * 1000 + 1000));
3701     });
3702
3703     //you may want to do something like this:
3704     /**
3705     $('#my-widget-box').on('reload.ace.widget', function(){
3706         //load new data here
3707         //and when finished trigger "reloaded" event
3708         $(this).trigger('reloaded.ace.widget');
3709     });
3710     */
3711 })(window.jQuery);;/**
3712 The autocomplete dropdown when typing inside search box.
3713 <u><i class="glyphicon glyphicon-flash"></i> You don't need this. Used for demo only</u>
3714 */
3715 (function($ , undefined) {
3716
3717     ace.vars['US_STATES'] = ["Alabama","Alaska","Arizona","Arkansas","California","Colorado","Connecticut","Delaware","Florida","Georgia","Hawaii","Idaho","Illinois","Indiana","Iowa","Kansas","Kentucky","Louisiana","Maine","Maryland","Massachusetts","Michigan","Minnesota","Mississippi","Missouri","Montana","Nebraska","Nevada","New Hampshire","New Jersey","New Mexico","New York","North Dakota","North Carolina","Ohio","Oklahoma","Oregon","Pennsylvania","Rhode Island","South Carolina","South Dakota","Tennessee","Texas","Utah","Vermont","Virginia","Washington","West Virginia","Wisconsin","Wyoming"]
3718     try {
3719         $('#nav-search-input').bs_typeahead({
3720             source: ace.vars['US_STATES'],
3721             updater:function (item) {
3722                 //when an item is selected from dropdown menu, focus back to input element
3723                 $('#nav-search-input').focus();
3724                 return item;
3725             }
3726         });
3727     } catch(e) {}
3728
3729 })(window.jQuery);