/******************************************************** * * Custom Javascript code for AppStrap Bootstrap theme * Written by Themelize.me (http://themelize.me) * * * File structure: * * 1. setup.js * 2. utils.js * 3. misc.js * 4. plugins/* * 5. base.js * *******************************************************/ // =============================================================== // @group: Config & Global variables // =============================================================== // Config var Config = { PLUGINS_LOCALPATH: "https://frmwrks.phcnetworks.net/appstrap/version-3.3.2/theme/assets/plugins/" }; // Extend using $.extend(true, Config, { PLUGINS_LOCALPATH: 'new/path/setting' }); // Globals - don't touch! var Globals = { PLUGINS: {}, PREINITPLUGINS: {}, LOADED_FILES: [], PAGE_SCROLLED: false, PAGELOADER_DONE: false, }; // =============================================================== // @group: Internal worker functions // =============================================================== (function($) { $.extend($.fn, { // ---------------------------------------------------------------- // Trigger callback when fakeLoader is loaded // ---------------------------------------------------------------- isPageLoaderDone: function(callback) { var $loader = $('[data-toggle="page-loader"]'); var triggerCallback = function() { $('html').addClass('.page-loader-done'); if (callback && typeof(callback) === "function") { callback(); } }; if ($loader.length === 0 || $loader.css('display') == 'none') { triggerCallback(); } var isPageLoaderDoneTimer = setInterval(function() { if ($loader.css('display') == 'none') { Globals.PAGELOADER_DONE = true; clearInterval(isPageLoaderDoneTimer); triggerCallback(); } }, 500); }, // ---------------------------------------------------------------- // Plugin: Waypoints // @see: http://imakewebthings.com/waypoints/ // Used as helper for other functions so not called direct // ---------------------------------------------------------------- includeWaypoints: function(callback) { if (typeof jQuery.fn.waypoint === 'undefined') { $document.themeLoadPlugin(['https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js'], []); var tries = 0; var isWaypointsDoneTimer = setInterval(function() { if (typeof jQuery.fn.waypoint === 'function') { clearInterval(isWaypointsDoneTimer); if (callback && typeof(callback) === "function") { callback(); } } tries++; if (tries > 20) { clearInterval(isWaypointsDoneTimer); alert('Error: Waypoints plugin could not be loaded'); } }, 500); } else { if (callback && typeof(callback) === "function") { callback(); } } }, refreshWaypoints: function() { if (typeof jQuery.fn.waypoint !== 'undefined') { Waypoint.refreshAll(); } }, // ---------------------------------------------------------------- // Determine if element is in viewport // @credit: https://coderwall.com/p/fnvjvg/jquery-test-if-element-is-in-viewport // ---------------------------------------------------------------- elementInView: function(obj) { var elementTop = obj.offset().top; var elementBottom = elementTop + obj.outerHeight(); var viewportTop = $(window).scrollTop(); var viewportBottom = viewportTop + $(window).height(); return elementBottom > viewportTop && elementTop < viewportBottom; }, // ---------------------------------------------------------------- // Scroll links // ---------------------------------------------------------------- themeScrollMenus: function() { var context = $(this); var scrollLinks = context.find('[data-toggle="scroll-link"]'); var $header = $('#header [data-toggle="sticky"]'); var $body = $('body'); var $window = $(window); var $spys = $('[data-spy="scroll"]'); var spyTarget = $body.data('spy-target') || '.navbar-main'; var spyData; if (scrollLinks.length > 0) { var getHeaderOffset = function(extra) { var offset = $header.outerHeight() + (extra !== null ? extra : 0); if ($body.hasClass('header-compact-sticky')) { offset = offset - 35; } if ($body.data('offset-elements')) { $($body.data('offset-elements'), context).each(function() { offset += $(this).outerHeight(); }); } return offset; }; var customActiveSpyClass = function(active) { scrollLinks.each(function() { var $t = $(this); var customActive = $t.data('active-class') || null; if (active === null && customActive !== null) { $t.removeClass(customActive); } else { if ($t.attr('href') == active) { $t.addClass(customActive); } else if (customActive !== null) { $t.removeClass(customActive); } } }); } var triggerSpy = function(state) { var offsetExtra = 5; if (state == 'refresh') { spyData = $body.data('bs.scrollspy'); spyData._config.offset = getHeaderOffset(offsetExtra); $body.data('bs.scrollspy', spyData); $body.scrollspy('refresh'); } else { $body.scrollspy({ target: spyTarget, offset: getHeaderOffset(offsetExtra), }); } }; triggerSpy('init'); // Custom active class per link spyData = $body.data('bs.scrollspy'); if (spyData._activeTarget) { customActiveSpyClass(spyData._activeTarget); } $window.on('activate.bs.scrollspy', function(e, t) { customActiveSpyClass(t.relatedTarget); }); $window.on('scroll.bs.scrollspy', function(e) { setTimeout(function() { customActiveSpyClass($body.data('bs.scrollspy')._activeTarget); }, 200); }); $window.on('resize', function() { setTimeout(function() { triggerSpy('refresh'); }, 200); }); scrollLinks.click(function() { if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) { var $this = $(this), target = $(this.hash), speed = $this.data('scroll-link-speed') || 1000, noOffset = $this.data('scroll-link-nooffset') || false; var clickScroll = function() { var hash = this.hash || null; target = target.length ? target : (hash !== null ? $('[id=' + this.hash.slice(1) + ']') : null); if (target !== null) { offset = getHeaderOffset(null); if (noOffset) { offset = 0; } $('html, body').animate({ scrollTop: target.offset().top - offset, }, speed); } }; // If header changes size $(window).trigger('resize'); clickScroll(); return false; } }); } }, //submenu dropdowns // -------------------------------- themeSubMenus: function() { var context = $(this); var $tabsPills = $('.dropdown-menu [data-toggle="tab"], .dropdown-menu [data-toggle="pill"]'); $tabsPills.on('click', function(e) { event.preventDefault(); event.stopPropagation(); $(this).tab('show'); }); $tabsPills.on('shown.bs.tab', function(e) { var $from = $(e.relatedTarget); var $to = $(e.target); var toSelectors = $to.getSelector(); var fromSelectors = $from.getSelector(); var $toSelectors = $(toSelectors); var $fromSelectors = $(fromSelectors); $toSelectors.addClass('active'); $fromSelectors.removeClass('active'); $(document).find('[data-target="' + toSelectors + '"]').addClass('active'); $(document).find('[data-target="' + fromSelectors + '"]').removeClass('active'); }); context.find('.dropdown-menu [data-toggle=dropdown]').on('click', function(event) { event.preventDefault(); event.stopPropagation(); // Toggle direct parent $(this).parent().toggleClass('show'); }); // Persistent menus context.find('.dropdown.dropdown-persist').on({ "shown.bs.dropdown": function() { $(this).data('closable', false); }, "hide.bs.dropdown": function(event) { temp = $(this).data('closable'); $(this).data('closable', true); return temp; } }); context.find('.dropdown.dropdown-persist .dropdown-menu').on({ "click": function(event) { $(this).parent('.dropdown.dropdown-persist').data('closable', false); }, }); }, // Gets selector from href or data-target getSelector: function() { var element = $(this); var selector = element.data('target'); if (!selector || selector === '#') { selector = element.attr('href') || ''; } try { var $selector = $(selector); return $selector.length > 0 ? selector : null; } catch (error) { return null; } }, // calculate a height with offset calcHeightsOffset: function(height, offset) { if (typeof offset == 'number') { return height - offset; } else if (typeof offset == 'string' && $(offset).length > 0) { $(offset).each(function() { height = height - $(offset).height(); }); } return height; }, // Detected IE & adds body class isIE: function() { if (document.documentMode || /Edge/.test(navigator.userAgent)) { return true; } }, // Determines plugin location // -------------------------------- getScriptLocation: function() { var location = $('body').data('plugins-localpath') || null; if (location) { return location; } return Config.PLUGINS_LOCALPATH; }, // Delays // -------------------------------- delay: function(callback, ms) { var timer = 0; clearTimeout(timer); timer = setTimeout(callback, ms); }, // Hash from string // -------------------------------- hashCode: function(str) { var hash = 0; for (var i = 0; i < str.length; i++) { hash = ~~(((hash << 5) - hash) + str.charCodeAt(i)); } return hash; }, // Load plugin // -------------------------------- themeLoadPlugin: function(js, css, callback, placement) { // Manually loaded assets var manualPlugins = $('body').data('plugins-manual') || null; if (manualPlugins !== null) { if (callback && typeof(callback) === "function") { callback(); } return; } var themeLoadPluginPath = function(url) { if (url.indexOf('http://') === 0 || url.indexOf('https://') === 0) { return url; } var location = $document.getScriptLocation(); return location + url; }; $.ajaxPrefilter("script", function(s) { s.crossDomain = true; }); if (js.length > 0) { var progress = 0; var internalCallback = function(url) { // Complete if (++progress === js.length) { $.each(css, function(index, value) { if (Globals.LOADED_FILES[value] === value) { // Already loaded return true; } // Record file loaded Globals.LOADED_FILES[value] = value; $('head').prepend(''); }); if (callback && typeof(callback) === "function") { callback(); } } }; $.each(js, function(index, value) { if (Globals.LOADED_FILES[value] === value) { // Already loaded internalCallback(); return true; } // Offline mode var hash = window.location.hash; if (hash === '#offline' && (value.indexOf('http://') === 0 || value.indexOf('https://')) === 0) { console.log('Offline mode: ' + value + ' loading skipped'); return; } // Record file loaded Globals.LOADED_FILES[value] = value; if (placement === undefined) { var options = { url: themeLoadPluginPath(value), dataType: "script", success: internalCallback, cache: true }; $.ajax(options); } else if (placement === 'append') { $('script[src*="bootstrap.min.js"]').after(''); internalCallback(); } else if (placement === 'prepend') { $('script[src*="bootstrap.min.js"]').before(''); internalCallback(); } else if (placement === 'head') { $('head').append(''); internalCallback(); } }); } else if (css.length > 0) { // Just CSS $.each(css, function(index, value) { if (Globals.LOADED_FILES[value] === value) { // Already loaded return true; } // Record file loaded Globals.LOADED_FILES[value] = value; $('head').prepend(''); }); if (callback && typeof(callback) === "function") { callback(); } } }, }); })(jQuery); // Temp fix for https://github.com/vmitsaras/js-offcanvas/commit/ab116f632a092477574d69760ecbe3d7c07b00ab#diff-7399a891b21afad97155db02f6dbd60dL142 var raf = (function(callback) { return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60); }; })(); var utils = {}; utils.raf = function(callback) { raf(callback); }; window.utils = utils; // =============================================================== // @group: Custom functionality intergration/init // =============================================================== (function($) { $.extend($.fn, { themeCustomScripts: function(refresh) { var context = $(this); if (typeof context === "undefined" || context === null) { context = $(document); } $document = $(document); // Menus need init quick, @see utils.js context.themeSubMenus(); context.themeScrollMenus(); // ---------------------------------------------------------------- // Hover effects // ---------------------------------------------------------------- var elementsHovered = context.find('[data-hover]'); if (elementsHovered.length > 0) { var initElementsHovered = function() { elementsHovered.each(function() { var $element = jQuery(this), animateClass = $element.data('hover'), animateClassOut = $element.data('hover-out'), animateDelay = $element.data('hover-delay') || null, animateDuration = $element.data('hover-duration') || null; // Delays & durations if (animateDelay !== null) { $element.css({ '-webkit-animation-delay': animateDelay + 's', '-moz-animation-delay': animateDelay + 's', 'animation-delay': animateDelay + 's' }); } if (animateDuration !== null) { $element.css({ '-webkit-animation-duration': animateDuration + 's', '-moz-animation-duration': animateDuration + 's', 'animation-duration': animateDuration + 's' }); } $element.hover( function() { $element.addClass('animated ' + animateClass).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() { $element.removeClass('animated ' + animateClass).addClass('animated ' + animateClassOut); }); }, function() {} ); }); }; $document.themeLoadPlugin([], ["https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css"], function() { $document.isPageLoaderDone(initElementsHovered); }); } // ---------------------------------------------------------------- // Fullheight elements // ---------------------------------------------------------------- var fullHeights = context.find('[data-toggle="full-height"]'); if (fullHeights.length > 0) { var doFullHeightsOffset = function(height, offset) { return $document.calcHeightsOffset(height, offset); }; var doFullHeights = function() { fullHeights.each(function() { var $element = $(this), fullHeightParent = $element.data('parent') || window, fullHeightOffset = $element.data('offset') || null, fullHeightBreakpoint = $element.data('breakpoint') || null, $fullHeightParent = $(fullHeightParent) || null; if ($fullHeightParent) { var fullHeightParentHeight = $fullHeightParent.height(); var fullHeight = fullHeightParentHeight; if (fullHeightOffset) { fullHeight = doFullHeightsOffset(fullHeight, fullHeightOffset); } if (fullHeightBreakpoint) { if ($(window).width() <= fullHeightBreakpoint) { $element.css('height', 'auto'); } else { $element.outerHeight(fullHeight); } } else { $element.outerHeight(fullHeight); } } }); }; doFullHeights(); $(window).on('resize', function() { setTimeout(function() { doFullHeights(); }, 400); }); } // ---------------------------------------------------------------- // Animated scroll elements // ---------------------------------------------------------------- var elementsAnimated = context.find('[data-animate]'); if (elementsAnimated.length > 0) { var initElementsAnimated = function() { // SEO hack, hide stuff when page scrolled $(window).on('scroll', function() { if (Globals.PAGE_SCROLLED !== true) { //$body.addClass('animates-pending'); Globals.PAGE_SCROLLED = true; } }); elementsAnimated.each(function() { var $element = $(this), animateClass = $element.data('animate'), animateInfinite = $element.data('animate-infinite') || null, animateDelay = $element.data('animate-delay') || null, animateDuration = $element.data('animate-duration') || null, animateOffset = $element.data('animate-offset') || '98%', animateInView = $element.data('animate-inview') || false, elementInView = $document.elementInView($element); // Already scroll passed so don't animate again if (elementInView === true && animateInView === false) { animateClass = null; $element.removeAttr('data-animate'); } // Infinite if (animateInfinite !== null) { $element.addClass('infinite'); } // Delays & durations if (animateDelay !== null) { $element.css({ '-webkit-animation-delay': animateDelay + 's', '-moz-animation-delay': animateDelay + 's', 'animation-delay': animateDelay + 's' }); } if (animateDuration !== null) { $element.css({ '-webkit-animation-duration': animateDuration + 's', '-moz-animation-duration': animateDuration + 's', 'animation-duration': animateDuration + 's' }); } if (animateClass !== null) { $element.waypoint(function() { $element.addClass('animated ' + animateClass).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() { $element.addClass('animated-done'); $element.removeClass(animateClass); }); this.destroy(); }, { offset: animateOffset, }); } }); }; $document.includeWaypoints(function() { $document.themeLoadPlugin([], ["https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css"], function() { $document.isPageLoaderDone(initElementsAnimated); }); }); } // ---------------------------------------------------------------- // Scroll state // ---------------------------------------------------------------- context.find('[data-scroll="scroll-state"]').each(function() { var $scroll = $(this), $doc = $(document), scrollAmount = $scroll.data('scroll-amount') || $(window).outerHeight(), scrollAmountOut = $scroll.data('scroll-amount-out') || null, //@todo scrollSettings = $scroll.data('scroll-setting') || null, scrollEffectIn = scrollSettings !== null ? (scrollSettings.effectIn || null) : null, scrollEffectOut = scrollSettings !== null ? (scrollSettings.effectOut || null) : null, scrollEffectDelay = scrollSettings !== null ? (scrollSettings.effectDelay || null) : null, scrollEffectDuration = scrollSettings !== null ? (scrollSettings.effectDuration || null) : null, scrollBreakpoint = scrollSettings !== null ? (scrollSettings.breakpoint || null) : null, scrollFallbackState = scrollSettings !== null ? (scrollSettings.fallbackState || 'scroll-state-active') : null, scrollActive = $scroll.data('scroll-active') || true, scrollPersist = scrollSettings !== null ? (scrollSettings.persist || null) : null, effectType = 'transitions', $window = $(window); if ($scroll.hasClass('scroll-state-hidden')) { $scroll.data('state', 'out'); } if (scrollEffectIn !== null || scrollEffectOut !== null) { $scroll.addClass('scroll-effect'); $document.themeLoadPlugin([], ["https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css"]); effectType = 'animate'; } // Delays & durations if (scrollEffectDelay !== null) { $scroll.css({ '-webkit-animation-delay': scrollEffectDelay + 's', '-moz-animation-delay': scrollEffectDelay + 's', 'animation-delay': scrollEffectDelay + 's' }); } if (scrollEffectDuration !== null) { $scroll.css({ '-webkit-animation-duration': scrollEffectDuration + 's', '-moz-animation-duration': scrollEffectDuration + 's', 'animation-duration': scrollEffectDuration + 's' }); } if (scrollBreakpoint) { $window.on('resize', function() { setTimeout(function() { if ($window.width() <= scrollBreakpoint) { scrollActive = false; $scroll.addClass(scrollFallbackState); $scroll.removeClass(scrollEffectOut); $scroll.removeClass(scrollEffectIn); } else { scrollActive = true; $scroll.removeClass(scrollFallbackState); } $scroll.data('scroll-active', scrollActive); }, 400); }); } $doc.scroll(function() { if ($scroll.data('scroll-active') === false) { return; } var y = $(this).scrollTop(); var active = $scroll.data('state'); if (y >= scrollAmount) { if (active === 'out') { $scroll.data('state', 'in'); $scroll.addClass('scroll-state-active'); $scroll.removeClass('scroll-state-hidden'); if (scrollEffectOut !== null) { $scroll.removeClass(scrollEffectOut); } if (scrollEffectIn !== null) { $scroll.addClass('animated ' + scrollEffectIn); } } } else if (active === 'in') { if (scrollPersist) { $scroll.data('state', 'persist'); } else { $scroll.data('state', 'out'); if (scrollEffectOut !== null) { $scroll.addClass('animated ' + scrollEffectOut); } else { $scroll.removeClass('scroll-state-active'); $scroll.addClass('scroll-state-hidden'); } if (scrollEffectIn !== null) { $scroll.removeClass(scrollEffectIn); } } } }); }); // ---------------------------------------------------------------- // scrollax - adjust oapcity & top on scroll // ---------------------------------------------------------------- context.find('[data-scroll="scrollax"]').each(function() { var $scroll = $(this), $doc = $(document), $window = $(window), opRatio = $scroll.data('scrollax-op-ratio') || 500, yRatio = $scroll.data('scrollax-y-ratio') || 5; $doc.scroll(function() { var windowTop = $window.scrollTop(); $scroll.css({ "opacity": (opRatio === 'off' ? 1 : 1 - windowTop / opRatio), "transform": (yRatio === 'off' ? 0 : "translateY(" + (0 - windowTop / yRatio) + "px)"), }); }); }); // ---------------------------------------------------------------- // Quantity widget // ---------------------------------------------------------------- context.find('[data-toggle="quantity"]').each(function() { var $this = $(this), $down = $this.find('.quantity-down'), $up = $this.find('.quantity-up'), $quantity = $this.find('.quantity'); var toggleQuantity = function(direction) { var value = parseInt($quantity.val()); if (direction === 'down') { value = value - 1; } else if (direction === 'up') { value = value + 1; } if (value < 0) { value = 0; } $quantity.val(value); }; if ($quantity.length > 0) { $down.on('click', function() { toggleQuantity('down'); }); $up.on('click', function() { toggleQuantity('up'); }); } }); // ---------------------------------------------------------------- // Dynamic/quick CSS props // Example: data-css='{"height":"240px","background-position":"center center"}' // ---------------------------------------------------------------- context.find('[data-css]').each(function() { var $this = $(this), currentStyles = $this.data('css') || '', styleProps = $this.data('css') || {}, newStyles = {}; if (styleProps !== null && typeof styleProps === 'object') { newStyles = $.extend(currentStyles, styleProps); $this.css(newStyles); } }); // ---------------------------------------------------------------- // Overlay menu // ---------------------------------------------------------------- var overlayMenus = context.find('[data-toggle=overlay]'); if (overlayMenus.length > 0) { overlayMenus.each(function() { var $this = jQuery(this), target = $this.data('target') || null; // General class for all triggers $this.addClass('overlay-trigger'); if ($(target).length > 0) { $target = $(target); $this.on('click', function(e) { $this.toggleClass('overlay-active'); jQuery($this.data('target')).toggleClass('overlay-active'); jQuery('html').toggleClass('overlay-open'); return false; }); } }); // Overlay dismiss links/buttons context.find('[data-dismiss="overlay"]').each(function() { var $this = jQuery(this), $target = $this.data('target') || '.overlay', $trigger = jQuery('[data-toggle="overlay"][data-target="' + $target + '"]') || null; // Check target overlay to close exists if ($($target).length > 0) { $target = jQuery($target); $this.on('click', function(e) { $target.removeClass('overlay-active'); jQuery('html').removeClass('overlay-open'); // Try to find the trigger if ($trigger.length > 0) { $trigger.removeClass('overlay-active'); } else { // close all jQuery('[data-toggle="overlay"]').removeClass('overlay-active'); } return false; }); } }); } // ---------------------------------------------------------------- // Clickable elements // ---------------------------------------------------------------- context.find('[data-url]').each(function() { var url = $(this).data('url'); var parseStringUrl = function(url) { var a = document.createElement('a'); a.href = url; return a; }; var urlParse = parseStringUrl(url); $(this).addClass('clickable-element'); // Hover event $(this).on('hover', function() { $(this).hover( function() { $(this).addClass("hovered"); }, function() { $(this).removeClass("hovered"); } ); }); // Disable Links within block $(this).find('a').on('click', function(e) { if ($(this).attr('href') === urlParse.href) { e.preventDefault(); } }); // Click event $(this).on('click', function() { if (urlParse.host !== location.host) { // external window.open(urlParse.href, '_blank'); } else { // internal window.location = url; } }); }); // ---------------------------------------------------------------- // Search form show/hide // ---------------------------------------------------------------- $searchForm = context.find('[data-toggle=search-form]'); if ($searchForm.length > 0) { var $trigger = $searchForm; var target = $trigger.data('target'); var $target = $(target); if ($target.length === 0) { return; } $target.addClass('collapse'); $('[data-toggle=search-form]').click(function() { $target.collapse('toggle'); $(target + ' .search').focus(); $trigger.toggleClass('open'); $('html').toggleClass('search-form-open'); $(window).trigger('resize'); }); $('[data-toggle=search-form-close]').click(function() { $target.collapse('hide'); $trigger.removeClass('open'); $('html').removeClass('search-form-open'); $(window).trigger('resize'); }); } // ---------------------------------------------------------------- // colour switch - demo only // ---------------------------------------------------------------- var defaultColour = $('body').data('colour-scheme') || 'green'; var colourSchemes = context.find('.theme-colours a'); colourSchemes.removeClass('active'); colourSchemes.filter('.' + defaultColour).addClass('active'); colourSchemes.click(function() { var $this = $(this); var c = $this.attr('href').replace('#', ''); var cacheBuster = 3 * Math.floor(Math.random() * 6); $('.theme-colours a').removeClass('active'); $('.theme-colours a.' + c).addClass('active'); if (c !== defaultColour) { context.find('#colour-scheme').attr('href', 'assets/css/colour-' + c + '.css?x=' + cacheBuster); } else { context.find('#colour-scheme').attr('href', '#'); } }); // ---------------------------------------------------------------- // IE placeholders // ---------------------------------------------------------------- if (navigator.userAgent.toLowerCase().indexOf('msie') > -1) { context.find('[placeholder]').focus(function() { var input = jQuery(this); if (input.val() === input.attr('placeholder')) { if (this.originalType) { this.type = this.originalType; delete this.originalType; } input.val(''); input.removeClass('placeholder'); } }).blur(function() { var input = jQuery(this); if (input.val() === '') { input.addClass('placeholder'); input.val(input.attr('placeholder')); } }).blur(); } // ---------------------------------------------------------------- // Bootstrap animated progressbar width // ---------------------------------------------------------------- var progressBarsAnimated = context.find('[data-toggle="progress-bar-animated-progress"]'); if (progressBarsAnimated.length > 0) { var initProgressBarsAnimated = function() { progressBarsAnimated.each(function() { var $progress = jQuery(this); var currentStyles = $progress.attr("style") || ''; $progress.waypoint(function() { currentStyles += 'width: ' + $progress.attr("aria-valuenow") + '% !important;'; $progress.attr("style", currentStyles).addClass('progress-bar-animated-progress'); this.destroy(); }, { offset: '98%' }); }); }; $document.includeWaypoints(function() { progressBarsAnimated.css("width", 0); $document.isPageLoaderDone(initProgressBarsAnimated); }); } // ---------------------------------------------------------------- // Bootstrap collapse // ---------------------------------------------------------------- var collapses = context.find('[data-toggle="collapse"]'); collapses.each(function() { var $this = $(this); var target = $this.attr('href') || $this.data('target'); var parent = $this.data('parent') || null; if ($(target).length > 0) { if ($(target).hasClass('show')) { $this.addClass('show'); } } $this.on({ 'click': function() { $this.toggleClass('show', !$(target).hasClass('show')); $(window).trigger('resize'); var $checks = $this.find('input[type="checkbox"]'); if ($checks.length > 0) { $checks.prop('checked', !$(target).hasClass('show')); } } }); }); // Scroll to top of active card context.find('[data-accordion-focus]').on('shown.bs.collapse', function(e) { var headingTop = $(e.target).parent().offset().top; var scrollTo = $document.calcHeightsOffset(headingTop, $('#header').outerHeight()); $('html,body').animate({ scrollTop: scrollTo + 20 }, 500); }); var radioCollapses = context.find('[data-toggle="radio-collapse"]'); radioCollapses.each(function(index, item) { var $item = $(item); var $target = $($item.data('target')); var $parent = $($item.data('parent')); var $radio = $item.find('input[type=radio]'); var $radioOthers = $parent.find('input[type=radio]').not($radio); $radio.on('change', function() { if ($radio.is(':checked')) { $target.collapse('show'); } else { $target.collapse('hide'); } }); $radio.on('click', function() { $radioOthers.prop('checked', false).trigger('change'); }); }); // ---------------------------------------------------------------- // Bootstrap modals onload & duration & animation // @see: http://v4-alpha.getbootstrap.com/components/modal/ // ---------------------------------------------------------------- var modalsDuration = context.find('[data-modal-duration]'); if (modalsDuration.length > 0) { var $modal = modalsDuration, duration = $modal.data('modal-duration'), progressBar = $('
'); $modal.find('.modal-content').append(progressBar); // Actual durations $modal.on('show.bs.modal', function(e) { var i = 2; var durationProgress = setInterval(function() { progressBar.width(i++ + '%'); }, duration / 100); setTimeout(function() { $modal.modal('hide'); clearInterval(durationProgress); }, duration); }); } var modalsOnload = context.find('[data-toggle="modal-onload"]'); if (modalsOnload.length > 0) { modalsOnload.on('shown.bs.modal', function() { $(this).data('modal-shown', true); }); modalsOnload.each(function() { var $modal = $(this), delay = $modal.data('modal-delay') || null, force = $modal.data('modal-force') || false; // Open it again ever if opened once before var startModal = function($modal) { var shown = $modal.data('modal-shown') || false; //if (shown === false || shown && force) { $modal.modal(); //} }; // Delay modal opening if (delay !== null) { setTimeout(function() { startModal($modal); }, delay); } else { // No delay trigger direct startModal($modal); } }); } // Inline modals ie. no fixed backdrop var modalsHideBd = context.find('[data-backdrop=false]'); var $body = $('body'); modalsHideBd.on('show.bs.modal', function(e) { $(this).data('bs.modal')._config.backdrop = false; $body.addClass('modal-no-backdrop'); }); modalsHideBd.on('hidden.bs.modal', function(e) { $body.removeClass('modal-no-backdrop'); }); // Animate.css modal integration function modalAnimate($m, s, e) { var animateIn = $m.data('modal-animate-in') || 'fadeIn', animateOut = $m.data('modal-animate-out') || 'fadeOut', animateAdd = animateIn, animateRemove = animateOut; if (s == 'out') { animateAdd = animateOut; animateRemove = animateIn; } $m.removeClass(animateRemove); $m.addClass(animateAdd + ' animated').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function() { $m.removeClass(animateAdd + ' animated'); if (s == 'out') { $m.removeClass('modal-animate-closing'); $body.removeClass('modal-animate'); } }); } var $modalsAnimate = context.find('[data-modal-animate-in], [data-modal-animate-out]'); if ($modalsAnimate.length > 0) { var $modalBackdrop = $('').addClass('modal-animate-backdrop'); $modalBackdrop.appendTo($body); $modalsAnimate.on('click.backdropDismiss', function(e) { var $m = $(e.target).hasClass('modal') ? $(e.target) : null; if ($m) { $m.modal('hide'); } }); $modalsAnimate.on('show.bs.modal', function(e) { var $m = $(this); var backdrop = $m.data('bs.modal')._config.backdrop; $body.addClass('modal-animate'); $m.data('bs.modal')._config.backdrop = false; if (backdrop) { $modalBackdrop.addClass('show'); } modalAnimate($m, 'in', e); }).on('hide.bs.modal', function(e) { var $m = $(this); $m.addClass('modal-animate-closing'); $modalBackdrop.removeClass('show'); modalAnimate($m, 'out', e); }); } // ---------------------------------------------------------------- // Bootstrap tooltip // @see: http://getbootstrap.com/javascript/#tooltips // ---------------------------------------------------------------- // invoke by adding data-toggle="tooltip" to a tags (this makes it validate) if ($document.tooltip) { context.find('[data-toggle="tooltip"]').tooltip(); } // ---------------------------------------------------------------- // Bootstrap popover // @see: http://getbootstrap.com/javascript/#popovers // ---------------------------------------------------------------- // invoke by adding data-toggle="popover" to a tags (this makes it validate) if ($document.popover) { context.find('[data-toggle="popover"]').popover(); } // ---------------------------------------------------------------- // allow any page element to set page class // ---------------------------------------------------------------- context.find('[data-page-class]').each(function() { context.find('html').addClass(jQuery(this).data('page-class')); }); // ---------------------------------------------------------------- // Detect Bootstrap fixed header // @see: http://getbootstrap.com/components/#navbar-fixed-top // ---------------------------------------------------------------- if (context.find('.navbar-fixed-top').length > 0) { context.find('html').addClass('has-navbar-fixed-top'); } // ---------------------------------------------------------------- // simple class toggles // ---------------------------------------------------------------- context.find('[data-toggle="class"]').each(function() { var $this = $(this); var target = $this.data('target'); var $target = $(target); var toggleClass = $this.data('toggle-class') || 'show'; var toggleTrigger = $this.data('toggle-trigger') || 'click'; var toggleAction = $this.data('toggle-action') || 'toggle'; var toggleCallback = function(t, c, a) { if (typeof c === 'object') { $.each(c, function(i, name) { if (a === 'remove') { t.removeClass(name); } else if (a === 'add') { t.addClass(name); } else { t.toggleClass(name); } }); } else { if (a === 'remove') { t.removeClass(c); } else if (a === 'add') { t.addClass(c); } else { t.toggleClass(c); } } }; if (typeof target === 'object') { $.each(target, function(selector, data) { var _toggleTrigger = data.toggleTrigger || toggleTrigger; var _toggleActions = data.actions || toggleAction; $this.on(_toggleTrigger, function() { if (typeof _toggleActions === 'object') { $.each(_toggleActions, function(action, classes) { toggleCallback($(selector), classes, action); }); } else { toggleCallback($(selector), _toggleClass, _toggleAction); } return false; }); }); } else { if ($target.length === 0) { return; } $this.on(toggleTrigger, function() { toggleCallback($target, toggleClass, toggleAction); return false; }); } }); // ---------------------------------------------------------------- // Simple class togglers // // Toggle // ---------------------------------------------------------------- $("[data-toggle='toggle']").click(function() { var $this = $(this); var selector = $this.getSelector(); var toggleClass = $this.data("class"); $(selector).toggleClass(toggleClass); }); // ---------------------------------------------------------------- // show hide for hidden header // ---------------------------------------------------------------- context.find('[data-toggle=show-hide]').each(function() { var $this = jQuery(this); var target = $this.attr('data-target'); var $target = $(target); var state = 'show'; //open or hide var targetState = $this.attr('data-target-state'); var callback = $this.attr('data-callback'); if ($target.length === 0) { return; } if (state === 'show') { // Close by default $target.addClass('collapse'); } $this.click(function() { //allows trigger link to say target is open & should be closed if (typeof targetState !== 'undefined' && targetState !== false) { state = targetState; } if (state === undefined) { state = 'show'; } if (!$target.hasClass('show')) { // About to open $this.addClass('show'); } else { $this.removeClass('show'); } $target.collapse('toggle'); if (callback && typeof(callback) === "function") { callback(); } }); }); // Clones DOM elements // -------------------------------- context.find('[data-clone]').each(function() { var $this = $(this); var clone = $this.data('clone') || null; // @todo - allow multiple clones var cloneTo = $this.data('clone-to') || null; var $cloneFrom, $cloneTo; var placement = $this.data('clone-placement') || 'after'; var classesRemove = $this.data('clone-classes-remove') || []; var classesAdd = $this.data('clone-classes-add') || []; // Clone to $cloneTo = $this; if (cloneTo !== null) { $cloneTo = $(cloneTo); $cloneTo = $cloneTo.length() > 0 ? $cloneTo : $this; } // Clone from $clone = $(clone); $clone = $clone.length > 0 ? $clone : null; if ($clone === null) { return; } // Manipulate clone $clone = $clone.clone(); $clone.addClass('cloned-element'); // Remove elements // Classes if (classesRemove !== null && $.isArray(classesRemove)) { $.each(classesRemove, function(k, c) { $clone.removeClass(c); }); } if (classesAdd !== null && $.isArray(classesAdd)) { $.each(classesAdd, function(k, c) { $clone.addClass(c); }); } // Placement if (placement === 'before') { $clone.prependTo($this); } else { $clone.appendTo($this); } }); }, }); })(jQuery); // Object of plugins to add to Globals.PLUGINS // Add custom plugin integration here or as separate files // within the /src/plugins directory var defaultPlugins = { //themePluginPLUGINNAME: function(context) { // // Example: Plugin integration code here //}, // Next plugin here }; // Add to Globals.PLUGINS $.extend($.fn, { themePlugins: defaultPlugins }); // Object of plugins to add to Globals.PLUGINS Globals.PLUGINS.themePluginBackstretch = function(context) { // ---------------------------------------------------------------- // Plugin: Backstretch // @see: http://srobbin.com/jquery-plugins/backstretch/ // ---------------------------------------------------------------- var $backstretches = context.find('[data-toggle=backstretch]'); if ($backstretches.length > 0) { var themePluginBackstretchInit = function() { $backstretches.each(function() { var backstretchEl = $(this); var backstretchTarget = jQuery, backstretchImgs = []; var backstretchSettings = { fade: 750, duration: 4000 }; // Get images from element jQuery.each(backstretchEl.data('backstretch-imgs').split(','), function(k, img) { backstretchImgs[k] = img; }); // block level element if (backstretchEl.data('backstretch-target')) { backstretchTarget = backstretchEl.data('backstretch-target'); if (backstretchTarget === 'self') { backstretchTarget = backstretchEl; } else { if ($(backstretchTarget).length > 0) { backstretchTarget = $(backstretchTarget); } } } if (backstretchImgs) { $('html').addClass('has-backstretch'); // Merge in any custom settings backstretchSettings = $.extend({}, backstretchSettings, backstretchEl.data()); backstretchTarget.backstretch(backstretchImgs, backstretchSettings); // add overlay if (backstretchEl.data('backstretch-overlay') !== false) { $('.backstretch').prepend(''); if (backstretchEl.data('backstretch-overlay-opacity')) { $('.backstretch').find('.backstretch-overlay').css('background', 'white').fadeTo(0, backstretchEl.data('backstretch-overlay-opacity')); } } } }); }; $document.themeLoadPlugin(["backstretch/jquery.backstretch.min.js"], [], themePluginBackstretchInit); } }; // Object of plugins to add to Globals.PLUGINS Globals.PLUGINS.themePluginBlazy = function(context) { // ---------------------------------------------------------------- // Plugin: Blazy // @see: http://dinbror.dk/blog/blazy/ // // From AppStrap 3.0.9 data-bg-img is now loaded by BLazy too // ---------------------------------------------------------------- var $blazys = context.find('[data-toggle="blazy"]'); var $blazy_bgs = context.find('[data-bg-img]'); var bLazy; if ($blazys.length > 0 || $blazy_bgs.length > 0) { var themePluginBlazyInit = function() { if ($blazys.length > 0) { $blazys.each(function() { // Remove alts while loading var $t = $(this); var alt = $t.attr('alt') || null; if (alt) { $t.data('alt', alt); $t.attr('alt', ''); } }); bLazy = new Blazy({ selector: '[data-toggle="blazy"]', loadInvisible: true, success: function(ele) { var $ele = $(ele); var alt = $ele.data('alt') || null; if (alt) { $ele.attr('alt', alt); $ele.data('alt', ''); } } }); } if ($blazy_bgs.length > 0) { $blazy_bgs.addClass('bg-img blazy-bg'); bLazy = new Blazy({ selector: '[data-bg-img]', loadInvisible: true, src: 'data-bg-img' }); } }; $document.themeLoadPlugin( ["https://cdn.jsdelivr.net/blazy/latest/blazy.min.js"], ["plugin-css/plugin-blazy.min.css"], themePluginBlazyInit ); } }; // Object of plugins to add to Globals.PLUGINS Globals.PLUGINS.themePluginBootstrapSelect = function(context) { // ---------------------------------------------------------------- // Plugin: Bootstrap Select // @see: https://github.com/snapappointments/bootstrap-select // ---------------------------------------------------------------- var $selects = context.find('[data-toggle="select"], [data-toggle="selects"] select'); var themePluginBootstrapSelectInit = function() { if ($selects.length > 0) { $selects.each(function() { var $select = $(this); var styles = []; var defaultSettings = { "width": "100%", "style": null, "classes": null, }; var customSettings = $select.data('settings') || {}; var settings = $.extend({}, defaultSettings, customSettings); // @see: https://silviomoreto.github.io/bootstrap-select/options/ var style = $select.data('style') || null; if (style) { styles.push(style); } if ($select.hasClass('form-control-lg')) { styles.push('btn-lg'); } else if ($select.hasClass('form-control-sm')) { styles.push('btn-sm'); } if ($select.hasClass('form-control-rounded')) { styles.push('btn-rounded'); } if (settings.classes !== null) { if (typeof settings.classes == 'object') { $.each(settings.classes, function(key, value) { styles.push(value); }) } else if (typeof settings.classes == 'string') { styles.push(settings.classes); } } // Default if (styles.length == 0) { styles.push('btn-light'); } if (styles) { settings.style = styles.join(' '); } $select.selectpicker(settings); }); } }; if ($selects.length > 0) { $document.themeLoadPlugin( ["https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.0-beta/js/bootstrap-select.min.js"], ["https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.13.0-beta/css/bootstrap-select.min.css", "plugin-css/plugin-bootstrap-select.min.css"], themePluginBootstrapSelectInit ); } }; // Object of plugins to add to Globals.PLUGINS Globals.PLUGINS.themePluginBootstrapSwitch = function(context) { // ---------------------------------------------------------------- // Plugin: Bootstrap switch integration // @see: http://www.bootstrap-switch.org/ // ---------------------------------------------------------------- var $bootstrapSwitches = context.find('[data-toggle=switch]'); if ($bootstrapSwitches.length > 0) { var themePluginBootstrapSwitchInit = function() { $bootstrapSwitches.bootstrapSwitch(); }; $document.themeLoadPlugin( ["bootstrap-switch/build/js/bootstrap-switch.min.js"], ["plugin-css/plugin-bootstrap-switch.min.css", "bootstrap-switch/build/css/bootstrap3/bootstrap-switch.min.css"], themePluginBootstrapSwitchInit ); } }; var clipboardSelectors = '[data-clipboard-target], [data-clipboard-text]'; // Object of plugins to add to Globals.PREINITPLUGINS Globals.PREINITPLUGINS.themePluginClipboard = function(context) { // Get premanipulated HTML $(clipboardSelectors).each(function() { var $this = $(this); if ($this.data('clipboard-target-html')) { var target = $this.data('clipboard-target'); var $target = $(target); $target.data('clipboard-html-clone', $target.clone().prop('outerHTML')); } }); }; // Object of plugins to add to Globals.PLUGINS Globals.PLUGINS.themePluginClipboard = function(context) { // ---------------------------------------------------------------- // Plugin: Clipboard.js // @see: https://clipboardjs.com/ // ---------------------------------------------------------------- var $clipboards = context.find(clipboardSelectors); var formatFactory = function(html) { var parse = function(html, tab) { if (!tab) { tab = 0; } var html = $.parseHTML(html); var formatHtml = new String(); function setTabs() { var tabs = new String(); for (i = 0; i < tab; i++) { tabs += '\t'; } return tabs; }; $.each(html, function(i, el) { if (el.nodeName == '#text') { if (($(el).text().trim()).length) { formatHtml += setTabs() + $(el).text().trim() + '\n'; } } else { var innerHTML = $(el).html().trim(); $(el).html(innerHTML.replace('\n', '').replace(/ +(?= )/g, '')); if ($(el).children().length) { $(el).html('\n' + parse(innerHTML, (tab + 1)) + setTabs()); var outerHTML = $(el).prop('outerHTML').trim(); formatHtml += setTabs() + outerHTML + '\n'; } else { var outerHTML = $(el).prop('outerHTML').trim(); formatHtml += setTabs() + outerHTML + '\n'; } } }); return formatHtml; }; return parse(html.replace(/(\r\n|\n|\r)/gm, " ").replace(/ +(?= )/g, '')); }; var themePluginClipboardInit = function() { if ($clipboards.length > 0) { var clipboard = new Clipboard(clipboardSelectors, { text: function(trigger) { if ($(trigger).data('clipboard-target-html')) { var target = $(trigger).data('clipboard-target'); var $target = $(target); var htmlClone = $target.data('clipboard-html-clone') || null; var html = htmlClone || $target.clone().html(); return formatFactory(html); } } }); clipboard.on('success', function(e) { var $trigger = $(e.trigger) || null; var hasTooltip = $trigger.data('toggle') == 'tooltip' || false; if (hasTooltip !== false) { var originalTitle = $trigger.data('original-title'); $trigger.attr("title", "Copied!").tooltip("_fixTitle").tooltip("show").attr("title", originalTitle).tooltip("_fixTitle") } e.clearSelection(); }); } }; if ($clipboards.length > 0) { $document.themeLoadPlugin( ["https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"], [], themePluginClipboardInit ); } }; // Object of plugins to add to Globals.PLUGINS Globals.PLUGINS.themePluginCountTo = function(context) { // ---------------------------------------------------------------- // Count To (counters) // @see: // ---------------------------------------------------------------- var $countTos = context.find('[data-toggle="count-to"]'); if ($countTos.length > 0) { var themePluginCountToInit = function() { $countTos.each(function() { var $this = $(this), delay = $this.data('delay') || 0; $this.waypoint(function() { setTimeout(function() { $this.countTo({ onComplete: function() { $this.addClass('count-to-done'); }, formatter: function(value, options) { var v = value.toFixed(options.decimals); if (v == '-0') { v = '0'; } return v; }, }); }, delay); this.destroy(); }, { offset: '90%', }); }); }; $document.themeLoadPlugin(["https://cdnjs.cloudflare.com/ajax/libs/jquery-countto/1.2.0/jquery.countTo.min.js"], [], function() { $document.includeWaypoints(function() { $document.isPageLoaderDone(themePluginCountToInit); }); }); } }; // Object of plugins to add to Globals.PLUGINS Globals.PLUGINS.themePluginCountDown = function(context) { // ---------------------------------------------------------------- // Plugin: jQuery Countdown timer // @see: http://hilios.github.io/jQuery.countdown/ // ---------------------------------------------------------------- var $countdowns = context.find('[data-countdown]'); if ($countdowns.length > 0) { var themePluginCountdownInit = function() { $countdowns.each(function() { var $this = $(this), countTo = $this.data('countdown'), countdownFormat = $this.data('countdown-format') || null, coundownExpireText = $this.data('countdown-expire-text') || null; $this.countdown(countTo) .on('update.countdown', function(event) { if (countdownFormat === null) { countdownFormat = '%H hrs %M mins %S secs'; if (event.offset.totalDays > 0) { countdownFormat = '%-d day%!d ' + countdownFormat; } if (event.offset.weeks > 0) { countdownFormat = '%-w week%!w ' + countdownFormat; } } $this.html(event.strftime(countdownFormat)); }) .on('finish.countdown', function(event) { if (coundownExpireText !== coundownExpireText) { $this.html(coundownExpireText); } $this.addClass('countdown-done'); }); }); }; $document.themeLoadPlugin(["https://cdnjs.cloudflare.com/ajax/libs/jquery.countdown/2.2.0/jquery.countdown.min.js"], [], themePluginCountdownInit); } }; // Object of plugins to add to Globals.PLUGINS Globals.PLUGINS.themePluginCubePortfolio = function(context) { // ---------------------------------------------------------------- // Plugin: Cube Portfolio // @see: http://hilios.github.io/jQuery.countdown/ // ---------------------------------------------------------------- var $cubePortfolios = context.find('[data-toggle="cbp"]'); var defaultSettings = { layoutMode: 'mosaic', sortToPreventGaps: true, defaultFilter: '*', animationType: 'slideDelay', gapHorizontal: 2, gapVertical: 2, gridAdjustment: 'responsive', mediaQueries: [{ width: 1100, cols: 4 }, { width: 800, cols: 3 }, { width: 480, cols: 2 }, { width: 0, cols: 1 }], caption: 'zoom', displayTypeSpeed: 100, displayType: "sequentially", // lightbox lightboxDelegate: '.cbp-lightbox', lightboxGallery: true, lightboxTitleSrc: 'data-title', lightboxCounter: '