/*! * Ace v1.3.2 */ if (typeof jQuery === 'undefined') { throw new Error('Ace\'s JavaScript requires jQuery') } /** Required. Ace's Basic File to Initiliaze Different Parts and Some Variables. */ (function($ , undefined) { if( !('ace' in window) ) window['ace'] = {} if( !('helper' in window['ace']) ) window['ace'].helper = {} if( !('vars' in window['ace']) ) window['ace'].vars = {} window['ace'].vars['icon'] = ' ace-icon '; window['ace'].vars['.icon'] = '.ace-icon'; ace.vars['touch'] = ('ontouchstart' in document.documentElement);//(('ontouchstart' in document.documentElement) || (window.DocumentTouch && document instanceof DocumentTouch)); //sometimes we try to use 'tap' event instead of 'click' if jquery mobile plugin is available ace['click_event'] = ace.vars['touch'] && $.fn.tap ? 'tap' : 'click'; //sometimes the only good way to work around browser's pecularities is to detect them using user-agents //though it's not accurate var agent = navigator.userAgent ace.vars['webkit'] = !!agent.match(/AppleWebKit/i) ace.vars['safari'] = !!agent.match(/Safari/i) && !agent.match(/Chrome/i); ace.vars['android'] = ace.vars['safari'] && !!agent.match(/Android/i) ace.vars['ios_safari'] = !!agent.match(/OS ([4-9])(_\d)+ like Mac OS X/i) && !agent.match(/CriOS/i) ace.vars['ie'] = window.navigator.msPointerEnabled || (document.all && document.querySelector);//8-11 ace.vars['old_ie'] = document.all && !document.addEventListener;//8 and below ace.vars['very_old_ie'] = document.all && !document.querySelector;//7 and below ace.vars['firefox'] = 'MozAppearance' in document.documentElement.style; ace.vars['non_auto_fixed'] = ace.vars['android'] || ace.vars['ios_safari']; })(jQuery); jQuery(function($) { basics(); enableSidebar(); enableAjax(); handleScrollbars(); dropdownAutoPos(); navbarHelpers(); sidebarTooltips(); scrollTopBtn(); someBrowserFix(); bsCollapseToggle(); smallDeviceDropdowns(); //////////////////////////// function basics() { // for android and ios we don't use "top:auto" when breadcrumbs is fixed if(ace.vars['non_auto_fixed']) { $('body').addClass('mob-safari'); } ace.vars['transition'] = !!$.support.transition.end } function enableSidebar() { //initiate sidebar function var $sidebar = $('.sidebar'); if($.fn.ace_sidebar) $sidebar.ace_sidebar(); if($.fn.ace_sidebar_scroll) $sidebar.ace_sidebar_scroll({ //'scroll_style': 'scroll-dark scroll-thin', 'scroll_to_active': true, //scroll to selected item? (one time only on page load) 'include_shortcuts': true, //true = include shortcut buttons in the scrollbars 'include_toggle': false || ace.vars['safari'] || ace.vars['ios_safari'], //true = include toggle button in the scrollbars 'smooth_scroll': 150, //> 0 means smooth_scroll, time in ms, used in first approach only, better to be almost half the amount of submenu transition time 'outside': false//true && ace.vars['touch'] //used in first approach only, true means the scrollbars should be outside of the sidebar }); if($.fn.ace_sidebar_hover) $sidebar.ace_sidebar_hover({ 'sub_hover_delay': 750, 'sub_scroll_style': 'no-track scroll-thin scroll-margin scroll-visible' }); } function enableAjax() { //Load content via ajax if($.fn.ace_ajax) { $('[data-ajax-content=true]').ace_ajax({ 'close_active': true, 'content_url': function(hash) { //***NOTE*** //this is for Ace demo only, you should change it to return a valid URL //please refer to documentation for more info if( !hash.match(/^page\//) ) return false; var path = document.location.pathname; //for example in Ace HTML demo version we convert /ajax/ajax.html#page/gallery to > /ajax/gallery.html and load it if(path.match(/(\/ajax\/)(ajax\.html)?/)) return path.replace(/(\/ajax\/)(ajax\.html)?/, '/ajax/'+hash.replace(/^page\//, '')+'.html') ; //for example in Ace PHP demo version we convert "ajax.php#page/dashboard" to "ajax.php?page=dashboard" and load it return path + "?" + hash.replace(/\//, "="); }, 'default_url': 'page/index'//default hash }) } } ///////////////////////////// function handleScrollbars() { //add scrollbars for navbar dropdowns var has_scroll = !!$.fn.ace_scroll; if(has_scroll) $('.dropdown-content').ace_scroll({reset: false, mouseWheelLock: true}) //reset scrolls bars on window resize if(has_scroll && !ace.vars['old_ie']) {//IE has an issue with widget fullscreen on ajax?!!! $(window).on('resize.reset_scroll', function() { $('.ace-scroll:not(.scroll-disabled)').not(':hidden').ace_scroll('reset'); }); if(has_scroll) $(document).on('settings.ace.reset_scroll', function(e, name) { if(name == 'sidebar_collapsed') $('.ace-scroll:not(.scroll-disabled)').not(':hidden').ace_scroll('reset'); }); } } function dropdownAutoPos() { //change a dropdown to "dropup" depending on its position $(document).on('click.dropdown.pos', '.dropdown-toggle[data-position="auto"]', function() { var offset = $(this).offset(); var parent = $(this.parentNode); if ( parseInt(offset.top + $(this).height()) + 50 > (ace.helper.scrollTop() + ace.helper.winHeight() - parent.find('.dropdown-menu').eq(0).height()) ) parent.addClass('dropup'); else parent.removeClass('dropup'); }); } function navbarHelpers() { //prevent dropdowns from hiding when a from is clicked /**$(document).on('click', '.dropdown-navbar form', function(e){ e.stopPropagation(); });*/ //disable navbar icon animation upon click $('.ace-nav [class*="icon-animated-"]').closest('a').one('click', function(){ var icon = $(this).find('[class*="icon-animated-"]').eq(0); var $match = icon.attr('class').match(/icon\-animated\-([\d\w]+)/); icon.removeClass($match[0]); }); //prevent dropdowns from hiding when a tab is selected $(document).on('click', '.dropdown-navbar .nav-tabs', function(e){ e.stopPropagation(); var $this , href var that = e.target if( ($this = $(e.target).closest('[data-toggle=tab]')) && $this.length > 0) { $this.tab('show'); e.preventDefault(); $(window).triggerHandler('resize.navbar.dropdown') } }); } function sidebarTooltips() { //tooltip in sidebar items $('.sidebar .nav-list .badge[title],.sidebar .nav-list .badge[title]').each(function() { var tooltip_class = $(this).attr('class').match(/tooltip\-(?:\w+)/); tooltip_class = tooltip_class ? tooltip_class[0] : 'tooltip-error'; $(this).tooltip({ 'placement': function (context, source) { var offset = $(source).offset(); if( parseInt(offset.left) < parseInt(document.body.scrollWidth / 2) ) return 'right'; return 'left'; }, container: 'body', template: '
' }); }); //or something like this if items are dynamically inserted /** $('.sidebar').tooltip({ 'placement': function (context, source) { var offset = $(source).offset(); if( parseInt(offset.left) < parseInt(document.body.scrollWidth / 2) ) return 'right'; return 'left'; }, selector: '.nav-list .badge[title],.nav-list .label[title]', container: 'body', template: '
' }); */ } function scrollTopBtn() { //the scroll to top button var scroll_btn = $('.btn-scroll-up'); if(scroll_btn.length > 0) { var is_visible = false; $(window).on('scroll.scroll_btn', function() { var scroll = ace.helper.scrollTop(); var h = ace.helper.winHeight(); var body_sH = document.body.scrollHeight; if(scroll > parseInt(h / 4) || (scroll > 0 && body_sH >= h && h + scroll >= body_sH - 1)) {//|| for smaller pages, when reached end of page if(!is_visible) { scroll_btn.addClass('display'); is_visible = true; } } else { if(is_visible) { scroll_btn.removeClass('display'); is_visible = false; } } }).triggerHandler('scroll.scroll_btn'); scroll_btn.on(ace.click_event, function(){ var duration = Math.min(500, Math.max(100, parseInt(ace.helper.scrollTop() / 3))); $('html,body').animate({scrollTop: 0}, duration); return false; }); } } function someBrowserFix() { //chrome and webkit have a problem here when resizing from 479px to more //we should force them redraw the navbar! if( ace.vars['webkit'] ) { var ace_nav = $('.ace-nav').get(0); if( ace_nav ) $(window).on('resize.webkit_fix' , function(){ ace.helper.redraw(ace_nav); }); } //fix an issue with ios safari, when an element is fixed and an input receives focus if(ace.vars['ios_safari']) { $(document).on('ace.settings.ios_fix', function(e, event_name, event_val) { if(event_name != 'navbar_fixed') return; $(document).off('focus.ios_fix blur.ios_fix', 'input,textarea,.wysiwyg-editor'); if(event_val == true) { $(document).on('focus.ios_fix', 'input,textarea,.wysiwyg-editor', function() { $(window).on('scroll.ios_fix', function() { var navbar = $('#navbar').get(0); if(navbar) ace.helper.redraw(navbar); }); }).on('blur.ios_fix', 'input,textarea,.wysiwyg-editor', function() { $(window).off('scroll.ios_fix'); }) } }).triggerHandler('ace.settings.ios_fix', ['navbar_fixed', $('#navbar').css('position') == 'fixed']); } } function bsCollapseToggle() { //bootstrap collapse component icon toggle $(document).on('hide.bs.collapse show.bs.collapse', function (ev) { var panel_id = ev.target.getAttribute('id') var panel = $('a[href*="#'+ panel_id+'"]'); if(panel.length == 0) panel = $('a[data-target*="#'+ panel_id+'"]'); if(panel.length == 0) return; panel.find(ace.vars['.icon']).each(function(){ var $icon = $(this) var $match var $icon_down = null var $icon_up = null if( ($icon_down = $icon.attr('data-icon-show')) ) { $icon_up = $icon.attr('data-icon-hide') } else if( $match = $icon.attr('class').match(/fa\-(.*)\-(up|down)/) ) { $icon_down = 'fa-'+$match[1]+'-down' $icon_up = 'fa-'+$match[1]+'-up' } if($icon_down) { if(ev.type == 'show') $icon.removeClass($icon_down).addClass($icon_up) else $icon.removeClass($icon_up).addClass($icon_down) return false;//ignore other icons that match, one is enough } }); }) } //in small devices display navbar dropdowns like modal boxes function smallDeviceDropdowns() { if(ace.vars['old_ie']) return; $('.ace-nav > li') .on('shown.bs.dropdown.navbar', function(e) { adjustNavbarDropdown.call(this); }) .on('hidden.bs.dropdown.navbar', function(e) { $(window).off('resize.navbar.dropdown'); resetNavbarDropdown.call(this); }) function adjustNavbarDropdown() { var $sub = $(this).find('> .dropdown-menu'); if( $sub.css('position') == 'fixed' ) { var win_width = parseInt($(window).width()); var offset_w = win_width > 320 ? 60 : (win_width > 240 ? 40 : 30); var avail_width = parseInt(win_width) - offset_w; var avail_height = parseInt($(window).height()) - 30; var width = parseInt(Math.min(avail_width , 320)); //we set 'width' here for text wrappings and spacings to take effect before calculating scrollHeight $sub.css('width', width); var tabbed = false; var extra_parts = 0; var dropdown_content = $sub.find('.tab-pane.active .dropdown-content.ace-scroll'); if(dropdown_content.length == 0) dropdown_content = $sub.find('.dropdown-content.ace-scroll'); else tabbed = true; var parent_menu = dropdown_content.closest('.dropdown-menu'); var scrollHeight = $sub[0].scrollHeight; if(dropdown_content.length == 1) { //sometimes there's no scroll-content, for example in detached scrollbars var content = dropdown_content.find('.scroll-content')[0]; if(content) { scrollHeight = content.scrollHeight; } extra_parts += parent_menu.find('.dropdown-header').outerHeight(); extra_parts += parent_menu.find('.dropdown-footer').outerHeight(); var tab_content = parent_menu.closest('.tab-content'); if( tab_content.length != 0 ) { extra_parts += tab_content.siblings('.nav-tabs').eq(0).height(); } } var height = parseInt(Math.min(avail_height , 480, scrollHeight + extra_parts)); var left = parseInt(Math.abs((avail_width + offset_w - width)/2)); var top = parseInt(Math.abs((avail_height + 30 - height)/2)); var zindex = parseInt($sub.css('z-index')) || 0; $sub.css({'height': height, 'left': left, 'right': 'auto', 'top': top - (!tabbed ? 1 : 3)}); if(dropdown_content.length == 1) { if(!ace.vars['touch']) { dropdown_content.ace_scroll('update', {size: height - extra_parts}).ace_scroll('enable').ace_scroll('reset'); } else { dropdown_content .ace_scroll('disable').css('max-height', height - extra_parts).addClass('overflow-scroll'); } } $sub.css('height', height + (!tabbed ? 2 : 7));//for bottom border adjustment and tab content paddings if($sub.hasClass('user-menu')) { $sub.css('height', '');//because of user-info hiding/showing at different widths, which changes above 'scrollHeight', so we remove it! //user menu is re-positioned in small widths //but we need to re-position again in small heights as well (modal mode) var user_info = $(this).find('.user-info'); if(user_info.length == 1 && user_info.css('position') == 'fixed') { user_info.css({'left': left, 'right': 'auto', 'top': top, 'width': width - 2, 'max-width': width - 2, 'z-index': zindex + 1}); } else user_info.css({'left': '', 'right': '', 'top': '', 'width': '', 'max-width': '', 'z-index': ''}); } //dropdown's z-index is limited by parent .navbar's z-index (which doesn't make sense because dropdowns are fixed!) //so for example when in 'content-slider' page, fixed modal toggle buttons go above are dropdowns //so we increase navbar's z-index to fix this! $(this).closest('.navbar.navbar-fixed-top').css('z-index', zindex); } else { if($sub.length != 0) resetNavbarDropdown.call(this, $sub); } var self = this; $(window) .off('resize.navbar.dropdown') .one('resize.navbar.dropdown', function() { $(self).triggerHandler('shown.bs.dropdown.navbar'); }) } //reset scrollbars and user menu function resetNavbarDropdown($sub) { $sub = $sub || $(this).find('> .dropdown-menu'); if($sub.length > 0) { $sub .css({'width': '', 'height': '', 'left': '', 'right': '', 'top': ''}) .find('.dropdown-content').each(function() { if(ace.vars['touch']) { $(this).css('max-height', '').removeClass('overflow-scroll'); } var size = parseInt($(this).attr('data-size') || 0) || $.fn.ace_scroll.defaults.size; $(this).ace_scroll('update', {size: size}).ace_scroll('enable').ace_scroll('reset'); }) if( $sub.hasClass('user-menu') ) { var user_info = $(this).find('.user-info') .css({'left': '', 'right': '', 'top': '', 'width': '', 'max-width': '', 'z-index': ''}); } } $(this).closest('.navbar').css('z-index', ''); } } }) //some functions ace.helper.redraw = function(elem, force) { var saved_val = elem.style['display']; elem.style.display = 'none'; elem.offsetHeight; if(force !== true) { elem.style.display = saved_val; } else { //force redraw for example in old IE setTimeout(function() { elem.style.display = saved_val; }, 10); } } ace.helper.boolAttr = function(elem, attr) { return elem.getAttribute(attr) === "true"; } ace.helper.intAttr = function(elem, attr) { return parseInt(elem.getAttribute(attr)) || 0; } ace.helper.scrollTop = function() { return document.scrollTop || document.documentElement.scrollTop || document.body.scrollTop //return $(window).scrollTop(); } ace.helper.winHeight = function() { return window.innerHeight || document.documentElement.clientHeight; //return $(window).innerHeight(); } ace.helper.camelCase = function(str) { return str.replace(/-([\da-z])/gi, function(match, chr) { return chr ? chr.toUpperCase() : ''; }); } ace.helper.removeStyle = 'removeProperty' in document.documentElement.style ? function(elem, prop) { elem.style.removeProperty(prop) } : function(elem, prop) { elem.style[ace.helper.camelCase(prop)] = '' } ace.helper.hasClass = 'classList' in document.documentElement ? function(elem, className) { return elem.classList.contains(className); } : function(elem, className) { return elem.className.indexOf(className) > -1; } ;/** Load content via Ajax . For more information please refer to documentation #basics/ajax */ (function($ , undefined) { var ajax_loaded_scripts = {} function AceAjax(contentArea, options) { var $contentArea = $(contentArea); var self = this; var content_url = options.content_url || false var default_url = options.default_url || false; var loading_icon = options.loading_icon || 'fa-spinner fa-2x orange'; var loading_text = options.loading_text || ''; var update_breadcrumbs = options.update_breadcrumbs || options.update_breadcrumbs === undefined; var update_title = options.update_title || options.update_breadcrumbs === undefined; var update_active = options.update_active || options.update_breadcrumbs === undefined; var close_active = options.close_active || false; var max_load_wait = options.max_load_wait || false; var working = false; this.loadUrl = function(hash) { var url = false; hash = hash.replace(/^(\#\!)?\#/, ''); if(typeof content_url === 'function') url = content_url(hash); if(typeof url === 'string') this.getUrl(url, hash, false); } this.getUrl = function(url, hash, manual_trigger) { if(working) { return; } var event $contentArea.trigger(event = $.Event('ajaxloadstart'), {url: url, hash: hash}) if (event.isDefaultPrevented()) return; self.startLoading(); $.ajax({ 'url': url }) .error(function() { $contentArea.trigger('ajaxloaderror', {url: url, hash: hash}); self.stopLoading(true); }) .done(function(result) { $contentArea.trigger('ajaxloaddone', {url: url, hash: hash}); var link_element = null, link_text = '';; if(typeof update_active === 'function') { link_element = update_active.call(null, hash, url); } else if(update_active === true) { link_element = $('a[data-url="'+hash+'"]'); if(link_element.length > 0) { var nav = link_element.closest('.nav'); if(nav.length > 0) { nav.find('.active').each(function(){ var $class = 'active'; if( $(this).hasClass('hover') || close_active ) $class += ' open'; $(this).removeClass($class); if(close_active) { $(this).find(' > .submenu').css('display', ''); } }) var active_li = link_element.closest('li').addClass('active').parents('.nav li').addClass('active open'); nav.closest('.sidebar[data-sidebar-scroll=true]').each(function() { var $this = $(this); $this.ace_sidebar_scroll('reset'); if(manual_trigger) $this.ace_sidebar_scroll('scroll_to_active');//first time only }) } } } ///////// if(typeof update_breadcrumbs === 'function') { link_text = update_breadcrumbs.call(null, hash, url, link_element); } else if(update_breadcrumbs === true && link_element != null && link_element.length > 0) { link_text = updateBreadcrumbs(link_element); } ///////// //convert "title" and "link" tags to "div" tags for later processing result = String(result) .replace(/<(title|link)([\s\>])/gi,'') $contentArea.empty().html(result); $contentArea.css('opacity', 0.6); //remove previous stylesheets inserted via ajax setTimeout(function() { $('head').find('link.ace-ajax-stylesheet').remove(); var main_selectors = ['link.ace-main-stylesheet', 'link#main-ace-style', 'link[href*="/ace.min.css"]', 'link[href*="/ace.css"]'] var ace_style = []; for(var m = 0; m < main_selectors.length; m++) { ace_style = $('head').find(main_selectors[m]).first(); if(ace_style.length > 0) break; } $contentArea.find('.ajax-append-link').each(function(e) { var $link = $(this); if ( $link.attr('href') ) { var new_link = jQuery('', {type : 'text/css', rel: 'stylesheet', 'class': 'ace-ajax-stylesheet'}) if( ace_style.length > 0 ) new_link.insertBefore(ace_style); else new_link.appendTo('head'); new_link.attr('href', $link.attr('href'));//we set "href" after insertion, for IE to work } $link.remove(); }) }, 10); ////////////////////// if(typeof update_title === 'function') { update_title.call(null, hash, url, link_text); } else if(update_title === true) { updateTitle(link_text); } if( !manual_trigger ) { $('html,body').animate({scrollTop: 0}, 250); } ////////////////////// $contentArea.trigger('ajaxloadcomplete', {url: url, hash: hash}); ////////////////////// self.stopLoading(); }) } /////////////////////// var loadTimer = null; this.startLoading = function() { if(working) return; working = true; $contentArea .css('opacity', 0.25) .prevAll('.ajax-loading-overlay').remove(); $('
'+loading_text+'
').insertBefore(contentArea); if(max_load_wait !== false) loadTimer = setTimeout(function() { loadTimer = null; if(!working) return; var event $contentArea.trigger(event = $.Event('ajaxloadlong')) if (event.isDefaultPrevented()) return; self.stopLoading(true); }, max_load_wait * 1000); } this.stopLoading = function(stopNow) { if(stopNow === true) { working = false; $contentArea .css('opacity', 1) .prevAll('.ajax-loading-overlay').remove(); if(loadTimer != null) { clearTimeout(loadTimer); loadTimer = null; } } else { $contentArea.css('opacity', 0.75) $contentArea.one('ajaxscriptsloaded', function() { self.stopLoading(true); }) } } /////////////////////// function updateBreadcrumbs(link_element) { var link_text = ''; //update breadcrumbs var breadcrumbs = $('.breadcrumb'); if(breadcrumbs.length > 0 && breadcrumbs.is(':visible')) { breadcrumbs.find('> li:not(:first-child)').remove(); var i = 0; link_element.parents('.nav li').each(function() { var link = $(this).find('> a'); var link_clone = link.clone(); link_clone.find('i,.fa,.glyphicon,.ace-icon,.menu-icon,.badge,.label').remove(); var text = link_clone.text(); link_clone.remove(); var href = link.attr('href'); if(i == 0) { var li = $('
  • ').appendTo(breadcrumbs); li.text(text); link_text = text; } else { var li = $('
  • ').insertAfter(breadcrumbs.find('> li:first-child')); li.find('a').attr('href', href).text(text); } i++; }) } return link_text; } function updateTitle(link_text) { var $title = $contentArea.find('.ajax-append-title'); if($title.length > 0) { document.title = $title.text(); $title.remove(); } else if(link_text.length > 0) { var extra = $.trim(String(document.title).replace(/^(.*)[\-]/, ''));//for example like " - Ace Admin" if(extra) extra = ' - ' + extra; link_text = $.trim(link_text) + extra; } } this.loadScripts = function(scripts, callback) { $.ajaxPrefilter('script', function(opts) {opts.cache = true}); setTimeout(function() { //let's keep a list of loaded scripts so that we don't load them more than once! function finishLoading() { if(typeof callback === 'function') callback(); $('.btn-group[data-toggle="buttons"] > .btn').button(); $contentArea.trigger('ajaxscriptsloaded'); } //var deferreds = []; var deferred_count = 0;//deferreds count var resolved = 0; for(var i = 0; i < scripts.length; i++) if(scripts[i]) { (function() { var script_name = "js-"+scripts[i].replace(/[^\w\d\-]/g, '-').replace(/\-\-/g, '-'); if( ajax_loaded_scripts[script_name] !== true ) deferred_count++; })() } function nextScript(index) { index += 1; if(index < scripts.length) loadScript(index); else { finishLoading(); } } function loadScript(index) { index = index || 0; if(!scripts[index]) {//could be null sometimes return nextScript(index); } var script_name = "js-"+scripts[index].replace(/[^\w\d\-]/g, '-').replace(/\-\-/g, '-'); //only load scripts that are not loaded yet! if( ajax_loaded_scripts[script_name] !== true ) { $.getScript(scripts[index]) .done(function() { ajax_loaded_scripts[script_name] = true; }) //.fail(function() { //}) .complete(function() { resolved++; if(resolved >= deferred_count && working) { finishLoading(); } else { nextScript(index); } }) } else {//script previoisly loaded nextScript(index); } } if (deferred_count > 0) { loadScript(); } else { finishLoading(); } }, 10) } ///////////////// $(window) .off('hashchange.ace_ajax') .on('hashchange.ace_ajax', function(e, manual_trigger) { var hash = $.trim(window.location.hash); if(!hash || hash.length == 0) return; self.loadUrl(hash); }).trigger('hashchange.ace_ajax', [true]); var hash = $.trim(window.location.hash); if(!hash && default_url) window.location.hash = default_url; }//AceAjax $.fn.aceAjax = $.fn.ace_ajax = function (option, value, value2) { var method_call; var $set = this.each(function () { var $this = $(this); var data = $this.data('ace_ajax'); var options = typeof option === 'object' && option; if (!data) $this.data('ace_ajax', (data = new AceAjax(this, options))); if (typeof option === 'string' && typeof data[option] === 'function') { if(value2 != undefined) method_call = data[option](value, value2); else method_call = data[option](value); } }); return (method_call === undefined) ? $set : method_call; } })(window.jQuery); ;/** Custom drag event for touch devices used in scrollbars. For better touch event handling and extra options a more advanced solution such as Hammer.js is recommended. */ //based on but not dependent on jQuery mobile /* * jQuery Mobile v1.3.2 * http://jquerymobile.com * * Copyright 2010, 2013 jQuery Foundation, Inc. and other contributors * Released under the MIT license. * http://jquery.org/license * */ (function($ , undefined) { if(!ace.vars['touch']) return; var touchStartEvent = "touchstart MSPointerDown pointerdown",// : "mousedown", touchStopEvent = "touchend touchcancel MSPointerUp MSPointerCancel pointerup pointercancel",// : "mouseup", touchMoveEvent = "touchmove MSPointerMove MSPointerHover pointermove";// : "mousemove"; $.event.special.ace_drag = { setup: function() { var min_threshold = 0; var $this = $(this); $this.on(touchStartEvent, function(event) { var data = event.originalEvent.touches ? event.originalEvent.touches[ 0 ] : event, start = { //time: Date.now(), coords: [ data.pageX, data.pageY ], origin: $(event.target) }, stop; //start.origin.trigger({'type' : 'ace_dragStart', 'start':(start || [-1,-1])}); var direction = false, dx = 0, dy = 0; function moveHandler(event) { if (!start) { return; } var data = event.originalEvent.touches ? event.originalEvent.touches[ 0 ] : event; stop = { coords: [ data.pageX, data.pageY ] }; // prevent scrolling //if ( Math.abs(start.coords[1] - stop.coords[1]) > 0 || Math.abs(start.coords[0] - stop.coords[01]) > 0 ) { //event.preventDefault(); //} if (start && stop) { dx = 0; dy = 0; direction = ( Math.abs(dy = start.coords[ 1 ] - stop.coords[ 1 ]) > min_threshold && Math.abs(dx = start.coords[ 0 ] - stop.coords[ 0 ]) <= Math.abs(dy) ) ? (dy > 0 ? 'up' : 'down') : ( Math.abs(dx = start.coords[ 0 ] - stop.coords[ 0 ]) > min_threshold && Math.abs( dy ) <= Math.abs(dx) ) ? (dx > 0 ? 'left' : 'right') : false; if( direction !== false ) { var retval = {cancel: false} start.origin.trigger({ 'type': 'ace_drag', //'start': start.coords, //'stop': stop.coords, 'direction': direction, 'dx': dx, 'dy': dy, 'retval': retval }) // prevent document scrolling unless retval.cancel == true if( retval.cancel == false ) event.preventDefault(); } } start.coords[0] = stop.coords[0]; start.coords[1] = stop.coords[1]; } $this .on(touchMoveEvent, moveHandler) .one(touchStopEvent, function(event) { $this.off(touchMoveEvent, moveHandler); //start.origin.trigger({'type' : 'ace_dragEnd', 'stop':(stop || [-1,-1])}); start = stop = undefined; }); }); } } })(window.jQuery);;/** Sidebar functions. Collapsing/expanding, toggling mobile view menu and other sidebar functions. */ (function($ , undefined) { var sidebar_count = 0; function Sidebar(sidebar, options) { var self = this; this.$sidebar = $(sidebar); this.$sidebar.attr('data-sidebar', 'true'); if( !this.$sidebar.attr('id') ) this.$sidebar.attr( 'id' , 'id-sidebar-'+(++sidebar_count) ) var duration = options.duration || ace.helper.intAttr(sidebar, 'data-submenu-duration') ||300;//transition duration //some vars this.minimized = false;//will be initiated later this.collapsible = false;//... this.horizontal = false;//... this.mobile_view = false;// this.vars = function() { return {'minimized': this.minimized, 'collapsible': this.collapsible, 'horizontal': this.horizontal, 'mobile_view': this.mobile_view} } this.get = function(name) { if(this.hasOwnProperty(name)) return this[name]; } this.set = function(name, value) { if(this.hasOwnProperty(name)) this[name] = value; } this.ref = function() { //return a reference to self return this; } var toggleIcon = function(minimized) { var icon = $(this).find(ace.vars['.icon']), icon1, icon2; if(icon.length > 0) { icon1 = icon.attr('data-icon1');//the icon for expanded state icon2 = icon.attr('data-icon2');//the icon for collapsed state if(minimized !== undefined) { if(minimized) icon.removeClass(icon1).addClass(icon2); else icon.removeClass(icon2).addClass(icon1); } else { icon.toggleClass(icon1).toggleClass(icon2); } } } var findToggleBtn = function() { var toggle_btn = self.$sidebar.find('.sidebar-collapse'); if(toggle_btn.length == 0) toggle_btn = $('.sidebar-collapse[data-target="#'+(self.$sidebar.attr('id')||'')+'"]'); if(toggle_btn.length != 0) toggle_btn = toggle_btn[0]; else toggle_btn = null; return toggle_btn; } //collapse/expand button this.toggleMenu = function(toggle_btn, save) { if(this.collapsible) return; //var minimized = this.$sidebar.hasClass('menu-min'); this.minimized = !this.minimized; try { //toggle_btn can also be a param to indicate saving to cookie or not?! if toggle_btn === false, it won't be saved ace.settings.sidebar_collapsed(sidebar, this.minimized, !(toggle_btn === false || save === false));//@ ace-extra.js } catch(e) { if(this.minimized) this.$sidebar.addClass('menu-min'); else this.$sidebar.removeClass('menu-min'); } if( !toggle_btn ) { toggle_btn = findToggleBtn(); } if(toggle_btn) { toggleIcon.call(toggle_btn, this.minimized); } //force redraw for ie8 if(ace.vars['old_ie']) ace.helper.redraw(sidebar); } this.collapse = function(toggle_btn, save) { if(this.collapsible) return; this.minimized = false; this.toggleMenu(toggle_btn, save); } this.expand = function(toggle_btn, save) { if(this.collapsible) return; this.minimized = true; this.toggleMenu(toggle_btn, save); } //collapse/expand in 2nd mobile style this.toggleResponsive = function(toggle_btn) { if(!this.mobile_view || this.mobile_style != 3) return; if( this.$sidebar.hasClass('menu-min') ) { //remove menu-min because it interferes with responsive-max this.$sidebar.removeClass('menu-min'); var btn = findToggleBtn(); if(btn) toggleIcon.call(btn); } this.minimized = !this.$sidebar.hasClass('responsive-min'); this.$sidebar.toggleClass('responsive-min responsive-max'); if( !toggle_btn ) { toggle_btn = this.$sidebar.find('.sidebar-expand'); if(toggle_btn.length == 0) toggle_btn = $('.sidebar-expand[data-target="#'+(this.$sidebar.attr('id')||'')+'"]'); if(toggle_btn.length != 0) toggle_btn = toggle_btn[0]; else toggle_btn = null; } if(toggle_btn) { var icon = $(toggle_btn).find(ace.vars['.icon']), icon1, icon2; if(icon.length > 0) { icon1 = icon.attr('data-icon1');//the icon for expanded state icon2 = icon.attr('data-icon2');//the icon for collapsed state icon.toggleClass(icon1).toggleClass(icon2); } } $(document).triggerHandler('settings.ace', ['sidebar_collapsed' , this.minimized]); } //some helper functions this.is_collapsible = function() { var toggle return (this.$sidebar.hasClass('navbar-collapse')) && ((toggle = $('.navbar-toggle[data-target="#'+(this.$sidebar.attr('id')||'')+'"]').get(0)) != null) && toggle.scrollHeight > 0 //sidebar is collapsible and collapse button is visible? } this.is_mobile_view = function() { var toggle return ((toggle = $('.menu-toggler[data-target="#'+(this.$sidebar.attr('id')||'')+'"]').get(0)) != null) && toggle.scrollHeight > 0 } //toggling submenu this.$sidebar.on(ace.click_event+'.ace.submenu', '.nav-list', function (ev) { var nav_list = this; //check to see if we have clicked on an element which is inside a .dropdown-toggle element?! //if so, it means we should toggle a submenu var link_element = $(ev.target).closest('a'); if(!link_element || link_element.length == 0) return;//return if not clicked inside a link element var minimized = self.minimized && !self.collapsible; //if .sidebar is .navbar-collapse and in small device mode, then let minimized be uneffective if( !link_element.hasClass('dropdown-toggle') ) {//it doesn't have a submenu return //just one thing before we return //if sidebar is collapsed(minimized) and we click on a first level menu item //and the click is on the icon, not on the menu text then let's cancel event and cancel navigation //Good for touch devices, that when the icon is tapped to see the menu text, navigation is cancelled //navigation is only done when menu text is tapped if( ace.click_event == 'tap' && minimized && link_element.get(0).parentNode.parentNode == nav_list )//only level-1 links { var text = link_element.find('.menu-text').get(0); if( text != null && ev.target != text && !$.contains(text , ev.target) ) {//not clicking on the text or its children ev.preventDefault(); return false; } } //ios safari only has a bit of a problem not navigating to link address when scrolling down //specify data-link attribute to ignore this if(ace.vars['ios_safari'] && link_element.attr('data-link') !== 'false') { //only ios safari has a bit of a problem not navigating to link address when scrolling down //please see issues section in documentation document.location = link_element.attr('href'); ev.preventDefault(); return false; } return; } ev.preventDefault(); var sub = link_element.siblings('.submenu').get(0); if(!sub) return false; var $sub = $(sub); var height_change = 0;//the amount of height change in .nav-list var parent_ul = sub.parentNode.parentNode; if ( ( minimized && parent_ul == nav_list ) || ( ( $sub.parent().hasClass('hover') && $sub.css('position') == 'absolute' ) && !self.collapsible ) ) { return false; } var sub_hidden = (sub.scrollHeight == 0) //if not open and visible, let's open it and make it visible if( sub_hidden ) {//being shown now $(parent_ul).find('> .open > .submenu').each(function() { //close all other open submenus except for the active one if(this != sub && !$(this.parentNode).hasClass('active')) { height_change -= this.scrollHeight; self.hide(this, duration, false); } }) } if( sub_hidden ) {//being shown now self.show(sub, duration); //if a submenu is being shown and another one previously started to hide, then we may need to update/hide scrollbars //but if no previous submenu is being hidden, then no need to check if we need to hide the scrollbars in advance if(height_change != 0) height_change += sub.scrollHeight;//we need new updated 'scrollHeight' here } else { self.hide(sub, duration); height_change -= sub.scrollHeight; //== -1 means submenu is being hidden } //hide scrollbars if content is going to be small enough that scrollbars is not needed anymore //do this almost before submenu hiding begins //but when minimized submenu's toggle should have no effect if (height_change != 0) { if(self.$sidebar.attr('data-sidebar-scroll') == 'true' && !self.minimized) self.$sidebar.ace_sidebar_scroll('prehide', height_change) } return false; }) var submenu_working = false; this.show = function(sub, $duration, wait) { if(wait !== false) { if(submenu_working) return false; submenu_working = true; } $duration = $duration || duration; var $sub = $(sub); var event; $sub.trigger(event = $.Event('show.ace.submenu')) if (event.isDefaultPrevented()) return false; $sub.css({ height: 0, overflow: 'hidden', display: 'block' }) .removeClass('nav-hide').addClass('nav-show')//only for window < @grid-float-breakpoint and .navbar-collapse.menu-min .parent().addClass('open'); sub.scrollTop = 0;//this is for submenu_hover when sidebar is minimized and a submenu is scrollTop'ed using scrollbars ... if( $duration > 0 ) { $sub.css({height: sub.scrollHeight, 'transition-property': 'height', 'transition-duration': ($duration/1000)+'s'}) } var complete = function(ev, trigger) { ev && ev.stopPropagation(); $sub .css({'transition-property': '', 'transition-duration': '', overflow:'', height: ''}) //if(ace.vars['webkit']) ace.helper.redraw(sub);//little Chrome issue, force redraw ;) if(trigger !== false) $sub.trigger($.Event('shown.ace.submenu')) if(wait !== false) submenu_working = false; } if( $duration > 0 && !!$.support.transition.end ) { $sub.one($.support.transition.end, complete); } else complete(); //there is sometimes a glitch, so maybe retry if(ace.vars['android']) { setTimeout(function() { complete(null, false); ace.helper.redraw(sub); }, $duration + 20); } return true; } this.hide = function(sub, $duration, wait) { if(wait !== false) { if(submenu_working) return false; submenu_working = true; } $duration = $duration || duration; var $sub = $(sub); var event; $sub.trigger(event = $.Event('hide.ace.submenu')) if (event.isDefaultPrevented()) return false; $sub.css({ height: sub.scrollHeight, overflow: 'hidden', display: 'block' }) .parent().removeClass('open'); sub.offsetHeight; //forces the "sub" to re-consider the new 'height' before transition if( $duration > 0 ) { $sub.css({'height': 0, 'transition-property': 'height', 'transition-duration': ($duration/1000)+'s'}); } var complete = function(ev, trigger) { ev && ev.stopPropagation(); $sub .css({display: 'none', overflow:'', height: '', 'transition-property': '', 'transition-duration': ''}) .removeClass('nav-show').addClass('nav-hide')//only for window < @grid-float-breakpoint and .navbar-collapse.menu-min if(trigger !== false) $sub.trigger($.Event('hidden.ace.submenu')) if(wait !== false) submenu_working = false; } if( $duration > 0 && !!$.support.transition.end ) { $sub.one($.support.transition.end, complete); } else complete(); //there is sometimes a glitch, so maybe retry if(ace.vars['android']) { setTimeout(function() { complete(null, false); ace.helper.redraw(sub); }, $duration + 20); } return true; } this.toggle = function(sub, $duration) { $duration = $duration || duration; if( sub.scrollHeight == 0 ) {//if an element is hidden scrollHeight becomes 0 if( this.show(sub, $duration) ) return 1; } else { if( this.hide(sub, $duration) ) return -1; } return 0; } //sidebar vars var minimized_menu_class = 'menu-min'; var responsive_min_class = 'responsive-min'; var horizontal_menu_class = 'h-sidebar'; var sidebar_mobile_style = function() { //differnet mobile menu styles this.mobile_style = 1;//default responsive mode with toggle button inside navbar if(this.$sidebar.hasClass('responsive') && !$('.menu-toggler[data-target="#'+this.$sidebar.attr('id')+'"]').hasClass('navbar-toggle')) this.mobile_style = 2;//toggle button behind sidebar else if(this.$sidebar.hasClass(responsive_min_class)) this.mobile_style = 3;//minimized menu else if(this.$sidebar.hasClass('navbar-collapse')) this.mobile_style = 4;//collapsible (bootstrap style) } sidebar_mobile_style.call(self); function update_vars() { this.mobile_view = this.mobile_style < 4 && this.is_mobile_view(); this.collapsible = !this.mobile_view && this.is_collapsible(); this.minimized = (!this.collapsible && this.$sidebar.hasClass(minimized_menu_class)) || (this.mobile_style == 3 && this.mobile_view && this.$sidebar.hasClass(responsive_min_class)) this.horizontal = !(this.mobile_view || this.collapsible) && this.$sidebar.hasClass(horizontal_menu_class) } //update some basic variables $(window).on('resize.sidebar.vars' , function(){ update_vars.call(self); }).triggerHandler('resize.sidebar.vars') }//end of Sidebar //sidebar events //menu-toggler $(document) .on(ace.click_event+'.ace.menu', '.menu-toggler', function(e){ var btn = $(this); var sidebar = $(btn.attr('data-target')); if(sidebar.length == 0) return; e.preventDefault(); sidebar.toggleClass('display'); btn.toggleClass('display'); var click_event = ace.click_event+'.ace.autohide'; var auto_hide = sidebar.attr('data-auto-hide') === 'true'; if( btn.hasClass('display') ) { //hide menu if clicked outside of it! if(auto_hide) { $(document).on(click_event, function(ev) { if( sidebar.get(0) == ev.target || $.contains(sidebar.get(0), ev.target) ) { ev.stopPropagation(); return; } sidebar.removeClass('display'); btn.removeClass('display'); $(document).off(click_event); }) } if(sidebar.attr('data-sidebar-scroll') == 'true') sidebar.ace_sidebar_scroll('reset'); } else { if(auto_hide) $(document).off(click_event); } return false; }) //sidebar collapse/expand button .on(ace.click_event+'.ace.menu', '.sidebar-collapse', function(e){ var target = $(this).attr('data-target'), $sidebar = null; if(target) $sidebar = $(target); if($sidebar == null || $sidebar.length == 0) $sidebar = $(this).closest('.sidebar'); if($sidebar.length == 0) return; e.preventDefault(); $sidebar.ace_sidebar('toggleMenu', this); }) //this button is used in `mobile_style = 3` responsive menu style to expand minimized sidebar .on(ace.click_event+'.ace.menu', '.sidebar-expand', function(e){ var target = $(this).attr('data-target'), $sidebar = null; if(target) $sidebar = $(target); if($sidebar == null || $sidebar.length == 0) $sidebar = $(this).closest('.sidebar'); if($sidebar.length == 0) return; var btn = this; e.preventDefault(); $sidebar.ace_sidebar('toggleResponsive', this); var click_event = ace.click_event+'.ace.autohide'; if($sidebar.attr('data-auto-hide') === 'true') { if( $sidebar.hasClass('responsive-max') ) { $(document).on(click_event, function(ev) { if( $sidebar.get(0) == ev.target || $.contains($sidebar.get(0), ev.target) ) { ev.stopPropagation(); return; } $sidebar.ace_sidebar('toggleResponsive', btn); $(document).off(click_event); }) } else { $(document).off(click_event); } } }) /** .on('shown.bs.collapse.sidebar hidden.bs.collapse.sidebar', '.sidebar[data-auto-hide=true]', function(e){ var click_event = ace.click_event+'.ace.autohide'; var sidebar = this; if(e.type == 'shown') { $(document).on(click_event, function(ev) { if( sidebar == ev.target || $.contains(sidebar, ev.target) ) { ev.stopPropagation(); return; } $(sidebar).collapse('hide'); $(document).off(click_event); }) } else $(document).off(click_event); }); */ $.fn.ace_sidebar = function (option, value) { var method_call; var $set = this.each(function () { var $this = $(this); var data = $this.data('ace_sidebar'); var options = typeof option === 'object' && option; if (!data) $this.data('ace_sidebar', (data = new Sidebar(this, options))); if (typeof option === 'string' && typeof data[option] === 'function') { if(value instanceof Array) method_call = data[option].apply(data, value); else method_call = data[option](value); } }); return (method_call === undefined) ? $set : method_call; }; })(window.jQuery); ;/** Scrollbars for sidebar. This approach can only be used on fixed sidebar. It doesn't use "overflow:hidden" CSS property and therefore can be used with .hover submenus and minimized sidebar. Except when in mobile view and menu toggle button is not in the navbar. */ (function($ , undefined) { //if( !$.fn.ace_scroll ) return; var old_safari = ace.vars['safari'] && navigator.userAgent.match(/version\/[1-5]/i) //NOTE //Safari on windows has not been updated for a long time. //And it has a problem when sidebar is fixed & scrollable and there is a CSS3 animation inside page content. //Very probably windows users of safari have migrated to another browser by now! var is_element_pos = 'getComputedStyle' in window ? //el.offsetHeight is used to force redraw and recalculate 'el.style.position' esp. for webkit! function(el, pos) { el.offsetHeight; return window.getComputedStyle(el).position == pos } : function(el, pos) { el.offsetHeight; return $(el).css('position') == pos } function Sidebar_Scroll(sidebar , settings) { var self = this; var $window = $(window); var $sidebar = $(sidebar), $nav = $sidebar.find('.nav-list'), $toggle = $sidebar.find('.sidebar-toggle').eq(0), $shortcuts = $sidebar.find('.sidebar-shortcuts').eq(0); var ace_sidebar = $sidebar.ace_sidebar('ref'); $sidebar.attr('data-sidebar-scroll', 'true'); var nav = $nav.get(0); if(!nav) return; var scroll_div = null, scroll_content = null, scroll_content_div = null, bar = null, track = null, ace_scroll = null; var scroll_to_active = settings.scroll_to_active || ace.helper.boolAttr(sidebar, 'data-scroll-to-active') || false, include_shortcuts = settings.include_shortcuts || ace.helper.boolAttr(sidebar, 'data-scroll-include-shortcuts') || false, include_toggle = settings.include_toggle || ace.helper.boolAttr(sidebar, 'data-scroll-include-toggle') || false, smooth_scroll = settings.smooth_scroll || ace.helper.intAttr(sidebar, 'data-scroll-smooth') || false, scrollbars_outside = settings.outside || ace.helper.boolAttr(sidebar, 'data-scroll-outside') || false, scroll_style = settings.scroll_style || $sidebar.attr('data-scroll-style') || '', only_if_fixed = true; var lockAnyway = settings.mousewheel_lock || ace.helper.boolAttr(sidebar, 'data-mousewheel-lock') || false; this.is_scrolling = false; var _initiated = false; this.sidebar_fixed = is_element_pos(sidebar, 'fixed'); var $avail_height, $content_height; var available_height = function() { //available window space var offset = $nav.parent().offset();//because `$nav.offset()` considers the "scrolled top" amount as well if(self.sidebar_fixed) offset.top -= ace.helper.scrollTop(); return $window.innerHeight() - offset.top - ( include_toggle ? 0 : $toggle.outerHeight() ); } var content_height = function() { return nav.clientHeight;//we don't use nav.scrollHeight here, because hover submenus are considered in calculating scrollHeight despite position=absolute! } var initiate = function(on_page_load) { if( _initiated ) return; if( !self.sidebar_fixed ) return;//eligible?? //return if we want scrollbars only on "fixed" sidebar and sidebar is not "fixed" yet! //initiate once $nav.wrap('