????JFIF??x?x????'
| Server IP : 79.136.114.73 / Your IP : 216.73.216.25 Web Server : Apache/2.4.7 (Ubuntu) PHP/5.5.9-1ubuntu4.29 OpenSSL/1.0.1f System : Linux b8009 3.13.0-170-generic #220-Ubuntu SMP Thu May 9 12:40:49 UTC 2019 x86_64 User : www-data ( 33) PHP Version : 5.5.9-1ubuntu4.29 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, MySQL : ON | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /var/www/www.astacus.se/wp-content/themes/x/framework/js/dist/site/ |
Upload File : |
// =============================================================================
// JS/X-BODY.JS
// -----------------------------------------------------------------------------
// Site specific functionality needed before the closing </body> tag.
// =============================================================================
// =============================================================================
// TABLE OF CONTENTS
// -----------------------------------------------------------------------------
// 01. Imports
// =============================================================================
// Imports
// =============================================================================
/*!
* hoverIntent v1.8.0 // 2014.06.29 // jQuery v1.9.1+
* http://cherne.net/brian/resources/jquery.hoverIntent.html
*
* You may use hoverIntent under the terms of the MIT license. Basically that
* means you are free to use hoverIntent as long as this header is left intact.
* Copyright 2007, 2014 Brian Cherne
*/
/* hoverIntent is similar to jQuery's built-in "hover" method except that
* instead of firing the handlerIn function immediately, hoverIntent checks
* to see if the user's mouse has slowed down (beneath the sensitivity
* threshold) before firing the event. The handlerOut function is only
* called after a matching handlerIn.
*
* // basic usage ... just like .hover()
* .hoverIntent( handlerIn, handlerOut )
* .hoverIntent( handlerInOut )
*
* // basic usage ... with event delegation!
* .hoverIntent( handlerIn, handlerOut, selector )
* .hoverIntent( handlerInOut, selector )
*
* // using a basic configuration object
* .hoverIntent( config )
*
* @param handlerIn function OR configuration object
* @param handlerOut function OR selector for delegation OR undefined
* @param selector selector OR undefined
* @author Brian Cherne <brian(at)cherne(dot)net>
*/
(function($) {
$.fn.hoverIntent = function(handlerIn,handlerOut,selector) {
// default configuration values
var cfg = {
interval: 100,
sensitivity: 6,
timeout: 0
};
if ( typeof handlerIn === "object" ) {
cfg = $.extend(cfg, handlerIn );
} else if ($.isFunction(handlerOut)) {
cfg = $.extend(cfg, { over: handlerIn, out: handlerOut, selector: selector } );
} else {
cfg = $.extend(cfg, { over: handlerIn, out: handlerIn, selector: handlerOut } );
}
// instantiate variables
// cX, cY = current X and Y position of mouse, updated by mousemove event
// pX, pY = previous X and Y position of mouse, set by mouseover and polling interval
var cX, cY, pX, pY;
// A private function for getting mouse position
var track = function(ev) {
cX = ev.pageX;
cY = ev.pageY;
};
// A private function for comparing current and previous mouse position
var compare = function(ev,ob) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
// compare mouse positions to see if they've crossed the threshold
if ( Math.sqrt( (pX-cX)*(pX-cX) + (pY-cY)*(pY-cY) ) < cfg.sensitivity ) {
$(ob).off("mousemove.hoverIntent",track);
// set hoverIntent state to true (so mouseOut can be called)
ob.hoverIntent_s = true;
return cfg.over.apply(ob,[ev]);
} else {
// set previous coordinates for next time
pX = cX; pY = cY;
// use self-calling timeout, guarantees intervals are spaced out properly (avoids JavaScript timer bugs)
ob.hoverIntent_t = setTimeout( function(){compare(ev, ob);} , cfg.interval );
}
};
// A private function for delaying the mouseOut function
var delay = function(ev,ob) {
ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t);
ob.hoverIntent_s = false;
return cfg.out.apply(ob,[ev]);
};
// A private function for handling mouse 'hovering'
var handleHover = function(e) {
// copy objects to be passed into t (required for event object to be passed in IE)
var ev = $.extend({},e);
var ob = this;
// cancel hoverIntent timer if it exists
if (ob.hoverIntent_t) { ob.hoverIntent_t = clearTimeout(ob.hoverIntent_t); }
// if e.type === "mouseenter"
if (e.type === "mouseenter") {
// set "previous" X and Y position based on initial entry point
pX = ev.pageX; pY = ev.pageY;
// update "current" X and Y position based on mousemove
$(ob).on("mousemove.hoverIntent",track);
// start polling interval (self-calling timeout) to compare mouse coordinates over time
if (!ob.hoverIntent_s) { ob.hoverIntent_t = setTimeout( function(){compare(ev,ob);} , cfg.interval );}
// else e.type == "mouseleave"
} else {
// unbind expensive mousemove event
$(ob).off("mousemove.hoverIntent",track);
// if hoverIntent state is true, then call the mouseOut function after the specified delay
if (ob.hoverIntent_s) { ob.hoverIntent_t = setTimeout( function(){delay(ev,ob);} , cfg.timeout );}
}
};
// listen for mouseenter and mouseleave
return this.on({'mouseenter.hoverIntent':handleHover,'mouseleave.hoverIntent':handleHover}, cfg.selector);
};
})(jQuery);
/**
* Isotope v1.5.26
* An exquisite jQuery plugin for magical layouts
* http://isotope.metafizzy.co
*
* Commercial use requires one-time purchase of a commercial license
* http://isotope.metafizzy.co/docs/license.html
*
* Non-commercial use is licensed under the MIT License
*
* Copyright 2014 Metafizzy
*/
/*jshint asi: true, browser: true, curly: true, eqeqeq: true, forin: false, immed: false, newcap: true, noempty: true, strict: true, undef: true */
/*global jQuery: false */
(function( window, $, undefined ){
'use strict';
// get global vars
var document = window.document;
var docElem = document.documentElement;
var Modernizr = window.Modernizr;
// helper function
var capitalize = function( str ) {
return str.charAt(0).toUpperCase() + str.slice(1);
};
// ========================= getStyleProperty by kangax ===============================
// http://perfectionkills.com/feature-testing-css-properties/
var prefixes = 'Moz Webkit O Ms'.split(' ');
var getStyleProperty = function( propName ) {
var style = docElem.style,
prefixed;
// test standard property first
if ( typeof style[propName] === 'string' ) {
return propName;
}
// capitalize
propName = capitalize( propName );
// test vendor specific properties
for ( var i=0, len = prefixes.length; i < len; i++ ) {
prefixed = prefixes[i] + propName;
if ( typeof style[ prefixed ] === 'string' ) {
return prefixed;
}
}
};
var transformProp = getStyleProperty('transform'),
transitionProp = getStyleProperty('transitionProperty');
// ========================= miniModernizr ===============================
// <3<3<3 and thanks to Faruk and Paul for doing the heavy lifting
/*!
* Modernizr v1.6ish: miniModernizr for Isotope
* http://www.modernizr.com
*
* Developed by:
* - Faruk Ates http://farukat.es/
* - Paul Irish http://paulirish.com/
*
* Copyright (c) 2009-2010
* Dual-licensed under the BSD or MIT licenses.
* http://www.modernizr.com/license/
*/
/*
* This version whittles down the script just to check support for
* CSS transitions, transforms, and 3D transforms.
*/
var tests = {
csstransforms: function() {
return !!transformProp;
},
csstransforms3d: function() {
var test = !!getStyleProperty('perspective');
// double check for Chrome's false positive
if ( test && 'webkitPerspective' in docElem.style ) {
var $style = $('<style>@media (transform-3d),(-webkit-transform-3d)' +
'{#modernizr{height:3px}}</style>').appendTo('head'),
$div = $('<div id="modernizr" />').appendTo('html');
test = $div.height() === 3;
$div.remove();
$style.remove();
}
return test;
},
csstransitions: function() {
return !!transitionProp;
}
};
var testName;
if ( Modernizr ) {
// if there's a previous Modernzir, check if there are necessary tests
for ( testName in tests) {
if ( !Modernizr.hasOwnProperty( testName ) ) {
// if test hasn't been run, use addTest to run it
Modernizr.addTest( testName, tests[ testName ] );
}
}
} else {
// or create new mini Modernizr that just has the 3 tests
Modernizr = window.Modernizr = {
_version : '1.6ish: miniModernizr for Isotope'
};
var classes = ' ';
var result;
// Run through tests
for ( testName in tests) {
result = tests[ testName ]();
Modernizr[ testName ] = result;
classes += ' ' + ( result ? '' : 'no-' ) + testName;
}
// Add the new classes to the <html> element.
$('html').addClass( classes );
}
// ========================= isoTransform ===============================
/**
* provides hooks for .css({ scale: value, translate: [x, y] })
* Progressively enhanced CSS transforms
* Uses hardware accelerated 3D transforms for Safari
* or falls back to 2D transforms.
*/
if ( Modernizr.csstransforms ) {
// i.e. transformFnNotations.scale(0.5) >> 'scale3d( 0.5, 0.5, 1)'
var transformFnNotations = Modernizr.csstransforms3d ?
{ // 3D transform functions
translate : function ( position ) {
return 'translate3d(' + position[0] + 'px, ' + position[1] + 'px, 0) ';
},
scale : function ( scale ) {
return 'scale3d(' + scale + ', ' + scale + ', 1) ';
}
} :
{ // 2D transform functions
translate : function ( position ) {
return 'translate(' + position[0] + 'px, ' + position[1] + 'px) ';
},
scale : function ( scale ) {
return 'scale(' + scale + ') ';
}
}
;
var setIsoTransform = function ( elem, name, value ) {
// unpack current transform data
var data = $.data( elem, 'isoTransform' ) || {},
newData = {},
fnName,
transformObj = {},
transformValue;
// i.e. newData.scale = 0.5
newData[ name ] = value;
// extend new value over current data
$.extend( data, newData );
for ( fnName in data ) {
transformValue = data[ fnName ];
transformObj[ fnName ] = transformFnNotations[ fnName ]( transformValue );
}
// get proper order
// ideally, we could loop through this give an array, but since we only have
// a couple transforms we're keeping track of, we'll do it like so
var translateFn = transformObj.translate || '',
scaleFn = transformObj.scale || '',
// sorting so translate always comes first
valueFns = translateFn + scaleFn;
// set data back in elem
$.data( elem, 'isoTransform', data );
// set name to vendor specific property
elem.style[ transformProp ] = valueFns;
};
// ==================== scale ===================
$.cssNumber.scale = true;
$.cssHooks.scale = {
set: function( elem, value ) {
// uncomment this bit if you want to properly parse strings
// if ( typeof value === 'string' ) {
// value = parseFloat( value );
// }
setIsoTransform( elem, 'scale', value );
},
get: function( elem, computed ) {
var transform = $.data( elem, 'isoTransform' );
return transform && transform.scale ? transform.scale : 1;
}
};
$.fx.step.scale = function( fx ) {
$.cssHooks.scale.set( fx.elem, fx.now+fx.unit );
};
// ==================== translate ===================
$.cssNumber.translate = true;
$.cssHooks.translate = {
set: function( elem, value ) {
// uncomment this bit if you want to properly parse strings
// if ( typeof value === 'string' ) {
// value = value.split(' ');
// }
//
// var i, val;
// for ( i = 0; i < 2; i++ ) {
// val = value[i];
// if ( typeof val === 'string' ) {
// val = parseInt( val );
// }
// }
setIsoTransform( elem, 'translate', value );
},
get: function( elem, computed ) {
var transform = $.data( elem, 'isoTransform' );
return transform && transform.translate ? transform.translate : [ 0, 0 ];
}
};
}
// ========================= get transition-end event ===============================
var transitionEndEvent, transitionDurProp;
if ( Modernizr.csstransitions ) {
transitionEndEvent = {
WebkitTransitionProperty: 'webkitTransitionEnd', // webkit
MozTransitionProperty: 'transitionend',
OTransitionProperty: 'oTransitionEnd otransitionend',
transitionProperty: 'transitionend'
}[ transitionProp ];
transitionDurProp = getStyleProperty('transitionDuration');
}
// ========================= smartresize ===============================
/*
* smartresize: debounced resize event for jQuery
*
* latest version and complete README available on Github:
* https://github.com/louisremi/jquery.smartresize.js
*
* Copyright 2011 @louis_remi
* Licensed under the MIT license.
*/
var $event = $.event,
dispatchMethod = 'dispatch',
resizeTimeout;
$event.special.smartresize = {
setup: function() {
$(this).bind( "resize", $event.special.smartresize.handler );
},
teardown: function() {
$(this).unbind( "resize", $event.special.smartresize.handler );
},
handler: function( event, execAsap ) {
// Save the context
var context = this,
args = arguments;
// set correct event type
event.type = "smartresize";
if ( resizeTimeout ) { clearTimeout( resizeTimeout ); }
resizeTimeout = setTimeout(function() {
$event[ dispatchMethod ].apply( context, args );
}, execAsap === "execAsap"? 0 : 100 );
}
};
$.fn.smartresize = function( fn ) {
return fn ? this.bind( "smartresize", fn ) : this.trigger( "smartresize", ["execAsap"] );
};
// ========================= Isotope ===============================
// our "Widget" object constructor
$.Isotope = function( options, element, callback ){
this.element = $( element );
this._create( options );
this._init( callback );
};
// styles of container element we want to keep track of
var isoContainerStyles = [ 'width', 'height' ];
var $window = $(window);
$.Isotope.settings = {
resizable: true,
layoutMode : 'masonry',
containerClass : 'isotope',
itemClass : 'isotope-item',
hiddenClass : 'isotope-hidden',
hiddenStyle: { opacity: 0, scale: 0.001 },
visibleStyle: { opacity: 1, scale: 1 },
containerStyle: {
position: 'relative',
overflow: 'hidden'
},
animationEngine: 'best-available',
animationOptions: {
queue: false,
duration: 800
},
sortBy : 'original-order',
sortAscending : true,
resizesContainer : true,
transformsEnabled: true,
itemPositionDataEnabled: false
};
$.Isotope.prototype = {
// sets up widget
_create : function( options ) {
this.options = $.extend( {}, $.Isotope.settings, options );
this.styleQueue = [];
this.elemCount = 0;
// get original styles in case we re-apply them in .destroy()
var elemStyle = this.element[0].style;
this.originalStyle = {};
// keep track of container styles
var containerStyles = isoContainerStyles.slice(0);
for ( var prop in this.options.containerStyle ) {
containerStyles.push( prop );
}
for ( var i=0, len = containerStyles.length; i < len; i++ ) {
prop = containerStyles[i];
this.originalStyle[ prop ] = elemStyle[ prop ] || '';
}
// apply container style from options
this.element.css( this.options.containerStyle );
this._updateAnimationEngine();
this._updateUsingTransforms();
// sorting
var originalOrderSorter = {
'original-order' : function( $elem, instance ) {
instance.elemCount ++;
return instance.elemCount;
},
random : function() {
return Math.random();
}
};
this.options.getSortData = $.extend( this.options.getSortData, originalOrderSorter );
// need to get atoms
this.reloadItems();
// get top left position of where the bricks should be
this.offset = {
left: parseInt( ( this.element.css('padding-left') || 0 ), 10 ),
top: parseInt( ( this.element.css('padding-top') || 0 ), 10 )
};
// add isotope class first time around
var instance = this;
setTimeout( function() {
instance.element.addClass( instance.options.containerClass );
}, 0 );
// bind resize method
if ( this.options.resizable ) {
$window.bind( 'smartresize.isotope', function() {
instance.resize();
});
}
// dismiss all click events from hidden events
this.element.delegate( '.' + this.options.hiddenClass, 'click', function(){
return false;
});
},
_getAtoms : function( $elems ) {
var selector = this.options.itemSelector,
// filter & find
$atoms = selector ? $elems.filter( selector ).add( $elems.find( selector ) ) : $elems,
// base style for atoms
atomStyle = { position: 'absolute' };
// filter out text nodes
$atoms = $atoms.filter( function( i, atom ) {
return atom.nodeType === 1;
});
if ( this.usingTransforms ) {
atomStyle.left = 0;
atomStyle.top = 0;
}
$atoms.css( atomStyle ).addClass( this.options.itemClass );
this.updateSortData( $atoms, true );
return $atoms;
},
// _init fires when your instance is first created
// (from the constructor above), and when you
// attempt to initialize the widget again (by the bridge)
// after it has already been initialized.
_init : function( callback ) {
this.$filteredAtoms = this._filter( this.$allAtoms );
this._sort();
this.reLayout( callback );
},
option : function( opts ){
// change options AFTER initialization:
// signature: $('#foo').bar({ cool:false });
if ( $.isPlainObject( opts ) ){
this.options = $.extend( true, this.options, opts );
// trigger _updateOptionName if it exists
var updateOptionFn;
for ( var optionName in opts ) {
updateOptionFn = '_update' + capitalize( optionName );
if ( this[ updateOptionFn ] ) {
this[ updateOptionFn ]();
}
}
}
},
// ====================== updaters ====================== //
// kind of like setters
_updateAnimationEngine : function() {
var animationEngine = this.options.animationEngine.toLowerCase().replace( /[ _\-]/g, '');
var isUsingJQueryAnimation;
// set applyStyleFnName
switch ( animationEngine ) {
case 'css' :
case 'none' :
isUsingJQueryAnimation = false;
break;
case 'jquery' :
isUsingJQueryAnimation = true;
break;
default : // best available
isUsingJQueryAnimation = !Modernizr.csstransitions;
}
this.isUsingJQueryAnimation = isUsingJQueryAnimation;
this._updateUsingTransforms();
},
_updateTransformsEnabled : function() {
this._updateUsingTransforms();
},
_updateUsingTransforms : function() {
var usingTransforms = this.usingTransforms = this.options.transformsEnabled &&
Modernizr.csstransforms && Modernizr.csstransitions && !this.isUsingJQueryAnimation;
// prevent scales when transforms are disabled
if ( !usingTransforms ) {
delete this.options.hiddenStyle.scale;
delete this.options.visibleStyle.scale;
}
this.getPositionStyles = usingTransforms ? this._translate : this._positionAbs;
},
// ====================== Filtering ======================
_filter : function( $atoms ) {
var filter = this.options.filter === '' ? '*' : this.options.filter;
if ( !filter ) {
return $atoms;
}
var hiddenClass = this.options.hiddenClass,
hiddenSelector = '.' + hiddenClass,
$hiddenAtoms = $atoms.filter( hiddenSelector ),
$atomsToShow = $hiddenAtoms;
if ( filter !== '*' ) {
$atomsToShow = $hiddenAtoms.filter( filter );
var $atomsToHide = $atoms.not( hiddenSelector ).not( filter ).addClass( hiddenClass );
this.styleQueue.push({ $el: $atomsToHide, style: this.options.hiddenStyle });
}
this.styleQueue.push({ $el: $atomsToShow, style: this.options.visibleStyle });
$atomsToShow.removeClass( hiddenClass );
return $atoms.filter( filter );
},
// ====================== Sorting ======================
updateSortData : function( $atoms, isIncrementingElemCount ) {
var instance = this,
getSortData = this.options.getSortData,
$this, sortData;
$atoms.each(function(){
$this = $(this);
sortData = {};
// get value for sort data based on fn( $elem ) passed in
for ( var key in getSortData ) {
if ( !isIncrementingElemCount && key === 'original-order' ) {
// keep original order original
sortData[ key ] = $.data( this, 'isotope-sort-data' )[ key ];
} else {
sortData[ key ] = getSortData[ key ]( $this, instance );
}
}
// apply sort data to element
$.data( this, 'isotope-sort-data', sortData );
});
},
// used on all the filtered atoms
_sort : function() {
var sortBy = this.options.sortBy,
getSorter = this._getSorter,
sortDir = this.options.sortAscending ? 1 : -1,
sortFn = function( alpha, beta ) {
var a = getSorter( alpha, sortBy ),
b = getSorter( beta, sortBy );
// fall back to original order if data matches
if ( a === b && sortBy !== 'original-order') {
a = getSorter( alpha, 'original-order' );
b = getSorter( beta, 'original-order' );
}
return ( ( a > b ) ? 1 : ( a < b ) ? -1 : 0 ) * sortDir;
};
this.$filteredAtoms.sort( sortFn );
},
_getSorter : function( elem, sortBy ) {
return $.data( elem, 'isotope-sort-data' )[ sortBy ];
},
// ====================== Layout Helpers ======================
_translate : function( x, y ) {
return { translate : [ x, y ] };
},
_positionAbs : function( x, y ) {
return { left: x, top: y };
},
_pushPosition : function( $elem, x, y ) {
x = Math.round( x + this.offset.left );
y = Math.round( y + this.offset.top );
var position = this.getPositionStyles( x, y );
this.styleQueue.push({ $el: $elem, style: position });
if ( this.options.itemPositionDataEnabled ) {
$elem.data('isotope-item-position', {x: x, y: y} );
}
},
// ====================== General Layout ======================
// used on collection of atoms (should be filtered, and sorted before )
// accepts atoms-to-be-laid-out to start with
layout : function( $elems, callback ) {
var layoutMode = this.options.layoutMode;
// layout logic
this[ '_' + layoutMode + 'Layout' ]( $elems );
// set the size of the container
if ( this.options.resizesContainer ) {
var containerStyle = this[ '_' + layoutMode + 'GetContainerSize' ]();
this.styleQueue.push({ $el: this.element, style: containerStyle });
}
this._processStyleQueue( $elems, callback );
this.isLaidOut = true;
},
_processStyleQueue : function( $elems, callback ) {
// are we animating the layout arrangement?
// use plugin-ish syntax for css or animate
var styleFn = !this.isLaidOut ? 'css' : (
this.isUsingJQueryAnimation ? 'animate' : 'css'
),
animOpts = this.options.animationOptions,
onLayout = this.options.onLayout,
objStyleFn, processor,
triggerCallbackNow, callbackFn;
// default styleQueue processor, may be overwritten down below
processor = function( i, obj ) {
obj.$el[ styleFn ]( obj.style, animOpts );
};
if ( this._isInserting && this.isUsingJQueryAnimation ) {
// if using styleQueue to insert items
processor = function( i, obj ) {
// only animate if it not being inserted
objStyleFn = obj.$el.hasClass('no-transition') ? 'css' : styleFn;
obj.$el[ objStyleFn ]( obj.style, animOpts );
};
} else if ( callback || onLayout || animOpts.complete ) {
// has callback
var isCallbackTriggered = false,
// array of possible callbacks to trigger
callbacks = [ callback, onLayout, animOpts.complete ],
instance = this;
triggerCallbackNow = true;
// trigger callback only once
callbackFn = function() {
if ( isCallbackTriggered ) {
return;
}
var hollaback;
for (var i=0, len = callbacks.length; i < len; i++) {
hollaback = callbacks[i];
if ( typeof hollaback === 'function' ) {
hollaback.call( instance.element, $elems, instance );
}
}
isCallbackTriggered = true;
};
if ( this.isUsingJQueryAnimation && styleFn === 'animate' ) {
// add callback to animation options
animOpts.complete = callbackFn;
triggerCallbackNow = false;
} else if ( Modernizr.csstransitions ) {
// detect if first item has transition
var i = 0,
firstItem = this.styleQueue[0],
testElem = firstItem && firstItem.$el,
styleObj;
// get first non-empty jQ object
while ( !testElem || !testElem.length ) {
styleObj = this.styleQueue[ i++ ];
// HACK: sometimes styleQueue[i] is undefined
if ( !styleObj ) {
return;
}
testElem = styleObj.$el;
}
// get transition duration of the first element in that object
// yeah, this is inexact
var duration = parseFloat( getComputedStyle( testElem[0] )[ transitionDurProp ] );
if ( duration > 0 ) {
processor = function( i, obj ) {
obj.$el[ styleFn ]( obj.style, animOpts )
// trigger callback at transition end
.one( transitionEndEvent, callbackFn );
};
triggerCallbackNow = false;
}
}
}
// process styleQueue
$.each( this.styleQueue, processor );
if ( triggerCallbackNow ) {
callbackFn();
}
// clear out queue for next time
this.styleQueue = [];
},
resize : function() {
if ( this[ '_' + this.options.layoutMode + 'ResizeChanged' ]() ) {
this.reLayout();
}
},
reLayout : function( callback ) {
this[ '_' + this.options.layoutMode + 'Reset' ]();
this.layout( this.$filteredAtoms, callback );
},
// ====================== Convenience methods ======================
// ====================== Adding items ======================
// adds a jQuery object of items to a isotope container
addItems : function( $content, callback ) {
var $newAtoms = this._getAtoms( $content );
// add new atoms to atoms pools
this.$allAtoms = this.$allAtoms.add( $newAtoms );
if ( callback ) {
callback( $newAtoms );
}
},
// convienence method for adding elements properly to any layout
// positions items, hides them, then animates them back in <--- very sezzy
insert : function( $content, callback ) {
// position items
this.element.append( $content );
var instance = this;
this.addItems( $content, function( $newAtoms ) {
var $newFilteredAtoms = instance._filter( $newAtoms );
instance._addHideAppended( $newFilteredAtoms );
instance._sort();
instance.reLayout();
instance._revealAppended( $newFilteredAtoms, callback );
});
},
// convienence method for working with Infinite Scroll
appended : function( $content, callback ) {
var instance = this;
this.addItems( $content, function( $newAtoms ) {
instance._addHideAppended( $newAtoms );
instance.layout( $newAtoms );
instance._revealAppended( $newAtoms, callback );
});
},
// adds new atoms, then hides them before positioning
_addHideAppended : function( $newAtoms ) {
this.$filteredAtoms = this.$filteredAtoms.add( $newAtoms );
$newAtoms.addClass('no-transition');
this._isInserting = true;
// apply hidden styles
this.styleQueue.push({ $el: $newAtoms, style: this.options.hiddenStyle });
},
// sets visible style on new atoms
_revealAppended : function( $newAtoms, callback ) {
var instance = this;
// apply visible style after a sec
setTimeout( function() {
// enable animation
$newAtoms.removeClass('no-transition');
// reveal newly inserted filtered elements
instance.styleQueue.push({ $el: $newAtoms, style: instance.options.visibleStyle });
instance._isInserting = false;
instance._processStyleQueue( $newAtoms, callback );
}, 10 );
},
// gathers all atoms
reloadItems : function() {
this.$allAtoms = this._getAtoms( this.element.children() );
},
// removes elements from Isotope widget
remove: function( $content, callback ) {
// remove elements immediately from Isotope instance
this.$allAtoms = this.$allAtoms.not( $content );
this.$filteredAtoms = this.$filteredAtoms.not( $content );
// remove() as a callback, for after transition / animation
var instance = this;
var removeContent = function() {
$content.remove();
if ( callback ) {
callback.call( instance.element );
}
};
if ( $content.filter( ':not(.' + this.options.hiddenClass + ')' ).length ) {
// if any non-hidden content needs to be removed
this.styleQueue.push({ $el: $content, style: this.options.hiddenStyle });
this._sort();
this.reLayout( removeContent );
} else {
// remove it now
removeContent();
}
},
shuffle : function( callback ) {
this.updateSortData( this.$allAtoms );
this.options.sortBy = 'random';
this._sort();
this.reLayout( callback );
},
// destroys widget, returns elements and container back (close) to original style
destroy : function() {
var usingTransforms = this.usingTransforms;
var options = this.options;
this.$allAtoms
.removeClass( options.hiddenClass + ' ' + options.itemClass )
.each(function(){
var style = this.style;
style.position = '';
style.top = '';
style.left = '';
style.opacity = '';
if ( usingTransforms ) {
style[ transformProp ] = '';
}
});
// re-apply saved container styles
var elemStyle = this.element[0].style;
for ( var prop in this.originalStyle ) {
elemStyle[ prop ] = this.originalStyle[ prop ];
}
this.element
.unbind('.isotope')
.undelegate( '.' + options.hiddenClass, 'click' )
.removeClass( options.containerClass )
.removeData('isotope');
$window.unbind('.isotope');
},
// ====================== LAYOUTS ======================
// calculates number of rows or columns
// requires columnWidth or rowHeight to be set on namespaced object
// i.e. this.masonry.columnWidth = 200
_getSegments : function( isRows ) {
var namespace = this.options.layoutMode,
measure = isRows ? 'rowHeight' : 'columnWidth',
size = isRows ? 'height' : 'width',
segmentsName = isRows ? 'rows' : 'cols',
containerSize = this.element[ size ](),
segments,
// i.e. options.masonry && options.masonry.columnWidth
segmentSize = this.options[ namespace ] && this.options[ namespace ][ measure ] ||
// or use the size of the first item, i.e. outerWidth
this.$filteredAtoms[ 'outer' + capitalize(size) ](true) ||
// if there's no items, use size of container
containerSize;
segments = Math.floor( containerSize / segmentSize );
segments = Math.max( segments, 1 );
// i.e. this.masonry.cols = ....
this[ namespace ][ segmentsName ] = segments;
// i.e. this.masonry.columnWidth = ...
this[ namespace ][ measure ] = segmentSize;
},
_checkIfSegmentsChanged : function( isRows ) {
var namespace = this.options.layoutMode,
segmentsName = isRows ? 'rows' : 'cols',
prevSegments = this[ namespace ][ segmentsName ];
// update cols/rows
this._getSegments( isRows );
// return if updated cols/rows is not equal to previous
return ( this[ namespace ][ segmentsName ] !== prevSegments );
},
// ====================== Masonry ======================
_masonryReset : function() {
// layout-specific props
this.masonry = {};
// FIXME shouldn't have to call this again
this._getSegments();
var i = this.masonry.cols;
this.masonry.colYs = [];
while (i--) {
this.masonry.colYs.push( 0 );
}
},
_masonryLayout : function( $elems ) {
var instance = this,
props = instance.masonry;
$elems.each(function(){
var $this = $(this),
//how many columns does this brick span
colSpan = Math.ceil( $this.outerWidth(true) / props.columnWidth );
colSpan = Math.min( colSpan, props.cols );
if ( colSpan === 1 ) {
// if brick spans only one column, just like singleMode
instance._masonryPlaceBrick( $this, props.colYs );
} else {
// brick spans more than one column
// how many different places could this brick fit horizontally
var groupCount = props.cols + 1 - colSpan,
groupY = [],
groupColY,
i;
// for each group potential horizontal position
for ( i=0; i < groupCount; i++ ) {
// make an array of colY values for that one group
groupColY = props.colYs.slice( i, i+colSpan );
// and get the max value of the array
groupY[i] = Math.max.apply( Math, groupColY );
}
instance._masonryPlaceBrick( $this, groupY );
}
});
},
// worker method that places brick in the columnSet
// with the the minY
_masonryPlaceBrick : function( $brick, setY ) {
// get the minimum Y value from the columns
var minimumY = Math.min.apply( Math, setY ),
shortCol = 0;
// Find index of short column, the first from the left
for (var i=0, len = setY.length; i < len; i++) {
if ( setY[i] === minimumY ) {
shortCol = i;
break;
}
}
// position the brick
var x = this.masonry.columnWidth * shortCol,
y = minimumY;
this._pushPosition( $brick, x, y );
// apply setHeight to necessary columns
var setHeight = minimumY + $brick.outerHeight(true),
setSpan = this.masonry.cols + 1 - len;
for ( i=0; i < setSpan; i++ ) {
this.masonry.colYs[ shortCol + i ] = setHeight;
}
},
_masonryGetContainerSize : function() {
var containerHeight = Math.max.apply( Math, this.masonry.colYs );
return { height: containerHeight };
},
_masonryResizeChanged : function() {
return this._checkIfSegmentsChanged();
},
// ====================== fitRows ======================
_fitRowsReset : function() {
this.fitRows = {
x : 0,
y : 0,
height : 0
};
},
_fitRowsLayout : function( $elems ) {
var instance = this,
containerWidth = this.element.width(),
props = this.fitRows;
$elems.each( function() {
var $this = $(this),
atomW = $this.outerWidth(true),
atomH = $this.outerHeight(true);
if ( props.x !== 0 && atomW + props.x > containerWidth ) {
// if this element cannot fit in the current row
props.x = 0;
props.y = props.height;
}
// position the atom
instance._pushPosition( $this, props.x, props.y );
props.height = Math.max( props.y + atomH, props.height );
props.x += atomW;
});
},
_fitRowsGetContainerSize : function () {
return { height : this.fitRows.height };
},
_fitRowsResizeChanged : function() {
return true;
},
// ====================== cellsByRow ======================
_cellsByRowReset : function() {
this.cellsByRow = {
index : 0
};
// get this.cellsByRow.columnWidth
this._getSegments();
// get this.cellsByRow.rowHeight
this._getSegments(true);
},
_cellsByRowLayout : function( $elems ) {
var instance = this,
props = this.cellsByRow;
$elems.each( function(){
var $this = $(this),
col = props.index % props.cols,
row = Math.floor( props.index / props.cols ),
x = ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2,
y = ( row + 0.5 ) * props.rowHeight - $this.outerHeight(true) / 2;
instance._pushPosition( $this, x, y );
props.index ++;
});
},
_cellsByRowGetContainerSize : function() {
return { height : Math.ceil( this.$filteredAtoms.length / this.cellsByRow.cols ) * this.cellsByRow.rowHeight + this.offset.top };
},
_cellsByRowResizeChanged : function() {
return this._checkIfSegmentsChanged();
},
// ====================== straightDown ======================
_straightDownReset : function() {
this.straightDown = {
y : 0
};
},
_straightDownLayout : function( $elems ) {
var instance = this;
$elems.each( function( i ){
var $this = $(this);
instance._pushPosition( $this, 0, instance.straightDown.y );
instance.straightDown.y += $this.outerHeight(true);
});
},
_straightDownGetContainerSize : function() {
return { height : this.straightDown.y };
},
_straightDownResizeChanged : function() {
return true;
},
// ====================== masonryHorizontal ======================
_masonryHorizontalReset : function() {
// layout-specific props
this.masonryHorizontal = {};
// FIXME shouldn't have to call this again
this._getSegments( true );
var i = this.masonryHorizontal.rows;
this.masonryHorizontal.rowXs = [];
while (i--) {
this.masonryHorizontal.rowXs.push( 0 );
}
},
_masonryHorizontalLayout : function( $elems ) {
var instance = this,
props = instance.masonryHorizontal;
$elems.each(function(){
var $this = $(this),
//how many rows does this brick span
rowSpan = Math.ceil( $this.outerHeight(true) / props.rowHeight );
rowSpan = Math.min( rowSpan, props.rows );
if ( rowSpan === 1 ) {
// if brick spans only one column, just like singleMode
instance._masonryHorizontalPlaceBrick( $this, props.rowXs );
} else {
// brick spans more than one row
// how many different places could this brick fit horizontally
var groupCount = props.rows + 1 - rowSpan,
groupX = [],
groupRowX, i;
// for each group potential horizontal position
for ( i=0; i < groupCount; i++ ) {
// make an array of colY values for that one group
groupRowX = props.rowXs.slice( i, i+rowSpan );
// and get the max value of the array
groupX[i] = Math.max.apply( Math, groupRowX );
}
instance._masonryHorizontalPlaceBrick( $this, groupX );
}
});
},
_masonryHorizontalPlaceBrick : function( $brick, setX ) {
// get the minimum Y value from the columns
var minimumX = Math.min.apply( Math, setX ),
smallRow = 0;
// Find index of smallest row, the first from the top
for (var i=0, len = setX.length; i < len; i++) {
if ( setX[i] === minimumX ) {
smallRow = i;
break;
}
}
// position the brick
var x = minimumX,
y = this.masonryHorizontal.rowHeight * smallRow;
this._pushPosition( $brick, x, y );
// apply setHeight to necessary columns
var setWidth = minimumX + $brick.outerWidth(true),
setSpan = this.masonryHorizontal.rows + 1 - len;
for ( i=0; i < setSpan; i++ ) {
this.masonryHorizontal.rowXs[ smallRow + i ] = setWidth;
}
},
_masonryHorizontalGetContainerSize : function() {
var containerWidth = Math.max.apply( Math, this.masonryHorizontal.rowXs );
return { width: containerWidth };
},
_masonryHorizontalResizeChanged : function() {
return this._checkIfSegmentsChanged(true);
},
// ====================== fitColumns ======================
_fitColumnsReset : function() {
this.fitColumns = {
x : 0,
y : 0,
width : 0
};
},
_fitColumnsLayout : function( $elems ) {
var instance = this,
containerHeight = this.element.height(),
props = this.fitColumns;
$elems.each( function() {
var $this = $(this),
atomW = $this.outerWidth(true),
atomH = $this.outerHeight(true);
if ( props.y !== 0 && atomH + props.y > containerHeight ) {
// if this element cannot fit in the current column
props.x = props.width;
props.y = 0;
}
// position the atom
instance._pushPosition( $this, props.x, props.y );
props.width = Math.max( props.x + atomW, props.width );
props.y += atomH;
});
},
_fitColumnsGetContainerSize : function () {
return { width : this.fitColumns.width };
},
_fitColumnsResizeChanged : function() {
return true;
},
// ====================== cellsByColumn ======================
_cellsByColumnReset : function() {
this.cellsByColumn = {
index : 0
};
// get this.cellsByColumn.columnWidth
this._getSegments();
// get this.cellsByColumn.rowHeight
this._getSegments(true);
},
_cellsByColumnLayout : function( $elems ) {
var instance = this,
props = this.cellsByColumn;
$elems.each( function(){
var $this = $(this),
col = Math.floor( props.index / props.rows ),
row = props.index % props.rows,
x = ( col + 0.5 ) * props.columnWidth - $this.outerWidth(true) / 2,
y = ( row + 0.5 ) * props.rowHeight - $this.outerHeight(true) / 2;
instance._pushPosition( $this, x, y );
props.index ++;
});
},
_cellsByColumnGetContainerSize : function() {
return { width : Math.ceil( this.$filteredAtoms.length / this.cellsByColumn.rows ) * this.cellsByColumn.columnWidth };
},
_cellsByColumnResizeChanged : function() {
return this._checkIfSegmentsChanged(true);
},
// ====================== straightAcross ======================
_straightAcrossReset : function() {
this.straightAcross = {
x : 0
};
},
_straightAcrossLayout : function( $elems ) {
var instance = this;
$elems.each( function( i ){
var $this = $(this);
instance._pushPosition( $this, instance.straightAcross.x, 0 );
instance.straightAcross.x += $this.outerWidth(true);
});
},
_straightAcrossGetContainerSize : function() {
return { width : this.straightAcross.x };
},
_straightAcrossResizeChanged : function() {
return true;
}
};
// ======================= imagesLoaded Plugin ===============================
/*!
* jQuery imagesLoaded plugin v1.1.0
* http://github.com/desandro/imagesloaded
*
* MIT License. by Paul Irish et al.
*/
// $('#my-container').imagesLoaded(myFunction)
// or
// $('img').imagesLoaded(myFunction)
// execute a callback when all images have loaded.
// needed because .load() doesn't work on cached images
// callback function gets image collection as argument
// `this` is the container
$.fn.imagesLoaded = function( callback ) {
var $this = this,
$images = $this.find('img').add( $this.filter('img') ),
len = $images.length,
blank = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==',
loaded = [];
function triggerCallback() {
callback.call( $this, $images );
}
function imgLoaded( event ) {
var img = event.target;
if ( img.src !== blank && $.inArray( img, loaded ) === -1 ){
loaded.push( img );
if ( --len <= 0 ){
setTimeout( triggerCallback );
$images.unbind( '.imagesLoaded', imgLoaded );
}
}
}
// if no images, trigger immediately
if ( !len ) {
triggerCallback();
}
$images.bind( 'load.imagesLoaded error.imagesLoaded', imgLoaded ).each( function() {
// cached images don't fire load sometimes, so we reset src.
var src = this.src;
// webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f
// data uri bypasses webkit log warning (thx doug jones)
this.src = blank;
this.src = src;
});
return $this;
};
// helper function for logging errors
// $.error breaks jQuery chaining
var logError = function( message ) {
if ( window.console ) {
window.console.error( message );
}
};
// ======================= Plugin bridge ===============================
// leverages data method to either create or return $.Isotope constructor
// A bit from jQuery UI
// https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js
// A bit from jcarousel
// https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js
$.fn.isotope = function( options, callback ) {
if ( typeof options === 'string' ) {
// call method
var args = Array.prototype.slice.call( arguments, 1 );
this.each(function(){
var instance = $.data( this, 'isotope' );
if ( !instance ) {
logError( "cannot call methods on isotope prior to initialization; " +
"attempted to call method '" + options + "'" );
return;
}
if ( !$.isFunction( instance[options] ) || options.charAt(0) === "_" ) {
logError( "no such method '" + options + "' for isotope instance" );
return;
}
// apply method
instance[ options ].apply( instance, args );
});
} else {
this.each(function() {
var instance = $.data( this, 'isotope' );
if ( instance ) {
// apply options & init
instance.option( options );
instance._init( callback );
} else {
// initialize new instance
$.data( this, 'isotope', new $.Isotope( options, this, callback ) );
}
});
}
// return jQuery object
// so plugin methods do not have to
return this;
};
})( window, jQuery );
/*! http://mths.be/placeholder v2.0.8 by @mathias */
;(function(window, document, $) {
// Opera Mini v7 doesn’t support placeholder although its DOM seems to indicate so
var isOperaMini = Object.prototype.toString.call(window.operamini) == '[object OperaMini]';
var isInputSupported = 'placeholder' in document.createElement('input') && !isOperaMini;
var isTextareaSupported = 'placeholder' in document.createElement('textarea') && !isOperaMini;
var prototype = $.fn;
var valHooks = $.valHooks;
var propHooks = $.propHooks;
var hooks;
var placeholder;
if (isInputSupported && isTextareaSupported) {
placeholder = prototype.placeholder = function() {
return this;
};
placeholder.input = placeholder.textarea = true;
} else {
placeholder = prototype.placeholder = function() {
var $this = this;
$this
.filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]')
.not('.placeholder')
.bind({
'focus.placeholder': clearPlaceholder,
'blur.placeholder': setPlaceholder
})
.data('placeholder-enabled', true)
.trigger('blur.placeholder');
return $this;
};
placeholder.input = isInputSupported;
placeholder.textarea = isTextareaSupported;
hooks = {
'get': function(element) {
var $element = $(element);
var $passwordInput = $element.data('placeholder-password');
if ($passwordInput) {
return $passwordInput[0].value;
}
return $element.data('placeholder-enabled') && $element.hasClass('placeholder') ? '' : element.value;
},
'set': function(element, value) {
var $element = $(element);
var $passwordInput = $element.data('placeholder-password');
if ($passwordInput) {
return $passwordInput[0].value = value;
}
if (!$element.data('placeholder-enabled')) {
return element.value = value;
}
if (value == '') {
element.value = value;
// Issue #56: Setting the placeholder causes problems if the element continues to have focus.
if (element != safeActiveElement()) {
// We can't use `triggerHandler` here because of dummy text/password inputs :(
setPlaceholder.call(element);
}
} else if ($element.hasClass('placeholder')) {
clearPlaceholder.call(element, true, value) || (element.value = value);
} else {
element.value = value;
}
// `set` can not return `undefined`; see http://jsapi.info/jquery/1.7.1/val#L2363
return $element;
}
};
if (!isInputSupported) {
valHooks.input = hooks;
propHooks.value = hooks;
}
if (!isTextareaSupported) {
valHooks.textarea = hooks;
propHooks.value = hooks;
}
$(function() {
// Look for forms
$(document).delegate('form', 'submit.placeholder', function() {
// Clear the placeholder values so they don't get submitted
var $inputs = $('.placeholder', this).each(clearPlaceholder);
setTimeout(function() {
$inputs.each(setPlaceholder);
}, 10);
});
});
// Clear placeholder values upon page reload
$(window).bind('beforeunload.placeholder', function() {
$('.placeholder').each(function() {
this.value = '';
});
});
}
function args(elem) {
// Return an object of element attributes
var newAttrs = {};
var rinlinejQuery = /^jQuery\d+$/;
$.each(elem.attributes, function(i, attr) {
if (attr.specified && !rinlinejQuery.test(attr.name)) {
newAttrs[attr.name] = attr.value;
}
});
return newAttrs;
}
function clearPlaceholder(event, value) {
var input = this;
var $input = $(input);
if (input.value == $input.attr('placeholder') && $input.hasClass('placeholder')) {
if ($input.data('placeholder-password')) {
$input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));
// If `clearPlaceholder` was called from `$.valHooks.input.set`
if (event === true) {
return $input[0].value = value;
}
$input.focus();
} else {
input.value = '';
$input.removeClass('placeholder');
input == safeActiveElement() && input.select();
}
}
}
function setPlaceholder() {
var $replacement;
var input = this;
var $input = $(input);
var id = this.id;
if (input.value == '') {
if (input.type == 'password') {
if (!$input.data('placeholder-textinput')) {
try {
$replacement = $input.clone().attr({ 'type': 'text' });
} catch(e) {
$replacement = $('<input>').attr($.extend(args(this), { 'type': 'text' }));
}
$replacement
.removeAttr('name')
.data({
'placeholder-password': $input,
'placeholder-id': id
})
.bind('focus.placeholder', clearPlaceholder);
$input
.data({
'placeholder-textinput': $replacement,
'placeholder-id': id
})
.before($replacement);
}
$input = $input.removeAttr('id').hide().prev().attr('id', id).show();
// Note: `$input[0] != input` now!
}
$input.addClass('placeholder');
$input[0].value = $input.attr('placeholder');
} else {
$input.removeClass('placeholder');
}
}
function safeActiveElement() {
// Avoid IE9 `document.activeElement` of death
// https://github.com/mathiasbynens/jquery-placeholder/pull/99
try {
return document.activeElement;
} catch (exception) {}
}
}(this, document, jQuery));
// =============================================================================
// JS/SRC/SITE/INC/X-BODY-CUSTOM.JS
// -----------------------------------------------------------------------------
// Includes all miscellaneous, custom functionality to be output near the
// closing </body> tag.
// =============================================================================
// =============================================================================
// TABLE OF CONTENTS
// -----------------------------------------------------------------------------
// 01. Custom Functionality
// =============================================================================
// Custom Functionality
// =============================================================================
jQuery(document).ready(function($) {
//
// Placeholder.
//
$('input, textarea').placeholder();
});
// =============================================================================
// JS/SRC/SITE/INC/X-BODY-SCROLLSPY.JS
// -----------------------------------------------------------------------------
// A modified version of the Bootstrap ScrollSpy plugin. More information can
// be found here: http://getbootstrap.com/javascript/#scrollspy
// =============================================================================
// =============================================================================
// TABLE OF CONTENTS
// -----------------------------------------------------------------------------
// 01. ScrollSpy Plugin
// 02. Setup ScrollSpy Functionality
// =============================================================================
// ScrollSpy Plugin
// =============================================================================
+function ($) { "use strict";
// SCROLLSPY CLASS DEFINITION
// ==========================
function ScrollSpy(element, options) {
var href
var process = $.proxy(this.process, this)
this.$element = $(element).is('body') ? $(window) : $(element)
this.$body = $('body')
this.$scrollElement = this.$element.on('scroll.bs.scroll-spy.data-api', process)
this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
this.selector = (this.options.target
|| ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
|| '') + ' .x-nav li > a'
this.offsets = $([])
this.targets = $([])
this.activeTarget = null
this.refresh()
this.process()
}
ScrollSpy.DEFAULTS = {
offset: 10
}
ScrollSpy.prototype.refresh = function () {
var offsetMethod = this.$element[0] == window ? 'offset' : 'position'
this.offsets = $([])
this.targets = $([])
var self = this
var $targets = this.$body
.find(this.selector)
.map(function () {
var $el = $(this)
var href = $el.data('target') || $el.attr('href')
var $href = /^#\w/.test(href) && $(href)
return ($href
&& $href.length
&& [[ $href[offsetMethod]().top + (!$.isWindow(self.$scrollElement.get(0)) && self.$scrollElement.scrollTop()), href ]]) || null
})
.sort(function (a, b) { return a[0] - b[0] })
.each(function () {
self.offsets.push(this[0])
self.targets.push(this[1])
})
}
ScrollSpy.prototype.process = function () {
var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
var scrollHeight = this.$scrollElement[0].scrollHeight || this.$body[0].scrollHeight
var maxScroll = scrollHeight - this.$scrollElement.height()
var offsets = this.offsets
var targets = this.targets
var activeTarget = this.activeTarget
var i
if (scrollTop >= maxScroll) {
return activeTarget != (i = targets.last()[0]) && this.activate(i)
}
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (!offsets[i + 1] || scrollTop <= offsets[i + 1])
&& this.activate( targets[i] )
}
}
ScrollSpy.prototype.activate = function (target) {
this.activeTarget = target
$(this.selector)
.parents('.current-menu-item')
.removeClass('current-menu-item')
var selector = this.selector
+ '[data-target="' + target + '"],'
+ this.selector + '[href="' + target + '"]'
var active = $(selector)
.parents('li')
.addClass('current-menu-item')
if (active.parent('.dropdown-menu').length) {
active = active
.closest('li.dropdown')
.addClass('current-menu-item')
}
active.trigger('activate.bs.scrollspy')
}
// SCROLLSPY PLUGIN DEFINITION
// ===========================
var old = $.fn.scrollspy
$.fn.scrollspy = function (option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.scrollspy')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
if (typeof option == 'string') data[option]()
})
}
$.fn.scrollspy.Constructor = ScrollSpy
// SCROLLSPY NO CONFLICT
// =====================
$.fn.scrollspy.noConflict = function () {
$.fn.scrollspy = old
return this
}
// SCROLLSPY DATA-API
// ==================
$(window).on('load', function () {
$('[data-spy="scroll"]').each(function () {
var $spy = $(this)
$spy.scrollspy($spy.data())
})
})
}(jQuery);
// Setup ScrollSpy Functionality
// =============================================================================
jQuery(document).ready(function($) {
var $body = $('body');
var bodyHeight = $body.outerHeight();
var adminbarHeight = $('#wpadminbar').outerHeight();
var navbarFixedTopHeight = $('.x-navbar-fixed-top-active .x-navbar').outerHeight();
var locHref = location.href;
var locHashIndex = locHref.indexOf('#');
var locHash = locHref.substr(locHashIndex);
//
// Calculate the offset height for various elements and remove it from
// the element's top offset so that fixed elements don't cover it up.
//
function animateOffset( element, ms, easing ) {
$('html, body').animate({
scrollTop: $(element).offset().top - adminbarHeight - navbarFixedTopHeight + 1
}, ms, easing);
}
//
// Page load offset (if necessary).
//
$(window).load(function() {
if ( locHashIndex !== -1 && $(locHash).length ) {
animateOffset(locHash, 1, 'linear');
}
});
//
// Scroll trigger.
//
$('a[href*="#"]').on('touchstart click', function(e) {
href = $(this).attr('href');
notComments = href.indexOf('#comments') === -1;
if ( href !== '#' && notComments ) {
var theId = href.split('#').pop();
var $el = $('#' + theId);
if ( $el.length > 0 ) {
e.preventDefault();
animateOffset($el, 850, 'easeInOutExpo');
}
}
});
//
// Initialize scrollspy.
//
if ( $body.hasClass('x-one-page-navigation-active') ) {
$body.scrollspy({
target : '.x-nav-wrap.desktop',
offset : adminbarHeight + navbarFixedTopHeight
});
//
// Refresh scrollspy as needed.
//
$(window).resize(function() {
$body.scrollspy('refresh');
});
var timesRun = 0;
var interval = setInterval(function() {
timesRun += 1;
var newBodyHeight = $body.outerHeight();
if ( newBodyHeight !== bodyHeight ) {
$body.scrollspy('refresh');
}
if ( timesRun === 10 ) {
clearInterval(interval);
}
}, 500);
}
});
// =============================================================================
// JS/SRC/SITE/INC/X-BODY-SLIDER-SCROLL.JS
// -----------------------------------------------------------------------------
// Includes all functionality pertaining to the scroll bottom anchor for the
// sliders.
// =============================================================================
// =============================================================================
// TABLE OF CONTENTS
// -----------------------------------------------------------------------------
// 01. Slider Scroll Bottom Anchor
// =============================================================================
// Slider Scroll Bottom Anchor
// =============================================================================
jQuery(function($) {
//
// Slider above.
//
$('.x-slider-container.above .x-slider-scroll-bottom').on('touchstart click', function(e) {
e.preventDefault();
$('html, body').animate({
scrollTop: $('.x-slider-container.above').outerHeight()
}, 850, 'easeInOutExpo');
});
//
// Slider below.
//
$('.x-slider-container.below .x-slider-scroll-bottom').on('touchstart click', function(e) {
e.preventDefault();
var mastheadHeight = $('.masthead').outerHeight();
var navbarFixedTopHeight = $('.x-navbar-fixed-top-active .x-navbar').outerHeight();
var sliderAboveHeight = $('.x-slider-container.above').outerHeight();
var sliderBelowHeight = $('.x-slider-container.below').outerHeight();
var heightSum = mastheadHeight + sliderAboveHeight + sliderBelowHeight - navbarFixedTopHeight;
$('html, body').animate({
scrollTop: heightSum
}, 850, 'easeInOutExpo');
});
});
// =============================================================================
// JS/SRC/SITE/INC/X-BODY-WOOCOMMERCE.JS
// -----------------------------------------------------------------------------
// Includes all additional WooCommerce functionality tied into the theme.
// =============================================================================
// =============================================================================
// TABLE OF CONTENTS
// -----------------------------------------------------------------------------
// 01. WooCommerce Functionality
// =============================================================================
// WooCommerce Functionality
// =============================================================================
jQuery(document).ready(function($) {
//
// Notifications.
//
var $notification = $('.x-cart-notification');
if ( $notification.length > 0 ) {
$('.add_to_cart_button.product_type_simple').on('click', function(e) {
$notification.addClass('bring-forward appear loading');
});
$('body').on('added_to_cart', function(e, fragments, cart_hash) {
setTimeout(function() {
$notification.removeClass('loading').addClass('added');
setTimeout(function() {
$notification.removeClass('appear');
setTimeout(function() {
$notification.removeClass('added bring-forward');
}, 650);
}, 1000);
}, 650);
});
}
//
// Star ratings.
//
var $container = $('p.stars');
var $stars = $container.find('a');
function starsLeave(e) {
if ( $container.hasClass('selected') ) {
$container.find('a.active').nextAll('a').removeClass('x-active');
} else {
$stars.removeClass('x-active');
}
}
function starClick(e) {
$(this).nextAll('a').removeClass('x-active');
}
function starOver(e) {
starsLeave();
$(this).addClass('x-active').prevAll('a').addClass('x-active');
}
$container.on('mouseleave', starsLeave);
$stars.on('click', starClick);
$stars.on('mouseover', starOver);
});